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 QR decomposition.
33  *
34  * Authors:
35  * Filip Novotny
36  * Fabien Spindler
37  *
38  *****************************************************************************/
39 
40 #include <cmath>     // For std::abs() on iOS
41 #include <cstdlib>   // For std::abs() on iOS
42 #include <algorithm> // for (std::min) and (std::max)
43 #include <visp3/core/vpConfig.h>
44 
45 #include <visp3/core/vpColVector.h>
46 #include <visp3/core/vpMath.h>
47 #include <visp3/core/vpMatrix.h>
48 
49 // Exception
50 #include <visp3/core/vpException.h>
51 #include <visp3/core/vpMatrixException.h>
52 
53 // Debug trace
54 #include <visp3/core/vpDebug.h>
55 
56 #ifdef VISP_HAVE_LAPACK
57 #  ifdef VISP_HAVE_GSL
58 #    if !(GSL_MAJOR_VERSION >= 2 && GSL_MINOR_VERSION >= 2)
59 // Needed for GSL_VERSION < 2.2 where gsl_linalg_tri_*_invert() not present
60 #      include <gsl/gsl_math.h>
61 #      include <gsl/gsl_vector.h>
62 #      include <gsl/gsl_matrix.h>
63 #      include <gsl/gsl_blas.h>
64 #    endif
65 #    include <gsl/gsl_linalg.h>
66 #    include <gsl/gsl_permutation.h>
67 #  endif
68 #  ifdef VISP_HAVE_MKL
69 #    include <mkl.h>
70 typedef MKL_INT integer;
71 
allocate_work(double ** work)72 integer allocate_work(double **work)
73 {
74   integer dimWork = (integer)((*work)[0]);
75   delete[] * work;
76   *work = new double[dimWork];
77   return (integer)dimWork;
78 }
79 #  elif !defined(VISP_HAVE_GSL)
80 #    ifdef VISP_HAVE_LAPACK_BUILT_IN
81 typedef long int integer;
82 #    else
83 typedef int integer;
84 #    endif
85 extern "C" int dgeqrf_(integer *m, integer *n, double *a, integer *lda, double *tau, double *work, integer *lwork,
86   integer *info);
87 extern "C" int dormqr_(char *side, char *trans, integer *m, integer *n, integer *k, double *a, integer *lda,
88   double *tau, double *c__, integer *ldc, double *work, integer *lwork, integer *info);
89 extern "C" int dorgqr_(integer *, integer *, integer *, double *, integer *, double *, double *, integer *, integer *);
90 extern "C" int dtrtri_(char *uplo, char *diag, integer *n, double *a, integer *lda, integer *info);
91 extern "C" int dgeqp3_(integer *m, integer *n, double*a, integer *lda, integer *p,
92   double *tau, double *work, integer* lwork, integer *info);
93 
94 int allocate_work(double **work);
95 
allocate_work(double ** work)96 int allocate_work(double **work)
97 {
98   unsigned int dimWork = (unsigned int)((*work)[0]);
99   delete[] * work;
100   *work = new double[dimWork];
101   return (int)dimWork;
102 }
103 #  endif
104 #endif
105 
106 #if defined(VISP_HAVE_GSL)
107 #ifndef DOXYGEN_SHOULD_SKIP_THIS
display_gsl(gsl_matrix * M)108 void display_gsl(gsl_matrix *M)
109 {
110   // display
111   for (unsigned int i = 0; i < M->size1; i++) {
112     unsigned int k = i * M->tda;
113     for (unsigned int j = 0; j < M->size2; j++) {
114       std:: cout << M->data[k + j] << " ";
115     }
116     std::cout << std::endl;
117   }
118 }
119 #endif
120 #endif
121 
122 #if defined(VISP_HAVE_LAPACK)
123 /*!
124   Compute the inverse of a n-by-n matrix using the QR decomposition with
125   Lapack 3rd party.
126 
127   \return The inverse matrix.
128 
129   Here an example:
130   \code
131 #include <visp3/core/vpMatrix.h>
132 
133 int main()
134 {
135   vpMatrix A(4,4);
136 
137   A[0][0] = 1/1.; A[0][1] = 1/2.; A[0][2] = 1/3.; A[0][3] = 1/4.;
138   A[1][0] = 1/5.; A[1][1] = 1/3.; A[1][2] = 1/3.; A[1][3] = 1/5.;
139   A[2][0] = 1/6.; A[2][1] = 1/4.; A[2][2] = 1/2.; A[2][3] = 1/6.;
140   A[3][0] = 1/7.; A[3][1] = 1/5.; A[3][2] = 1/6.; A[3][3] = 1/7.;
141 
142   // Compute the inverse
143   vpMatrix A_1 = A.inverseByQRLapack();
144   std::cout << "Inverse by QR: \n" << A_1 << std::endl;
145 
146   std::cout << "A*A^-1: \n" << A * A_1 << std::endl;
147 }
148   \endcode
149 
150   \sa inverseByQR()
151 */
inverseByQRLapack() const152 vpMatrix vpMatrix::inverseByQRLapack() const
153 {
154 #if defined(VISP_HAVE_GSL)
155   {
156     vpMatrix inv;
157     inv.resize(colNum, rowNum, false);
158     gsl_matrix *gsl_A, *gsl_Q, *gsl_R, gsl_inv;
159     gsl_vector *gsl_tau;
160 
161     gsl_A = gsl_matrix_alloc(rowNum, colNum);
162     gsl_Q = gsl_matrix_alloc(rowNum, rowNum); // M by M
163     gsl_R = gsl_matrix_alloc(rowNum, colNum); // M by N
164     gsl_tau = gsl_vector_alloc(std::min(rowNum, colNum));
165 
166     gsl_inv.size1 = inv.rowNum;
167     gsl_inv.size2 = inv.colNum;
168     gsl_inv.tda = gsl_inv.size2;
169     gsl_inv.data = inv.data;
170     gsl_inv.owner = 0;
171     gsl_inv.block = 0;
172 
173     // copy input matrix since gsl_linalg_QR_decomp() is destructive
174     unsigned int Atda = static_cast<unsigned int>(gsl_A->tda);
175     size_t len = sizeof(double) * colNum;
176     for (unsigned int i = 0; i < rowNum; i++) {
177       unsigned int k = i * Atda;
178       memcpy(&gsl_A->data[k], (*this)[i], len);
179     }
180     gsl_linalg_QR_decomp(gsl_A, gsl_tau);
181     gsl_linalg_QR_unpack(gsl_A, gsl_tau, gsl_Q, gsl_R);
182 #if (GSL_MAJOR_VERSION >= 2 && GSL_MINOR_VERSION >= 2)
183     gsl_linalg_tri_upper_invert(gsl_R);
184 #else
185     {
186       gsl_matrix_view m;
187       gsl_vector_view v;
188       for (unsigned int i = 0; i < rowNum; i++) {
189         double *Tii = gsl_matrix_ptr(gsl_R, i, i);
190         *Tii = 1.0 / (*Tii);
191         double aii = -(*Tii);
192         if (i > 0) {
193           m = gsl_matrix_submatrix(gsl_R, 0, 0, i, i);
194           v = gsl_matrix_subcolumn(gsl_R, i, 0, i);
195           gsl_blas_dtrmv(CblasUpper, CblasNoTrans, CblasNonUnit, &m.matrix, &v.vector);
196           gsl_blas_dscal(aii, &v.vector);
197         }
198       }
199     }
200 #endif
201     gsl_matrix_transpose(gsl_Q);
202 
203     gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, gsl_R, gsl_Q, 0, &gsl_inv);
204     unsigned int gsl_inv_tda = static_cast<unsigned int>(gsl_inv.tda);
205     size_t inv_len = sizeof(double) * inv.colNum;
206     for(unsigned int i = 0; i < inv.rowNum; i++) {
207       unsigned int k = i * gsl_inv_tda;
208       memcpy(inv[i], &gsl_inv.data[k], inv_len);
209     }
210 
211     gsl_matrix_free(gsl_A);
212     gsl_matrix_free(gsl_Q);
213     gsl_matrix_free(gsl_R);
214     gsl_vector_free(gsl_tau);
215 
216     return inv;
217   }
218 #else
219   {
220     if (rowNum != colNum) {
221       throw(vpMatrixException(vpMatrixException::matrixError, "Cannot inverse a non-square matrix (%ux%u) by QR", rowNum,
222                               colNum));
223     }
224 
225     integer rowNum_ = (integer)this->getRows();
226     integer colNum_ = (integer)this->getCols();
227     integer lda = (integer)rowNum_; // lda is the number of rows because we don't use a submatrix
228     integer dimTau = (std::min)(rowNum_, colNum_);
229     integer dimWork = -1;
230     double *tau = new double[dimTau];
231     double *work = new double[1];
232     integer info;
233     vpMatrix C;
234     vpMatrix A = *this;
235 
236     try {
237       // 1) Extract householder reflections (useful to compute Q) and R
238       dgeqrf_(&rowNum_, // The number of rows of the matrix A.  M >= 0.
239               &colNum_, // The number of columns of the matrix A.  N >= 0.
240               A.data,   /*On entry, the M-by-N matrix A.
241                                             On exit, the elements on and above the diagonal of
242                                          the array   contain the min(M,N)-by-N upper trapezoidal
243                                          matrix R (R is   upper triangular if m >= n); the
244                                          elements below the diagonal,   with the array TAU,
245                                          represent the orthogonal matrix Q as a   product of
246                                          min(m,n) elementary reflectors.
247                                           */
248               &lda,     // The leading dimension of the array A.  LDA >= max(1,M).
249               tau,      /*Dimension (min(M,N))
250                                         The scalar factors of the elementary reflectors
251                                       */
252               work,     // Internal working array. dimension (MAX(1,LWORK))
253               &dimWork, // The dimension of the array WORK.  LWORK >= max(1,N).
254               &info     // status
255               );
256 
257       if (info != 0) {
258         std::cout << "dgeqrf_:Preparation:" << -info << "th element had an illegal value" << std::endl;
259         throw vpMatrixException::badValue;
260       }
261       dimWork = allocate_work(&work);
262 
263       dgeqrf_(&rowNum_, // The number of rows of the matrix A.  M >= 0.
264               &colNum_, // The number of columns of the matrix A.  N >= 0.
265               A.data,   /*On entry, the M-by-N matrix A.
266                                             On exit, the elements on and above the diagonal of
267                                          the array   contain the min(M,N)-by-N upper trapezoidal
268                                          matrix R (R is   upper triangular if m >= n); the
269                                          elements below the diagonal,   with the array TAU,
270                                          represent the orthogonal matrix Q as a   product of
271                                          min(m,n) elementary reflectors.
272                                           */
273               &lda,     // The leading dimension of the array A.  LDA >= max(1,M).
274               tau,      /*Dimension (min(M,N))
275                                         The scalar factors of the elementary reflectors
276                                       */
277               work,     // Internal working array. dimension (MAX(1,LWORK))
278               &dimWork, // The dimension of the array WORK.  LWORK >= max(1,N).
279               &info     // status
280               );
281 
282       if (info != 0) {
283         std::cout << "dgeqrf_:" << -info << "th element had an illegal value" << std::endl;
284         throw vpMatrixException::badValue;
285       }
286 
287       // A now contains the R matrix in its upper triangular (in lapack
288       // convention)
289       C = A;
290 
291       // 2) Invert R
292       dtrtri_((char *)"U", (char *)"N", &dimTau, C.data, &lda, &info);
293       if (info != 0) {
294         if (info < 0)
295           std::cout << "dtrtri_:" << -info << "th element had an illegal value" << std::endl;
296         else if (info > 0) {
297           std::cout << "dtrtri_:R(" << info << "," << info << ")"
298                     << " is exactly zero.  The triangular matrix is singular "
299                        "and its inverse can not be computed."
300                     << std::endl;
301           std::cout << "R=" << std::endl << C << std::endl;
302         }
303         throw vpMatrixException::badValue;
304       }
305 
306       // 3) Zero-fill R^-1
307       // the matrix is upper triangular for lapack but lower triangular for visp
308       // we fill it with zeros above the diagonal (where we don't need the
309       // values)
310       for (unsigned int i = 0; i < C.getRows(); i++)
311         for (unsigned int j = 0; j < C.getRows(); j++)
312           if (j > i)
313             C[i][j] = 0.;
314 
315       dimWork = -1;
316       integer ldc = lda;
317 
318       // 4) Transpose Q and left-multiply it by R^-1
319       // get R^-1*tQ
320       // C contains R^-1
321       // A contains Q
322       dormqr_((char *)"R", (char *)"T", &rowNum_, &colNum_, &dimTau, A.data, &lda, tau, C.data, &ldc, work, &dimWork,
323               &info);
324       if (info != 0) {
325         std::cout << "dormqr_:Preparation" << -info << "th element had an illegal value" << std::endl;
326         throw vpMatrixException::badValue;
327       }
328       dimWork = allocate_work(&work);
329 
330       dormqr_((char *)"R", (char *)"T", &rowNum_, &colNum_, &dimTau, A.data, &lda, tau, C.data, &ldc, work, &dimWork,
331               &info);
332 
333       if (info != 0) {
334         std::cout << "dormqr_:" << -info << "th element had an illegal value" << std::endl;
335         throw vpMatrixException::badValue;
336       }
337       delete[] tau;
338       delete[] work;
339     } catch (vpMatrixException &) {
340       delete[] tau;
341       delete[] work;
342       throw;
343     }
344 
345     return C;
346   }
347 #endif
348 }
349 #endif
350 
351 /*!
352   Compute the inverse of a n-by-n matrix using the QR decomposition.
353   Only available if Lapack 3rd party is installed. If Lapack is not installed
354   we use a Lapack built-in version.
355 
356   \return The inverse matrix.
357 
358   Here an example:
359   \code
360 #include <visp3/core/vpMatrix.h>
361 
362 int main()
363 {
364   vpMatrix A(4,4);
365 
366   A[0][0] = 1/1.; A[0][1] = 1/2.; A[0][2] = 1/3.; A[0][3] = 1/4.;
367   A[1][0] = 1/5.; A[1][1] = 1/3.; A[1][2] = 1/3.; A[1][3] = 1/5.;
368   A[2][0] = 1/6.; A[2][1] = 1/4.; A[2][2] = 1/2.; A[2][3] = 1/6.;
369   A[3][0] = 1/7.; A[3][1] = 1/5.; A[3][2] = 1/6.; A[3][3] = 1/7.;
370 
371   // Compute the inverse
372   vpMatrix A_1 = A.inverseByQR();
373   std::cout << "Inverse by QR: \n" << A_1 << std::endl;
374 
375   std::cout << "A*A^-1: \n" << A * A_1 << std::endl;
376 }
377   \endcode
378 
379   \sa inverseByLU(), inverseByCholesky()
380 */
inverseByQR() const381 vpMatrix vpMatrix::inverseByQR() const
382 {
383 #if defined(VISP_HAVE_LAPACK)
384   return inverseByQRLapack();
385 #else
386   throw(vpException(vpException::fatalError, "Cannot inverse matrix by QR. Install Lapack 3rd party"));
387 #endif
388 }
389 
390 /*!
391   Compute the QR decomposition of a (m x n) matrix of rank r.
392   Only available if Lapack 3rd party is installed. If Lapack is not installed
393   we use a Lapack built-in version.
394 
395   \param Q : orthogonal matrix (will be modified).
396   \param R : upper-triangular matrix (will be modified).
397   \param full : whether or not we want full decomposition.
398   \param squareR : will return only the square (min(m,n) x min(m,n)) part of R.
399   \param tol : tolerance to test the rank of R.
400 
401   \return The rank r of the matrix.
402 
403   If full is false (default) then Q is (m x min(n,m)) and R is (min(n,m) x n).
404   We then have this = QR.
405 
406   If full is true and m > n then Q is (m x m) and R is (n x n).
407   In this case this = Q (R, 0)^T
408 
409   If squareR is true and n > m then R is (m x m). If r = m then R is invertible.
410 
411   Here an example:
412   \code
413 #include <visp3/core/vpMatrix.h>
414 
415 double residual(vpMatrix M1, vpMatrix M2)
416 {
417     return (M1 - M2).frobeniusNorm();
418 }
419 
420 int main()
421 {
422   vpMatrix A(4,3);
423 
424   A[0][0] = 1/1.; A[0][1] = 1/2.; A[0][2] = 1/3.;
425   A[1][0] = 1/5.; A[1][1] = 1/3.; A[1][2] = 1/3.;
426   A[2][0] = 1/6.; A[2][1] = 1/4.; A[2][2] = 1/2.;
427   A[3][0] = 1/7.; A[3][1] = 1/5.; A[3][2] = 1/6.;
428 
429   // Economic QR (Q 4x3, R 3x3)
430   vpMatrix Q, R;
431   int r = A.qr(A, R);
432   std::cout << "QR Residual: "
433             << residual(A, Q*R) << std::endl;
434 
435   // Full QR (Q 4x4, R 3x3)
436   r = A.qr(Q, R, true);
437   std::cout << "Full QR Residual: "
438             << residual(A, Q.extract(0, 0, 4, 3)*R) << std::endl;
439 }
440   \endcode
441 
442   \sa qrPivot()
443 */
qr(vpMatrix & Q,vpMatrix & R,bool full,bool squareR,double tol) const444 unsigned int vpMatrix::qr(vpMatrix &Q, vpMatrix &R, bool full, bool squareR, double tol) const
445 {
446 #if defined(VISP_HAVE_LAPACK)
447 #if defined(VISP_HAVE_GSL)
448   unsigned int m = rowNum;         // also rows of Q
449   unsigned int n = colNum;         // also columns of R
450   unsigned int r = std::min(n, m); // a priori non-null rows of R = rank of R
451   unsigned int q = r;              // columns of Q and rows of R
452   unsigned int na = n;             // columns of A
453 
454   // cannot be full decomposition if m < n
455   if(full && m > n) {
456     q = m;              // Q is square
457     na = m;             // A is square
458   }
459 
460   // prepare matrices and deal with r = 0
461   Q.resize(m, q, false);
462   if(squareR)
463     R.resize(r, r, false);
464   else
465     R.resize(r, n, false);
466   if(r == 0)
467     return 0;
468 
469   gsl_matrix *gsl_A, *gsl_Q, *gsl_R, gsl_Qfull;
470   gsl_vector *gsl_tau;
471 
472   gsl_A = gsl_matrix_alloc(rowNum, colNum);
473   gsl_R = gsl_matrix_alloc(rowNum, colNum); // M by N
474   gsl_tau = gsl_vector_alloc(std::min(rowNum, colNum));
475 
476   // copy input matrix since gsl_linalg_QR_decomp() is destructive
477   unsigned int Atda = static_cast<unsigned int>(gsl_A->tda);
478   size_t len = sizeof(double) * colNum;
479   for (unsigned int i = 0; i < rowNum; i++) {
480     unsigned int k = i * Atda;
481     memcpy(&gsl_A->data[k], (*this)[i], len);
482 //    for (unsigned int j = 0; j < colNum; j++)
483 //      gsl_A->data[k + j] = (*this)[i][j];
484   }
485 
486   gsl_linalg_QR_decomp(gsl_A, gsl_tau);
487 
488   if (full) {
489     // Q is M by M as expected by gsl_linalg_QR_unpack()
490     // for performance purpose dont allocate gsl_Q, but rather use gsl_Qfull = Q
491     gsl_Qfull.size1 = Q.rowNum;
492     gsl_Qfull.size2 = Q.colNum;
493     gsl_Qfull.tda = gsl_Qfull.size2;
494     gsl_Qfull.data = Q.data;
495     gsl_Qfull.owner = 0;
496     gsl_Qfull.block = 0;
497 
498     gsl_linalg_QR_unpack(gsl_A, gsl_tau, &gsl_Qfull, gsl_R);
499 //    std::cout << "gsl_Qfull:\n "; display_gsl(&gsl_Qfull);
500 //    std::cout << "gsl_R:\n "; display_gsl(gsl_R);
501   }
502   else {
503     gsl_Q = gsl_matrix_alloc(rowNum, rowNum); // M by M
504 
505     gsl_linalg_QR_unpack(gsl_A, gsl_tau, gsl_Q, gsl_R);
506 //    std::cout << "gsl_Q:\n "; display_gsl(gsl_Q);
507 //    std::cout << "gsl_R:\n "; display_gsl(gsl_R);
508 
509     unsigned int Qtda = static_cast<unsigned int>(gsl_Q->tda);
510     size_t len = sizeof(double) * Q.colNum;
511     for(unsigned int i = 0; i < Q.rowNum; i++) {
512       unsigned int k = i * Qtda;
513       memcpy(Q[i], &gsl_Q->data[k], len);
514 //      for(unsigned int j = 0; j < Q.colNum; j++) {
515 //        Q[i][j] = gsl_Q->data[k + j];
516 //      }
517     }
518     gsl_matrix_free(gsl_Q);
519   }
520 
521   // copy useful part of R and update rank
522   na = std::min(m, n);
523   unsigned int Rtda = static_cast<unsigned int>(gsl_R->tda);
524   size_t Rlen = sizeof(double) * R.colNum;
525   for(unsigned int i = 0; i < na; i++) {
526     unsigned int k = i * Rtda;
527     memcpy(R[i], &gsl_R->data[k], Rlen);
528 //      for(unsigned int j = i; j < na; j++)
529 //        R[i][j] = gsl_R->data[k + j];
530     if(std::abs(gsl_R->data[k + i]) < tol)
531       r--;
532   }
533 
534   gsl_matrix_free(gsl_A);
535   gsl_matrix_free(gsl_R);
536   gsl_vector_free(gsl_tau);
537 
538   return r;
539 #else
540   integer m = (integer)rowNum; // also rows of Q
541   integer n = (integer)colNum; // also columns of R
542   integer r = std::min(n, m);  // a priori non-null rows of R = rank of R
543   integer q = r;               // columns of Q and rows of R
544   integer na = n;              // columns of A
545 
546   // cannot be full decomposition if m < n
547   if(full && m > n) {
548     q = m;              // Q is square
549     na = m;             // A is square
550   }
551 
552   // prepare matrices and deal with r = 0
553   Q.resize(static_cast<unsigned int>(m), static_cast<unsigned int>(q));
554   if(squareR)
555     R.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(r));
556   else
557     R.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(n));
558   if(r == 0)
559     return 0;
560 
561   integer dimWork = -1;
562   double * qrdata = new double[m*na];
563   double *tau = new double[std::min(m,q)];
564   double *work = new double[1];
565   integer info;
566 
567   // copy this to qrdata in Lapack convention
568   for (integer i = 0; i < m; ++i)
569   {
570     for (integer j = 0; j < n; ++j)
571       qrdata[i + m * j] = data[j + n * i];
572     for (integer j = n; j < na; ++j)
573       qrdata[i + m * j] = 0;
574   }
575 
576   //   work = new double[1];
577   //1) Extract householder reflections (useful to compute Q) and R
578   dgeqrf_(
579         &m,        //The number of rows of the matrix A.  M >= 0.
580         &na,        //The number of columns of the matrix A.  N >= 0.
581         qrdata,
582         &m,
583         tau,
584         work,           //Internal working array. dimension (MAX(1,LWORK))
585         &dimWork,       //The dimension of the array WORK.  LWORK >= max(1,N).
586         &info           //status
587         );
588 
589   if(info != 0){
590     std::cout << "dgeqrf_:Preparation:" << -info << "th element had an illegal value" << std::endl;
591     delete[] qrdata;
592     delete[] work;
593     delete[] tau;
594     throw vpMatrixException::badValue;
595   }
596   dimWork = allocate_work(&work);
597 
598   dgeqrf_(
599         &m,        //The number of rows of the matrix A.  M >= 0.
600         &na,        //The number of columns of the matrix A.  N >= 0.
601         qrdata,
602         &m,            //The leading dimension of the array A.  LDA >= max(1,M).
603         tau,
604         work,           //Internal working array. dimension (MAX(1,LWORK))
605         &dimWork,       //The dimension of the array WORK.  LWORK >= max(1,N).
606         &info           //status
607         );
608 
609   if(info != 0){
610     std::cout << "dgeqrf_:" << -info << "th element had an illegal value" << std::endl;
611     delete[] qrdata;
612     delete[] work;
613     delete[] tau;
614     throw vpMatrixException::badValue;
615   }
616 
617   // data now contains the R matrix in its upper triangular (in lapack convention)
618 
619   // copy useful part of R from Q and update rank
620   na = std::min(m,n);
621   if(squareR)
622   {
623     for(int i=0;i<na;i++)
624     {
625       for(int j=i;j<na;j++)
626         R[i][j] = qrdata[i+m*j];
627       if(std::abs(qrdata[i+m*i]) < tol)
628         r--;
629     }
630   }
631   else
632   {
633     for(int i=0;i<na;i++)
634     {
635       for(int j=i;j<n;j++)
636         R[i][j] = qrdata[i+m*j];
637       if(std::abs(qrdata[i+m*i]) < tol)
638         r--;
639     }
640   }
641 
642   // extract Q
643   dorgqr_(&m, // The number of rows of the matrix Q. M >= 0.
644           &q, // The number of columns of the matrix Q. M >= N >= 0.
645           &q,
646           qrdata,
647           &m,            //The leading dimension of the array A.  LDA >= max(1,M).
648           tau,
649           work,           //Internal working array. dimension (MAX(1,LWORK))
650           &dimWork,       //The dimension of the array WORK.  LWORK >= max(1,N).
651           &info           //status
652           );
653 
654   // write qrdata into Q
655   for(int i = 0; i < m; ++i)
656     for(int j = 0; j < q; ++j)
657       Q[i][j] = qrdata[i+m*j];
658 
659   delete[] qrdata;
660   delete[] work;
661   delete[] tau;
662   return (unsigned int) r;
663 #endif // defined(VISP_HAVE_GSL)
664 #else
665   (void)Q;
666   (void)R;
667   (void)full;
668   (void)squareR;
669   (void)tol;
670   throw(vpException(vpException::fatalError, "Cannot perform QR decomposition. Install Lapack 3rd party"));
671 #endif
672 }
673 
674 
675 /*!
676   Compute the QR pivot decomposition of a (m x n) matrix of rank r.
677   Only available if Lapack 3rd party is installed. If Lapack is not installed
678   we use a Lapack built-in version.
679 
680   \param Q : orthogonal matrix (will be modified).
681   \param R : upper-triangular matrix (will be modified).
682   \param P : the (n x n) permutation matrix.
683   \param full : whether or not we want full decomposition.
684   \param squareR : will return only the (r x r) part of R and the (r x n) part of P.
685   \param tol : tolerance to test the rank of R.
686 
687   \return The rank r of the matrix.
688 
689   If full is false (default) then Q is (m x min(n,m)) and R is (min(n,m) x n).
690   We then have this.P = Q.R.
691 
692   If full is true and m > n then Q is (m x m) and R is (n x n).
693   In this case this.P = Q (R, 0)^T
694 
695   If squareR is true then R is (r x r) invertible.
696 
697   Here an example:
698   \code
699 #include <visp3/core/vpMatrix.h>
700 
701 double residual(vpMatrix M1, vpMatrix M2)
702 {
703     return (M1 - M2).frobeniusNorm();
704 }
705 
706 int main()
707 {
708   vpMatrix A(4,3);
709 
710   A[0][0] = 1/1.; A[0][1] = 1/2.; A[0][2] = 1/2.;
711   A[1][0] = 1/5.; A[1][1] = 1/3.; A[1][2] = 1/3.;
712   A[2][0] = 1/6.; A[2][1] = 1/4.; A[2][2] = 1/4.;
713   A[3][0] = 1/7.; A[3][1] = 1/5.; A[3][2] = 1/5.;
714   // A is (4x3) but rank 2
715 
716   // Economic QR (Q 4x3, R 3x3)
717   vpMatrix Q, R, P;
718   int r = A.qrPivot(Q, R, P);
719   std::cout << "A rank: " << r << std::endl;
720   std::cout << "Residual: " << residual(A*P, Q*R) << std::endl;
721 
722   // Full QR (Q 4x4, R 3x3)
723   r = A.qrPivot(Q, R, P, true);
724   std::cout << "QRPivot Residual: " <<
725   residual(A*P, Q.extract(0, 0, 4, 3)*R) << std::endl;
726 
727   // Using permutation matrix: keep only non-null part of R
728   Q.resize(4, r, false);            // Q is 4 x 2
729   R = R.extract(0, 0, r, 3)*P.t();  // R is 2 x 3
730   std::cout << "Full QRPivot Residual: " <<
731   residual(A, Q*R) << std::endl;
732 }
733   \endcode
734 
735   \sa qrPivot()
736 */
qrPivot(vpMatrix & Q,vpMatrix & R,vpMatrix & P,bool full,bool squareR,double tol) const737 unsigned int vpMatrix::qrPivot(vpMatrix &Q, vpMatrix &R, vpMatrix &P, bool full, bool squareR, double tol) const
738 {
739 #if defined(VISP_HAVE_LAPACK)
740 #if defined(VISP_HAVE_GSL)
741   unsigned int m = rowNum;         // also rows of Q
742   unsigned int n = colNum;         // also columns of R
743   unsigned int r = std::min(n, m); // a priori non-null rows of R = rank of R
744   unsigned int q = r;              // columns of Q and rows of R
745   unsigned int na = n;             // columns of A
746 
747   // cannot be full decomposition if m < n
748   if(full && m > n) {
749     q = m;              // Q is square
750     na = m;             // A is square
751   }
752 
753   // prepare Q and deal with r = 0
754   Q.resize(m, q, false);
755   if(r == 0) {
756     if(squareR) {
757       R.resize(0, 0, false);
758       P.resize(0, n, false);
759     }
760     else {
761       R.resize(r, n, false);
762       P.resize(n, n);
763     }
764     return 0;
765   }
766 
767   gsl_matrix gsl_A, *gsl_Q, *gsl_R, gsl_Qfull;
768   gsl_vector *gsl_tau;
769   gsl_permutation *gsl_p;
770   gsl_vector *gsl_norm;
771   int gsl_signum;
772 
773   gsl_A.size1 = rowNum;
774   gsl_A.size2 = colNum;
775   gsl_A.tda = gsl_A.size2;
776   gsl_A.data = this->data;
777   gsl_A.owner = 0;
778   gsl_A.block = 0;
779 
780   gsl_R = gsl_matrix_alloc(rowNum, colNum); // M by N
781   gsl_tau = gsl_vector_alloc(std::min(rowNum, colNum));
782   gsl_norm = gsl_vector_alloc(colNum);
783   gsl_p = gsl_permutation_alloc(n);
784 
785   if (full) {
786     // Q is M by M as expected by gsl_linalg_QR_unpack()
787     // for performance purpose dont allocate gsl_Q, but rather use gsl_Qfull = Q
788     gsl_Qfull.size1 = Q.rowNum;
789     gsl_Qfull.size2 = Q.colNum;
790     gsl_Qfull.tda = gsl_Qfull.size2;
791     gsl_Qfull.data = Q.data;
792     gsl_Qfull.owner = 0;
793     gsl_Qfull.block = 0;
794 
795     gsl_linalg_QRPT_decomp2(&gsl_A, &gsl_Qfull, gsl_R, gsl_tau, gsl_p, &gsl_signum, gsl_norm);
796 //    std::cout << "gsl_Qfull:\n "; display_gsl(&gsl_Qfull);
797 //    std::cout << "gsl_R:\n "; display_gsl(gsl_R);
798   }
799   else {
800     gsl_Q = gsl_matrix_alloc(rowNum, rowNum); // M by M
801 
802     gsl_linalg_QRPT_decomp2(&gsl_A, gsl_Q, gsl_R, gsl_tau, gsl_p, &gsl_signum, gsl_norm);
803 //    std::cout << "gsl_Q:\n "; display_gsl(gsl_Q);
804 //    std::cout << "gsl_R:\n "; display_gsl(gsl_R);
805 
806     unsigned int Qtda = static_cast<unsigned int>(gsl_Q->tda);
807     size_t len = sizeof(double) * Q.colNum;
808     for(unsigned int i = 0; i < Q.rowNum; i++) {
809       unsigned int k = i * Qtda;
810       memcpy(Q[i], &gsl_Q->data[k], len);
811 //      for(unsigned int j = 0; j < Q.colNum; j++) {
812 //        Q[i][j] = gsl_Q->data[k + j];
813 //      }
814     }
815     gsl_matrix_free(gsl_Q);
816   }
817 
818   // update rank
819   na = std::min(m, n);
820   unsigned int Rtda = static_cast<unsigned int>(gsl_R->tda);
821   for(unsigned int i = 0; i < na; i++) {
822     unsigned int k = i * Rtda;
823     if(std::abs(gsl_R->data[k + i]) < tol)
824       r--;
825   }
826 
827   if(squareR) {
828     R.resize(r, r, false); // R r x r
829     P.resize(r, n);
830     for(unsigned int i = 0; i < r; ++i)
831       P[i][gsl_p->data[i]] = 1;
832   }
833   else {
834     R.resize(na, n, false); // R is min(m,n) x n of rank r
835     P.resize(n, n);
836     for(unsigned int i = 0; i < n; ++i)
837       P[i][gsl_p->data[i]] = 1;
838   }
839 
840   // copy useful part of R
841   size_t Rlen = sizeof(double) * R.colNum;
842   for(unsigned int i = 0; i < na; i++) {
843     unsigned int k = i * Rtda;
844     memcpy(R[i], &gsl_R->data[k], Rlen);
845   }
846 
847   gsl_matrix_free(gsl_R);
848   gsl_vector_free(gsl_tau);
849   gsl_vector_free(gsl_norm);
850   gsl_permutation_free(gsl_p);
851 
852   return r;
853 #else
854   integer m = (integer)rowNum; // also rows of Q
855   integer n = (integer)colNum; // also columns of R
856   integer r = std::min(n, m);  // a priori non-null rows of R = rank of R
857   integer q = r;               // columns of Q and rows of R
858   integer na = n;              // columns of A
859 
860   // cannot be full decomposition if m < n
861   // cannot be full decomposition if m < n
862   if(full && m > n) {
863     q = m;              // Q is square
864     na = m;             // A is square
865   }
866 
867   // prepare Q and deal with r = 0
868   Q.resize(static_cast<unsigned int>(m), static_cast<unsigned int>(q));
869   if(r == 0) {
870     if(squareR) {
871       R.resize(0, 0);
872       P.resize(0, static_cast<unsigned int>(n));
873     }
874     else {
875       R.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(n));
876       P.resize(static_cast<unsigned int>(n), static_cast<unsigned int>(n));
877     }
878     return 0;
879   }
880 
881   integer dimWork = -1;
882   double* qrdata = new double[m*na];
883   double* tau = new double[std::min(q,m)];
884   double* work = new double[1];
885   integer* p = new integer[na];
886   for(int i = 0; i < na; ++i)
887     p[i] = 0;
888 
889   integer info;
890 
891   // copy this to qrdata in Lapack convention
892   for(integer i = 0; i < m; ++i)
893   {
894     for(integer j = 0; j < n; ++j)
895       qrdata[i+m*j] = data[j + n*i];
896     for(integer j = n; j < na; ++j)
897       qrdata[i+m*j] = 0;
898   }
899 
900   //1) Extract householder reflections (useful to compute Q) and R
901   dgeqp3_(
902         &m,        //The number of rows of the matrix A.  M >= 0.
903         &na,        //The number of columns of the matrix A.  N >= 0.
904         qrdata,    /*On entry, the M-by-N matrix A.        */
905         &m,      //The leading dimension of the array A.  LDA >= max(1,M).
906         p,         // Dimension N
907         tau,        /*Dimension (min(M,N))        */
908         work,       //Internal working array. dimension (3*N)
909 
910         &dimWork,
911         &info       //status
912         );
913 
914   if(info != 0){
915     std::cout << "dgeqp3_:Preparation:" << -info << "th element had an illegal value" << std::endl;
916     delete[] qrdata;
917     delete[] work;
918     delete[] tau;
919     delete[] p;
920     throw vpMatrixException::badValue;
921   }
922 
923   dimWork = allocate_work(&work);
924 
925   dgeqp3_(
926         &m,        //The number of rows of the matrix A.  M >= 0.
927         &na,        //The number of columns of the matrix A.  N >= 0.
928         qrdata,    /*On entry, the M-by-N matrix A.        */
929         &m,      //The leading dimension of the array A.  LDA >= max(1,M).
930         p,         // Dimension N
931         tau,        /*Dimension (min(M,N))        */
932         work,       //Internal working array. dimension (3*N)
933 
934         &dimWork,
935         &info       //status
936         );
937 
938   if(info != 0){
939     std::cout << "dgeqp3_:" << -info << " th element had an illegal value" << std::endl;
940     delete[] qrdata;
941     delete[] work;
942     delete[] tau;
943     delete[] p;
944     throw vpMatrixException::badValue;
945   }
946 
947   // data now contains the R matrix in its upper triangular (in lapack convention)
948   // get rank of R in r
949   na = std::min(n,m);
950   for(int i = 0; i < na; ++i)
951     if(std::abs(qrdata[i+m*i]) < tol)
952       r--;
953 
954   // write R
955   if(squareR) // R r x r
956   {
957     R.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(r));
958     for(int i=0;i<r;i++)
959       for(int j=i;j<r;j++)
960         R[i][j] = qrdata[i+m*j];
961 
962     // write P
963     P.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(n));
964     for(int i = 0; i < r; ++i)
965       P[i][p[i]-1] = 1;
966   }
967   else        // R is min(m,n) x n of rank r
968   {
969     R.resize(static_cast<unsigned int>(na), static_cast<unsigned int>(n));
970     for(int i=0;i<na;i++)
971       for(int j=i;j<n;j++)
972         R[i][j] = qrdata[i+m*j];
973     // write P
974     P.resize(static_cast<unsigned int>(n), static_cast<unsigned int>(n));
975     for(int i = 0; i < n; ++i)
976       P[i][p[i]-1] = 1;
977   }
978 
979   // extract Q
980   dorgqr_(&m, // The number of rows of the matrix Q. M >= 0.
981           &q, // The number of columns of the matrix Q. M >= N >= 0.
982           &q,
983           qrdata,
984           &m,            //The leading dimension of the array A.  LDA >= max(1,M).
985           tau,
986           work,           //Internal working array. dimension (MAX(1,LWORK))
987           &dimWork,       //The dimension of the array WORK.  LWORK >= max(1,N).
988           &info           //status
989           );
990 
991   // write qrdata into Q
992   for(int i = 0; i < m; ++i)
993     for(int j = 0; j < q; ++j)
994       Q[i][j] = qrdata[i+m*j];
995 
996   delete[] qrdata;
997   delete[] work;
998   delete[] tau;
999   delete[] p;
1000   return (unsigned int) r;
1001 #endif
1002 #else
1003   (void)Q;
1004   (void)R;
1005   (void)P;
1006   (void)full;
1007   (void)squareR;
1008   (void)tol;
1009   throw(vpException(vpException::fatalError, "Cannot perform QR decomposition. Install Lapack 3rd party"));
1010 #endif
1011 }
1012 
1013 /*!
1014   Compute the inverse of a full-rank n-by-n triangular matrix.
1015   Only available if Lapack 3rd party is installed. If Lapack is not installed
1016   we use a Lapack built-in version.
1017 
1018   \param upper : if it is an upper triangular matrix
1019 
1020   The function does not check if the matrix is actually upper or lower triangular.
1021 
1022   \return The inverse matrix
1023 */
inverseTriangular(bool upper) const1024 vpMatrix vpMatrix::inverseTriangular(bool upper) const
1025 {
1026   if(rowNum != colNum || rowNum == 0) {
1027     throw(vpException(vpException::dimensionError,
1028                       "Cannot inverse a triangular matrix (%d, %d) that is not square", rowNum, colNum));
1029   }
1030 #if defined(VISP_HAVE_LAPACK)
1031 #if defined(VISP_HAVE_GSL)
1032   vpMatrix inv;
1033   inv.resize(colNum, rowNum, false);
1034   gsl_matrix gsl_inv;
1035 
1036   gsl_inv.size1 = inv.rowNum;
1037   gsl_inv.size2 = inv.colNum;
1038   gsl_inv.tda = gsl_inv.size2;
1039   gsl_inv.data = inv.data;
1040   gsl_inv.owner = 0;
1041   gsl_inv.block = 0;
1042 
1043   unsigned int tda = static_cast<unsigned int>(gsl_inv.tda);
1044   size_t len = sizeof(double) * inv.colNum;
1045   for (unsigned int i = 0; i < rowNum; i++) {
1046     unsigned int k = i * tda;
1047     memcpy(&gsl_inv.data[k], (*this)[i], len);
1048   }
1049 
1050   if (upper) {
1051 #if (GSL_MAJOR_VERSION >= 2 && GSL_MINOR_VERSION >= 2)
1052     gsl_linalg_tri_upper_invert(&gsl_inv);
1053 #else
1054     {
1055       gsl_matrix_view m;
1056       gsl_vector_view v;
1057       for (unsigned int i = 0; i < rowNum; i++) {
1058         double *Tii = gsl_matrix_ptr(&gsl_inv, i, i);
1059         *Tii = 1.0 / *Tii;
1060         double aii = -(*Tii);
1061         if (i > 0) {
1062           m = gsl_matrix_submatrix(&gsl_inv, 0, 0, i, i);
1063           v = gsl_matrix_subcolumn(&gsl_inv, i, 0, i);
1064           gsl_blas_dtrmv(CblasUpper, CblasNoTrans, CblasNonUnit, &m.matrix, &v.vector);
1065           gsl_blas_dscal(aii, &v.vector);
1066         }
1067       }
1068     }
1069 #endif
1070   }
1071   else {
1072 #if (GSL_MAJOR_VERSION >= 2 && GSL_MINOR_VERSION >= 2)
1073     gsl_linalg_tri_lower_invert(&gsl_inv);
1074 #else
1075     {
1076       gsl_matrix_view m;
1077       gsl_vector_view v;
1078       for (unsigned int i = 0; i < rowNum; i++) {
1079         size_t j = rowNum - i - 1;
1080         double *Tjj = gsl_matrix_ptr(&gsl_inv, j, j);
1081         *Tjj = 1.0 / (*Tjj);
1082         double ajj = -(*Tjj);
1083         if (j < rowNum - 1) {
1084           m = gsl_matrix_submatrix(&gsl_inv, j + 1, j + 1, rowNum - j - 1, rowNum - j - 1);
1085           v = gsl_matrix_subcolumn(&gsl_inv, j, j + 1, rowNum - j - 1);
1086           gsl_blas_dtrmv(CblasLower, CblasNoTrans, CblasNonUnit, &m.matrix, &v.vector);
1087           gsl_blas_dscal(ajj, &v.vector);
1088         }
1089       }
1090     }
1091 #endif
1092   }
1093 
1094   return inv;
1095 #else
1096   integer n = (integer) rowNum; // lda is the number of rows because we don't use a submatrix
1097 
1098   vpMatrix R = *this;
1099   integer info;
1100 
1101   // we just use the other (upper / lower) method from Lapack
1102   if(rowNum > 1 && upper)  // upper triangular
1103     dtrtri_((char *)"L", (char *)"N", &n, R.data, &n, &info);
1104   else
1105     dtrtri_((char *)"U", (char *)"N", &n, R.data, &n, &info);
1106 
1107   if (info != 0) {
1108     if (info < 0)
1109       std::cout << "dtrtri_:" << -info << "th element had an illegal value" << std::endl;
1110     else if (info > 0) {
1111       std::cout << "dtrtri_:R(" << info << "," << info << ")"
1112                 << " is exactly zero.  The triangular matrix is singular "
1113                    "and its inverse can not be computed."
1114                 << std::endl;
1115       throw vpMatrixException::rankDeficient;
1116     }
1117     throw vpMatrixException::badValue;
1118   }
1119   return R;
1120 #endif
1121 #else
1122   (void)upper;
1123   throw(vpException(vpException::fatalError, "Cannot perform triangular inverse. Install Lapack 3rd party"));
1124 #endif
1125 }
1126 
1127 
1128 /*!
1129   Solve a linear system Ax = b using QR Decomposition.
1130 
1131   Non destructive wrt. A and b.
1132 
1133   \param b : Vector  b
1134   \param x : Vector  x
1135 
1136   \warning If Ax = b does not have a solution, this method does not return the least-square
1137   minimizer. Use solveBySVD() to get this vector.
1138 
1139   Here an example:
1140   \code
1141     #include <visp3/core/vpColVector.h>
1142     #include <visp3/core/vpMatrix.h>
1143     int main()
1144     {
1145       vpMatrix A(3,3);
1146       A[0][0] = 4.64;
1147       A[0][1] = 0.288;
1148       A[0][2] = -0.384;
1149       A[1][0] = 0.288;
1150       A[1][1] = 7.3296;
1151       A[1][2] = 2.2272;
1152       A[2][0] = -0.384;
1153       A[2][1] = 2.2272;
1154       A[2][2] = 6.0304;
1155       vpColVector X(3), B(3);
1156       B[0] = 1;
1157       B[1] = 2;
1158       B[2] = 3;
1159       A.solveByQR(B, X);
1160       // Obtained values of X
1161       // X[0] = 0.2468;
1162       // X[1] = 0.120782;
1163       // X[2] = 0.468587;
1164       std::cout << "X:\n" << X << std::endl;
1165     }
1166   \endcode
1167 
1168   \sa qrPivot()
1169 */
solveByQR(const vpColVector & b,vpColVector & x) const1170 void vpMatrix::solveByQR(const vpColVector &b, vpColVector &x) const
1171 {
1172   vpMatrix Q, R, P;
1173   unsigned int r = t().qrPivot(Q, R, P, false, true);
1174   x = Q.extract(0, 0, colNum, r)
1175       * R.inverseTriangular().t()
1176       * P * b;
1177 }
1178 
1179 /*!
1180   Solve a linear system Ax = b using QR Decomposition.
1181 
1182   Non destructive wrt. A and B.
1183 
1184   \param b : Vector b
1185 
1186   \return Vector x
1187 
1188   \warning If Ax = b does not have a solution, this method does not return the least-square
1189   minimizer. Use solveBySVD() to get this vector.
1190 
1191   Here an example:
1192   \code
1193     #include <visp3/core/vpColVector.h>
1194     #include <visp3/core/vpMatrix.h>
1195     int main()
1196     {
1197       vpMatrix A(3,3);
1198       A[0][0] = 4.64;
1199       A[0][1] = 0.288;
1200       A[0][2] = -0.384;
1201       A[1][0] = 0.288;
1202       A[1][1] = 7.3296;
1203       A[1][2] = 2.2272;
1204       A[2][0] = -0.384;
1205       A[2][1] = 2.2272;
1206       A[2][2] = 6.0304;
1207       vpColVector X(3), B(3);
1208       B[0] = 1;
1209       B[1] = 2;
1210       B[2] = 3;
1211       X = A.solveByQR(B);
1212       // Obtained values of X
1213       // X[0] = 0.2468;
1214       // X[1] = 0.120782;
1215       // X[2] = 0.468587;
1216       std::cout << "X:\n" << X << std::endl;
1217     }
1218   \endcode
1219 
1220   \sa qrPivot()
1221 */
solveByQR(const vpColVector & b) const1222 vpColVector vpMatrix::solveByQR(const vpColVector &b) const
1223 {
1224   vpColVector x(colNum);
1225   solveByQR(b, x);
1226   return x;
1227 }
1228