Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpMatrix_pseudo_inverse.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * 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
52
53#ifndef DOXYGEN_SHOULD_SKIP_THIS
54
55void 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
59void compute_pseudo_inverse(const vpMatrix &U, const vpColVector &sv, const vpMatrix &V, unsigned int nrows,
60 unsigned int ncols, double svThreshold, vpMatrix &Ap, int &rank_out, int *rank_in,
61 vpMatrix *imA, vpMatrix *imAt, vpMatrix *kerAt)
62{
63 Ap.resize(ncols, nrows, true, false);
64
65 // compute the highest singular value and the rank of h
66 double maxsv = sv[0];
67
68 rank_out = 0;
69
70 unsigned int sv_size = sv.size();
71 for (unsigned int i = 0; i < sv_size; ++i) {
72 if (sv[i] >(maxsv * svThreshold)) {
73 ++rank_out;
74 }
75 }
76
77 unsigned int rank = static_cast<unsigned int>(rank_out);
78 if (rank_in) {
79 rank = static_cast<unsigned int>(*rank_in);
80 }
81
82 for (unsigned int i = 0; i < ncols; ++i) {
83 for (unsigned int j = 0; j < nrows; ++j) {
84 for (unsigned int k = 0; k < rank; ++k) {
85 Ap[i][j] += (V[i][k] * U[j][k]) / sv[k];
86 }
87 }
88 }
89
90 // Compute im(A)
91 if (imA) {
92 imA->resize(nrows, rank);
93
94 for (unsigned int i = 0; i < nrows; ++i) {
95 for (unsigned int j = 0; j < rank; ++j) {
96 (*imA)[i][j] = U[i][j];
97 }
98 }
99 }
100
101 // Compute im(At)
102 if (imAt) {
103 imAt->resize(ncols, rank);
104 for (unsigned int i = 0; i < ncols; ++i) {
105 for (unsigned int j = 0; j < rank; ++j) {
106 (*imAt)[i][j] = V[i][j];
107 }
108 }
109 }
110
111 // Compute ker(At)
112 if (kerAt) {
113 kerAt->resize(ncols - rank, ncols);
114 if (rank != ncols) {
115 unsigned int v_rows = V.getRows();
116 for (unsigned int k = 0; k < (ncols - rank); ++k) {
117 unsigned j = k + rank;
118 for (unsigned int i = 0; i < v_rows; ++i) {
119 (*kerAt)[k][i] = V[i][j];
120 }
121 }
122 }
123 }
124}
125
126#endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
127
186unsigned int vpMatrix::pseudoInverse(vpMatrix &Ap, double svThreshold) const
187{
188#if defined(VISP_HAVE_LAPACK)
189 return pseudoInverseLapack(Ap, svThreshold);
190#elif defined(VISP_HAVE_EIGEN3)
191 return pseudoInverseEigen3(Ap, svThreshold);
192#elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
193 return pseudoInverseOpenCV(Ap, svThreshold);
194#else
195 (void)Ap;
196 (void)svThreshold;
197 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
198 "Install Lapack, Eigen3 or OpenCV 3rd party"));
199#endif
200}
201
266int vpMatrix::pseudoInverse(vpMatrix &Ap, int rank_in) const
267{
268#if defined(VISP_HAVE_LAPACK)
269 return pseudoInverseLapack(Ap, rank_in);
270#elif defined(VISP_HAVE_EIGEN3)
271 return pseudoInverseEigen3(Ap, rank_in);
272#elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
273 return pseudoInverseOpenCV(Ap, rank_in);
274#else
275 (void)Ap;
276 (void)rank_in;
277 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
278 "Install Lapack, Eigen3 or OpenCV 3rd party"));
279#endif
280}
281
336vpMatrix vpMatrix::pseudoInverse(double svThreshold) const
337{
338#if defined(VISP_HAVE_LAPACK)
339 return pseudoInverseLapack(svThreshold);
340#elif defined(VISP_HAVE_EIGEN3)
341 return pseudoInverseEigen3(svThreshold);
342#elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
343 return pseudoInverseOpenCV(svThreshold);
344#else
345 (void)svThreshold;
346 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
347 "Install Lapack, Eigen3 or OpenCV 3rd party"));
348#endif
349}
350
406{
407#if defined(VISP_HAVE_LAPACK)
408 return pseudoInverseLapack(rank_in);
409#elif defined(VISP_HAVE_EIGEN3)
410 return pseudoInverseEigen3(rank_in);
411#elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
412 return pseudoInverseOpenCV(rank_in);
413#else
414 (void)rank_in;
415 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
416 "Install Lapack, Eigen3 or OpenCV 3rd party"));
417#endif
418}
419
485unsigned int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, double svThreshold) const
486{
487#if defined(VISP_HAVE_LAPACK)
488 return pseudoInverseLapack(Ap, sv, svThreshold);
489#elif defined(VISP_HAVE_EIGEN3)
490 return pseudoInverseEigen3(Ap, sv, svThreshold);
491#elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
492 return pseudoInverseOpenCV(Ap, sv, svThreshold);
493#else
494 (void)Ap;
495 (void)sv;
496 (void)svThreshold;
497 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
498 "Install Lapack, Eigen3 or OpenCV 3rd party"));
499#endif
500}
501
572int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, int rank_in) const
573{
574#if defined(VISP_HAVE_LAPACK)
575 return pseudoInverseLapack(Ap, sv, rank_in);
576#elif defined(VISP_HAVE_EIGEN3)
577 return pseudoInverseEigen3(Ap, sv, rank_in);
578#elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
579 return pseudoInverseOpenCV(Ap, sv, rank_in);
580#else
581 (void)Ap;
582 (void)sv;
583 (void)rank_in;
584 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
585 "Install Lapack, Eigen3 or OpenCV 3rd party"));
586#endif
587}
588
666unsigned int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, double svThreshold, vpMatrix &imA, vpMatrix &imAt) const
667{
668 vpMatrix kerAt;
669 return pseudoInverse(Ap, sv, svThreshold, imA, imAt, kerAt);
670}
671
754int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, int rank_in, vpMatrix &imA, vpMatrix &imAt) const
755{
756 vpMatrix kerAt;
757 return pseudoInverse(Ap, sv, rank_in, imA, imAt, kerAt);
758}
759
865unsigned int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, double svThreshold, vpMatrix &imA, vpMatrix &imAt,
866 vpMatrix &kerAt) const
867{
868#if defined(VISP_HAVE_LAPACK)
869 return pseudoInverseLapack(Ap, sv, svThreshold, imA, imAt, kerAt);
870#elif defined(VISP_HAVE_EIGEN3)
871 return pseudoInverseEigen3(Ap, sv, svThreshold, imA, imAt, kerAt);
872#elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
873 return pseudoInverseOpenCV(Ap, sv, svThreshold, imA, imAt, kerAt);
874#else
875 (void)Ap;
876 (void)sv;
877 (void)svThreshold;
878 (void)imA;
879 (void)imAt;
880 (void)kerAt;
881 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
882 "Install Lapack, Eigen3 or OpenCV 3rd party"));
883#endif
884}
885
996int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, int rank_in, vpMatrix &imA, vpMatrix &imAt,
997 vpMatrix &kerAt) const
998{
999#if defined(VISP_HAVE_LAPACK)
1000 return pseudoInverseLapack(Ap, sv, rank_in, imA, imAt, kerAt);
1001#elif defined(VISP_HAVE_EIGEN3)
1002 return pseudoInverseEigen3(Ap, sv, rank_in, imA, imAt, kerAt);
1003#elif defined(VISP_HAVE_OPENCV) // Require opencv >= 2.1.1
1004 return pseudoInverseOpenCV(Ap, sv, rank_in, imA, imAt, kerAt);
1005#else
1006 (void)Ap;
1007 (void)sv;
1008 (void)rank_in;
1009 (void)imA;
1010 (void)imAt;
1011 (void)kerAt;
1012 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
1013 "Install Lapack, Eigen3 or OpenCV 3rd party"));
1014#endif
1015}
1016
1029vpMatrix vpMatrix::dampedInverse(const double &ratioOfMaxSvd) const
1030{
1031 vpColVector w;
1032 vpMatrix V, Mcpy(*this);
1033 Mcpy.svd(w, V);
1034 double maxSingularValue = w.getMaxValue();
1035 vpMatrix I;
1036 I.eye(this->colNum);
1037 double lambda = ratioOfMaxSvd * maxSingularValue;
1038 vpMatrix dampedInv = ((lambda * I) + (this->transpose() * (*this))).inverseByLU()* this->transpose();
1039 return dampedInv;
1040}
1041
1042END_VISP_NAMESPACE
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition vpArray2D.h:448
unsigned int size() const
Return the number of elements of the 2D array.
Definition vpArray2D.h:435
unsigned int getRows() const
Definition vpArray2D.h:433
unsigned int colNum
Definition vpArray2D.h:1203
Implementation of column vector and the associated operations.
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:175
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