Visual Servoing Platform  version 3.6.1 under development (2024-12-03)
vpMatrix_pseudo_inverse.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Pseudo inverse computation.
32  */
33 
34 #include <visp3/core/vpConfig.h>
35 #include <visp3/core/vpMatrix.h>
36 
37 #if defined(VISP_HAVE_SIMDLIB)
38 #include <Simd/SimdLib.h>
39 #endif
40 
41 #ifdef VISP_HAVE_LAPACK
42 #ifdef VISP_HAVE_GSL
43 #include <gsl/gsl_eigen.h>
44 #include <gsl/gsl_linalg.h>
45 #include <gsl/gsl_math.h>
46 #elif defined(VISP_HAVE_MKL)
47 #include <mkl.h>
48 #endif
49 #endif
50 
51 BEGIN_VISP_NAMESPACE
52 
53 #ifndef DOXYGEN_SHOULD_SKIP_THIS
54 
55 void compute_pseudo_inverse(const vpMatrix &U, const vpColVector &sv, const vpMatrix &V, unsigned int nrows,
56  unsigned int ncols, double svThreshold, vpMatrix &Ap, int &rank_out, int *rank_in,
57  vpMatrix *imA, vpMatrix *imAt, vpMatrix *kerAt)
58 {
59  Ap.resize(ncols, nrows, true, false);
60 
61  // compute the highest singular value and the rank of h
62  double maxsv = sv[0];
63 
64  rank_out = 0;
65 
66  unsigned int sv_size = sv.size();
67  for (unsigned int i = 0; i < sv_size; ++i) {
68  if (sv[i] >(maxsv * svThreshold)) {
69  ++rank_out;
70  }
71  }
72 
73  unsigned int rank = static_cast<unsigned int>(rank_out);
74  if (rank_in) {
75  rank = static_cast<unsigned int>(*rank_in);
76  }
77 
78  for (unsigned int i = 0; i < ncols; ++i) {
79  for (unsigned int j = 0; j < nrows; ++j) {
80  for (unsigned int k = 0; k < rank; ++k) {
81  Ap[i][j] += (V[i][k] * U[j][k]) / sv[k];
82  }
83  }
84  }
85 
86  // Compute im(A)
87  if (imA) {
88  imA->resize(nrows, rank);
89 
90  for (unsigned int i = 0; i < nrows; ++i) {
91  for (unsigned int j = 0; j < rank; ++j) {
92  (*imA)[i][j] = U[i][j];
93  }
94  }
95  }
96 
97  // Compute im(At)
98  if (imAt) {
99  imAt->resize(ncols, rank);
100  for (unsigned int i = 0; i < ncols; ++i) {
101  for (unsigned int j = 0; j < rank; ++j) {
102  (*imAt)[i][j] = V[i][j];
103  }
104  }
105  }
106 
107  // Compute ker(At)
108  if (kerAt) {
109  kerAt->resize(ncols - rank, ncols);
110  if (rank != ncols) {
111  unsigned int v_rows = V.getRows();
112  for (unsigned int k = 0; k < (ncols - rank); ++k) {
113  unsigned j = k + rank;
114  for (unsigned int i = 0; i < v_rows; ++i) {
115  (*kerAt)[k][i] = V[i][j];
116  }
117  }
118  }
119  }
120 }
121 
122 #endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
123 
182 unsigned int vpMatrix::pseudoInverse(vpMatrix &Ap, double svThreshold) const
183 {
184 #if defined(VISP_HAVE_LAPACK)
185  return pseudoInverseLapack(Ap, svThreshold);
186 #elif defined(VISP_HAVE_EIGEN3)
187  return pseudoInverseEigen3(Ap, svThreshold);
188 #elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
189  return pseudoInverseOpenCV(Ap, svThreshold);
190 #else
191  (void)Ap;
192  (void)svThreshold;
193  throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
194  "Install Lapack, Eigen3 or OpenCV 3rd party"));
195 #endif
196 }
197 
262 int vpMatrix::pseudoInverse(vpMatrix &Ap, int rank_in) const
263 {
264 #if defined(VISP_HAVE_LAPACK)
265  return pseudoInverseLapack(Ap, rank_in);
266 #elif defined(VISP_HAVE_EIGEN3)
267  return pseudoInverseEigen3(Ap, rank_in);
268 #elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
269  return pseudoInverseOpenCV(Ap, rank_in);
270 #else
271  (void)Ap;
272  (void)rank_in;
273  throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
274  "Install Lapack, Eigen3 or OpenCV 3rd party"));
275 #endif
276 }
277 
332 vpMatrix vpMatrix::pseudoInverse(double svThreshold) const
333 {
334 #if defined(VISP_HAVE_LAPACK)
335  return pseudoInverseLapack(svThreshold);
336 #elif defined(VISP_HAVE_EIGEN3)
337  return pseudoInverseEigen3(svThreshold);
338 #elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
339  return pseudoInverseOpenCV(svThreshold);
340 #else
341  (void)svThreshold;
342  throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
343  "Install Lapack, Eigen3 or OpenCV 3rd party"));
344 #endif
345 }
346 
402 {
403 #if defined(VISP_HAVE_LAPACK)
404  return pseudoInverseLapack(rank_in);
405 #elif defined(VISP_HAVE_EIGEN3)
406  return pseudoInverseEigen3(rank_in);
407 #elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
408  return pseudoInverseOpenCV(rank_in);
409 #else
410  (void)rank_in;
411  throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
412  "Install Lapack, Eigen3 or OpenCV 3rd party"));
413 #endif
414 }
415 
481 unsigned int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, double svThreshold) const
482 {
483 #if defined(VISP_HAVE_LAPACK)
484  return pseudoInverseLapack(Ap, sv, svThreshold);
485 #elif defined(VISP_HAVE_EIGEN3)
486  return pseudoInverseEigen3(Ap, sv, svThreshold);
487 #elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
488  return pseudoInverseOpenCV(Ap, sv, svThreshold);
489 #else
490  (void)Ap;
491  (void)sv;
492  (void)svThreshold;
493  throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
494  "Install Lapack, Eigen3 or OpenCV 3rd party"));
495 #endif
496 }
497 
568 int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, int rank_in) const
569 {
570 #if defined(VISP_HAVE_LAPACK)
571  return pseudoInverseLapack(Ap, sv, rank_in);
572 #elif defined(VISP_HAVE_EIGEN3)
573  return pseudoInverseEigen3(Ap, sv, rank_in);
574 #elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
575  return pseudoInverseOpenCV(Ap, sv, rank_in);
576 #else
577  (void)Ap;
578  (void)sv;
579  (void)rank_in;
580  throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
581  "Install Lapack, Eigen3 or OpenCV 3rd party"));
582 #endif
583 }
662 unsigned int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, double svThreshold, vpMatrix &imA, vpMatrix &imAt) const
663 {
664  vpMatrix kerAt;
665  return pseudoInverse(Ap, sv, svThreshold, imA, imAt, kerAt);
666 }
667 
750 int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, int rank_in, vpMatrix &imA, vpMatrix &imAt) const
751 {
752  vpMatrix kerAt;
753  return pseudoInverse(Ap, sv, rank_in, imA, imAt, kerAt);
754 }
755 
861 unsigned int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, double svThreshold, vpMatrix &imA, vpMatrix &imAt,
862  vpMatrix &kerAt) const
863 {
864 #if defined(VISP_HAVE_LAPACK)
865  return pseudoInverseLapack(Ap, sv, svThreshold, imA, imAt, kerAt);
866 #elif defined(VISP_HAVE_EIGEN3)
867  return pseudoInverseEigen3(Ap, sv, svThreshold, imA, imAt, kerAt);
868 #elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
869  return pseudoInverseOpenCV(Ap, sv, svThreshold, imA, imAt, kerAt);
870 #else
871  (void)Ap;
872  (void)sv;
873  (void)svThreshold;
874  (void)imA;
875  (void)imAt;
876  (void)kerAt;
877  throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
878  "Install Lapack, Eigen3 or OpenCV 3rd party"));
879 #endif
880 }
881 
992 int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, int rank_in, vpMatrix &imA, vpMatrix &imAt,
993  vpMatrix &kerAt) const
994 {
995 #if defined(VISP_HAVE_LAPACK)
996  return pseudoInverseLapack(Ap, sv, rank_in, imA, imAt, kerAt);
997 #elif defined(VISP_HAVE_EIGEN3)
998  return pseudoInverseEigen3(Ap, sv, rank_in, imA, imAt, kerAt);
999 #elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
1000  return pseudoInverseOpenCV(Ap, sv, rank_in, imA, imAt, kerAt);
1001 #else
1002  (void)Ap;
1003  (void)sv;
1004  (void)rank_in;
1005  (void)imA;
1006  (void)imAt;
1007  (void)kerAt;
1008  throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
1009  "Install Lapack, Eigen3 or OpenCV 3rd party"));
1010 #endif
1011 }
1012 
1025 vpMatrix vpMatrix::dampedInverse(const double &ratioOfMaxSvd) const
1026 {
1027  vpColVector w;
1028  vpMatrix V, Mcpy(*this);
1029  Mcpy.svd(w, V);
1030  double maxSingularValue = w.getMaxValue();
1031  vpMatrix I;
1032  I.eye(this->colNum);
1033  double lambda = ratioOfMaxSvd * maxSingularValue;
1034  vpMatrix dampedInv = ((lambda * I) + (this->transpose() * (*this))).inverseByLU()* this->transpose();
1035  return dampedInv;
1036 }
1037 
1038 END_VISP_NAMESPACE
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition: vpArray2D.h:362
unsigned int size() const
Return the number of elements of the 2D array.
Definition: vpArray2D.h:349
unsigned int getRows() const
Definition: vpArray2D.h:347
Type getMaxValue() const
Definition: vpArray2D.h:1130
unsigned int colNum
Number of columns in the array.
Definition: vpArray2D.h:1103
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ fatalError
Fatal error.
Definition: vpException.h:72
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:169
vpMatrix pseudoInverseOpenCV(double svThreshold=1e-6) const
vpMatrix pseudoInverseEigen3(double svThreshold=1e-6) const
vpMatrix dampedInverse(const double &ratioOfMaxSvd=1e-4) const
vpMatrix inverseByLU() const
void svd(vpColVector &w, vpMatrix &V)
vpMatrix pseudoInverseLapack(double svThreshold=1e-6) const
vpMatrix pseudoInverse(double svThreshold=1e-6) const
vpMatrix transpose() const