Visual Servoing Platform  version 3.6.1 under development (2024-04-25)
vpMatrix_qr.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 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 https://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  *
37 *****************************************************************************/
38 
39 #include <algorithm> // for (std::min) and (std::max)
40 #include <cmath> // For std::abs() on iOS
41 #include <cstdlib> // For std::abs() on iOS
42 #include <visp3/core/vpConfig.h>
43 
44 #include <visp3/core/vpColVector.h>
45 #include <visp3/core/vpMath.h>
46 #include <visp3/core/vpMatrix.h>
47 
48 // Exception
49 #include <visp3/core/vpException.h>
50 #include <visp3/core/vpMatrixException.h>
51 
52 // Debug trace
53 #include <visp3/core/vpDebug.h>
54 
55 #ifdef VISP_HAVE_LAPACK
56 #ifdef VISP_HAVE_GSL
57 #if !(GSL_MAJOR_VERSION >= 2 && GSL_MINOR_VERSION >= 2)
58 // Needed for GSL_VERSION < 2.2 where gsl_linalg_tri_*_invert() not present
59 #include <gsl/gsl_blas.h>
60 #include <gsl/gsl_math.h>
61 #include <gsl/gsl_matrix.h>
62 #include <gsl/gsl_vector.h>
63 #endif
64 #include <gsl/gsl_linalg.h>
65 #include <gsl/gsl_permutation.h>
66 #endif
67 #ifdef VISP_HAVE_MKL
68 #include <mkl.h>
69 typedef MKL_INT integer;
70 
71 integer allocate_work(double **work)
72 {
73  integer dimWork = (integer)((*work)[0]);
74  delete[] * work;
75  *work = new double[dimWork];
76  return (integer)dimWork;
77 }
78 #elif !defined(VISP_HAVE_GSL)
79 #ifdef VISP_HAVE_LAPACK_BUILT_IN
80 typedef long int integer;
81 #else
82 typedef int integer;
83 #endif
84 extern "C" int dgeqrf_(integer *m, integer *n, double *a, integer *lda, double *tau, double *work, integer *lwork,
85  integer *info);
86 extern "C" int dormqr_(char *side, char *trans, integer *m, integer *n, integer *k, double *a, integer *lda,
87  double *tau, double *c__, integer *ldc, double *work, integer *lwork, integer *info);
88 extern "C" int dorgqr_(integer *, integer *, integer *, double *, integer *, double *, double *, integer *, integer *);
89 extern "C" int dtrtri_(char *uplo, char *diag, integer *n, double *a, integer *lda, integer *info);
90 extern "C" int dgeqp3_(integer *m, integer *n, double *a, integer *lda, integer *p, double *tau, double *work,
91  integer *lwork, integer *info);
92 
93 int allocate_work(double **work);
94 
95 int allocate_work(double **work)
96 {
97  unsigned int dimWork = (unsigned int)((*work)[0]);
98  delete[] * work;
99  *work = new double[dimWork];
100  return (int)dimWork;
101 }
102 #endif
103 #endif
104 
105 #if defined(VISP_HAVE_GSL)
106 #ifndef DOXYGEN_SHOULD_SKIP_THIS
107 void display_gsl(gsl_matrix *M)
108 {
109  // display
110  for (unsigned int i = 0; i < M->size1; ++i) {
111  unsigned int k = i * M->tda;
112  for (unsigned int j = 0; j < M->size2; ++j) {
113  std::cout << M->data[k + j] << " ";
114  }
115  std::cout << std::endl;
116  }
117 }
118 #endif
119 #endif
120 
121 #if defined(VISP_HAVE_LAPACK)
152 {
153 #if defined(VISP_HAVE_GSL)
154  {
155  vpMatrix inv;
156  inv.resize(colNum, rowNum, false);
157  gsl_matrix *gsl_A, *gsl_Q, *gsl_R, gsl_inv;
158  gsl_vector *gsl_tau;
159 
160  gsl_A = gsl_matrix_alloc(rowNum, colNum);
161  gsl_Q = gsl_matrix_alloc(rowNum, rowNum); // M by M
162  gsl_R = gsl_matrix_alloc(rowNum, colNum); // M by N
163  gsl_tau = gsl_vector_alloc(std::min<unsigned int>(rowNum, colNum));
164 
165  gsl_inv.size1 = inv.rowNum;
166  gsl_inv.size2 = inv.colNum;
167  gsl_inv.tda = gsl_inv.size2;
168  gsl_inv.data = inv.data;
169  gsl_inv.owner = 0;
170  gsl_inv.block = 0;
171 
172  // copy input matrix since gsl_linalg_QR_decomp() is destructive
173  unsigned int Atda = static_cast<unsigned int>(gsl_A->tda);
174  size_t len = sizeof(double) * colNum;
175  for (unsigned int i = 0; i < rowNum; ++i) {
176  unsigned int k = i * Atda;
177  memcpy(&gsl_A->data[k], (*this)[i], len);
178  }
179  gsl_linalg_QR_decomp(gsl_A, gsl_tau);
180  gsl_linalg_QR_unpack(gsl_A, gsl_tau, gsl_Q, gsl_R);
181 #if (GSL_MAJOR_VERSION >= 2 && GSL_MINOR_VERSION >= 2)
182  gsl_linalg_tri_upper_invert(gsl_R);
183 #else
184  {
185  gsl_matrix_view m;
186  gsl_vector_view v;
187  for (unsigned int i = 0; i < rowNum; ++i) {
188  double *Tii = gsl_matrix_ptr(gsl_R, i, i);
189  *Tii = 1.0 / (*Tii);
190  double aii = -(*Tii);
191  if (i > 0) {
192  m = gsl_matrix_submatrix(gsl_R, 0, 0, i, i);
193  v = gsl_matrix_subcolumn(gsl_R, i, 0, i);
194  gsl_blas_dtrmv(CblasUpper, CblasNoTrans, CblasNonUnit, &m.matrix, &v.vector);
195  gsl_blas_dscal(aii, &v.vector);
196  }
197  }
198  }
199 #endif
200  gsl_matrix_transpose(gsl_Q);
201 
202  gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, gsl_R, gsl_Q, 0, &gsl_inv);
203  unsigned int gsl_inv_tda = static_cast<unsigned int>(gsl_inv.tda);
204  size_t inv_len = sizeof(double) * inv.colNum;
205  for (unsigned int i = 0; i < inv.rowNum; ++i) {
206  unsigned int k = i * gsl_inv_tda;
207  memcpy(inv[i], &gsl_inv.data[k], inv_len);
208  }
209 
210  gsl_matrix_free(gsl_A);
211  gsl_matrix_free(gsl_Q);
212  gsl_matrix_free(gsl_R);
213  gsl_vector_free(gsl_tau);
214 
215  return inv;
216  }
217 #else
218  {
219  if (rowNum != colNum) {
220  throw(vpMatrixException(vpMatrixException::matrixError, "Cannot inverse a non-square matrix (%ux%u) by QR",
221  rowNum, colNum));
222  }
223 
224  integer rowNum_ = (integer)this->getRows();
225  integer colNum_ = (integer)this->getCols();
226  integer lda = (integer)rowNum_; // lda is the number of rows because we don't use a submatrix
227  integer dimTau = std::min<integer>(rowNum_, colNum_);
228  integer dimWork = -1;
229  double *tau = new double[dimTau];
230  double *work = new double[1];
231  integer info;
232  vpMatrix C;
233  vpMatrix A = *this;
234 
235  try {
236  // 1) Extract householder reflections (useful to compute Q) and R
237  dgeqrf_(&rowNum_, // The number of rows of the matrix A. M >= 0.
238  &colNum_, // The number of columns of the matrix A. N >= 0.
239  A.data, /*On entry, the M-by-N matrix A.
240  On exit, the elements on and above the diagonal of
241  the array contain the min(M,N)-by-N upper trapezoidal
242  matrix R (R is upper triangular if m >= n); the
243  elements below the diagonal, with the array TAU,
244  represent the orthogonal matrix Q as a product of
245  min(m,n) elementary reflectors.
246  */
247  &lda, // The leading dimension of the array A. LDA >= max(1,M).
248  tau, /*Dimension (min(M,N))
249  The scalar factors of the elementary reflectors
250  */
251  work, // Internal working array. dimension (MAX(1,LWORK))
252  &dimWork, // The dimension of the array WORK. LWORK >= max(1,N).
253  &info // status
254  );
255 
256  if (info != 0) {
257  std::cout << "dgeqrf_:Preparation:" << -info << "th element had an illegal value" << std::endl;
259  }
260  dimWork = allocate_work(&work);
261 
262  dgeqrf_(&rowNum_, // The number of rows of the matrix A. M >= 0.
263  &colNum_, // The number of columns of the matrix A. N >= 0.
264  A.data, /*On entry, the M-by-N matrix A.
265  On exit, the elements on and above the diagonal of
266  the array contain the min(M,N)-by-N upper trapezoidal
267  matrix R (R is upper triangular if m >= n); the
268  elements below the diagonal, with the array TAU,
269  represent the orthogonal matrix Q as a product of
270  min(m,n) elementary reflectors.
271  */
272  &lda, // The leading dimension of the array A. LDA >= max(1,M).
273  tau, /*Dimension (min(M,N))
274  The scalar factors of the elementary reflectors
275  */
276  work, // Internal working array. dimension (MAX(1,LWORK))
277  &dimWork, // The dimension of the array WORK. LWORK >= max(1,N).
278  &info // status
279  );
280 
281  if (info != 0) {
282  std::cout << "dgeqrf_:" << -info << "th element had an illegal value" << std::endl;
284  }
285 
286  // A now contains the R matrix in its upper triangular (in lapack
287  // convention)
288  C = A;
289 
290  // 2) Invert R
291  dtrtri_((char *)"U", (char *)"N", &dimTau, C.data, &lda, &info);
292  if (info != 0) {
293  if (info < 0)
294  std::cout << "dtrtri_:" << -info << "th element had an illegal value" << std::endl;
295  else if (info > 0) {
296  std::cout << "dtrtri_:R(" << info << "," << info << ")"
297  << " is exactly zero. The triangular matrix is singular "
298  "and its inverse can not be computed."
299  << std::endl;
300  std::cout << "R=" << std::endl << C << std::endl;
301  }
303  }
304 
305  // 3) Zero-fill R^-1
306  // the matrix is upper triangular for lapack but lower triangular for visp
307  // we fill it with zeros above the diagonal (where we don't need the
308  // values)
309  for (unsigned int i = 0; i < C.getRows(); ++i)
310  for (unsigned int j = 0; j < C.getRows(); ++j)
311  if (j > i)
312  C[i][j] = 0.;
313 
314  dimWork = -1;
315  integer ldc = lda;
316 
317  // 4) Transpose Q and left-multiply it by R^-1
318  // get R^-1*tQ
319  // C contains R^-1
320  // A contains Q
321  dormqr_((char *)"R", (char *)"T", &rowNum_, &colNum_, &dimTau, A.data, &lda, tau, C.data, &ldc, work, &dimWork,
322  &info);
323  if (info != 0) {
324  std::cout << "dormqr_:Preparation" << -info << "th element had an illegal value" << std::endl;
326  }
327  dimWork = allocate_work(&work);
328 
329  dormqr_((char *)"R", (char *)"T", &rowNum_, &colNum_, &dimTau, A.data, &lda, tau, C.data, &ldc, work, &dimWork,
330  &info);
331 
332  if (info != 0) {
333  std::cout << "dormqr_:" << -info << "th element had an illegal value" << std::endl;
335  }
336  delete[] tau;
337  delete[] work;
338  }
339  catch (vpMatrixException &) {
340  delete[] tau;
341  delete[] work;
342  throw;
343  }
344 
345  return C;
346  }
347 #endif
348 }
349 #endif
350 
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 
444 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<unsigned int>(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<unsigned int>(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<unsigned int>(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<integer>(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<integer>(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  for (integer j = 0; j < n; ++j)
570  qrdata[i + m * j] = data[j + n * i];
571  for (integer j = n; j < na; ++j)
572  qrdata[i + m * j] = 0;
573  }
574 
575  // work = new double[1];
576  // 1) Extract householder reflections (useful to compute Q) and R
577  dgeqrf_(&m, // The number of rows of the matrix A. M >= 0.
578  &na, // The number of columns of the matrix A. N >= 0.
579  qrdata, &m, tau,
580  work, // Internal working array. dimension (MAX(1,LWORK))
581  &dimWork, // The dimension of the array WORK. LWORK >= max(1,N).
582  &info // status
583  );
584 
585  if (info != 0) {
586  std::cout << "dgeqrf_:Preparation:" << -info << "th element had an illegal value" << std::endl;
587  delete[] qrdata;
588  delete[] work;
589  delete[] tau;
591  }
592  dimWork = allocate_work(&work);
593 
594  dgeqrf_(&m, // The number of rows of the matrix A. M >= 0.
595  &na, // The number of columns of the matrix A. N >= 0.
596  qrdata,
597  &m, // The leading dimension of the array A. LDA >= max(1,M).
598  tau,
599  work, // Internal working array. dimension (MAX(1,LWORK))
600  &dimWork, // The dimension of the array WORK. LWORK >= max(1,N).
601  &info // status
602  );
603 
604  if (info != 0) {
605  std::cout << "dgeqrf_:" << -info << "th element had an illegal value" << std::endl;
606  delete[] qrdata;
607  delete[] work;
608  delete[] tau;
610  }
611 
612  // data now contains the R matrix in its upper triangular (in lapack convention)
613 
614  // copy useful part of R from Q and update rank
615  na = std::min<integer>(m, n);
616  if (squareR) {
617  for (int i = 0; i < na; ++i) {
618  for (int j = i; j < na; ++j)
619  R[i][j] = qrdata[i + m * j];
620  if (std::abs(qrdata[i + m * i]) < tol)
621  r--;
622  }
623  }
624  else {
625  for (int i = 0; i < na; ++i) {
626  for (int j = i; j < n; ++j)
627  R[i][j] = qrdata[i + m * j];
628  if (std::abs(qrdata[i + m * i]) < tol)
629  r--;
630  }
631  }
632 
633  // extract Q
634  dorgqr_(&m, // The number of rows of the matrix Q. M >= 0.
635  &q, // The number of columns of the matrix Q. M >= N >= 0.
636  &q, qrdata,
637  &m, // The leading dimension of the array A. LDA >= max(1,M).
638  tau,
639  work, // Internal working array. dimension (MAX(1,LWORK))
640  &dimWork, // The dimension of the array WORK. LWORK >= max(1,N).
641  &info // status
642  );
643 
644  // write qrdata into Q
645  for (int i = 0; i < m; ++i)
646  for (int j = 0; j < q; ++j)
647  Q[i][j] = qrdata[i + m * j];
648 
649  delete[] qrdata;
650  delete[] work;
651  delete[] tau;
652  return (unsigned int)r;
653 #endif // defined(VISP_HAVE_GSL)
654 #else
655  (void)Q;
656  (void)R;
657  (void)full;
658  (void)squareR;
659  (void)tol;
660  throw(vpException(vpException::fatalError, "Cannot perform QR decomposition. Install Lapack 3rd party"));
661 #endif
662 }
663 
726 unsigned int vpMatrix::qrPivot(vpMatrix &Q, vpMatrix &R, vpMatrix &P, bool full, bool squareR, double tol) const
727 {
728 #if defined(VISP_HAVE_LAPACK)
729 #if defined(VISP_HAVE_GSL)
730  unsigned int m = rowNum; // also rows of Q
731  unsigned int n = colNum; // also columns of R
732  unsigned int r = std::min<unsigned int>(n, m); // a priori non-null rows of R = rank of R
733  unsigned int q = r; // columns of Q and rows of R
734  unsigned int na = n; // columns of A
735 
736  // cannot be full decomposition if m < n
737  if (full && m > n) {
738  q = m; // Q is square
739  na = m; // A is square
740  }
741 
742  // prepare Q and deal with r = 0
743  Q.resize(m, q, false);
744  if (r == 0) {
745  if (squareR) {
746  R.resize(0, 0, false);
747  P.resize(0, n, false);
748  }
749  else {
750  R.resize(r, n, false);
751  P.resize(n, n);
752  }
753  return 0;
754  }
755 
756  gsl_matrix gsl_A, *gsl_Q, *gsl_R, gsl_Qfull;
757  gsl_vector *gsl_tau;
758  gsl_permutation *gsl_p;
759  gsl_vector *gsl_norm;
760  int gsl_signum;
761 
762  gsl_A.size1 = rowNum;
763  gsl_A.size2 = colNum;
764  gsl_A.tda = gsl_A.size2;
765  gsl_A.data = this->data;
766  gsl_A.owner = 0;
767  gsl_A.block = 0;
768 
769  gsl_R = gsl_matrix_alloc(rowNum, colNum); // M by N
770  gsl_tau = gsl_vector_alloc(std::min<unsigned int>(rowNum, colNum));
771  gsl_norm = gsl_vector_alloc(colNum);
772  gsl_p = gsl_permutation_alloc(n);
773 
774  if (full) {
775  // Q is M by M as expected by gsl_linalg_QR_unpack()
776  // for performance purpose dont allocate gsl_Q, but rather use gsl_Qfull = Q
777  gsl_Qfull.size1 = Q.rowNum;
778  gsl_Qfull.size2 = Q.colNum;
779  gsl_Qfull.tda = gsl_Qfull.size2;
780  gsl_Qfull.data = Q.data;
781  gsl_Qfull.owner = 0;
782  gsl_Qfull.block = 0;
783 
784  gsl_linalg_QRPT_decomp2(&gsl_A, &gsl_Qfull, gsl_R, gsl_tau, gsl_p, &gsl_signum, gsl_norm);
785  // std::cout << "gsl_Qfull:\n "; display_gsl(&gsl_Qfull);
786  // std::cout << "gsl_R:\n "; display_gsl(gsl_R);
787  }
788  else {
789  gsl_Q = gsl_matrix_alloc(rowNum, rowNum); // M by M
790 
791  gsl_linalg_QRPT_decomp2(&gsl_A, gsl_Q, gsl_R, gsl_tau, gsl_p, &gsl_signum, gsl_norm);
792  // std::cout << "gsl_Q:\n "; display_gsl(gsl_Q);
793  // std::cout << "gsl_R:\n "; display_gsl(gsl_R);
794 
795  unsigned int Qtda = static_cast<unsigned int>(gsl_Q->tda);
796  size_t len = sizeof(double) * Q.colNum;
797  for (unsigned int i = 0; i < Q.rowNum; ++i) {
798  unsigned int k = i * Qtda;
799  memcpy(Q[i], &gsl_Q->data[k], len);
800  // for(unsigned int j = 0; j < Q.colNum; ++j) {
801  // Q[i][j] = gsl_Q->data[k + j];
802  // }
803  }
804  gsl_matrix_free(gsl_Q);
805  }
806 
807  // update rank
808  na = std::min<unsigned int>(m, n);
809  unsigned int Rtda = static_cast<unsigned int>(gsl_R->tda);
810  for (unsigned int i = 0; i < na; ++i) {
811  unsigned int k = i * Rtda;
812  if (std::abs(gsl_R->data[k + i]) < tol)
813  r--;
814  }
815 
816  if (squareR) {
817  R.resize(r, r, false); // R r x r
818  P.resize(r, n);
819  for (unsigned int i = 0; i < r; ++i)
820  P[i][gsl_p->data[i]] = 1;
821  }
822  else {
823  R.resize(na, n, false); // R is min(m,n) x n of rank r
824  P.resize(n, n);
825  for (unsigned int i = 0; i < n; ++i)
826  P[i][gsl_p->data[i]] = 1;
827  }
828 
829  // copy useful part of R
830  size_t Rlen = sizeof(double) * R.colNum;
831  for (unsigned int i = 0; i < na; ++i) {
832  unsigned int k = i * Rtda;
833  memcpy(R[i], &gsl_R->data[k], Rlen);
834  }
835 
836  gsl_matrix_free(gsl_R);
837  gsl_vector_free(gsl_tau);
838  gsl_vector_free(gsl_norm);
839  gsl_permutation_free(gsl_p);
840 
841  return r;
842 #else
843  integer m = (integer)rowNum; // also rows of Q
844  integer n = (integer)colNum; // also columns of R
845  integer r = std::min<integer>(n, m); // a priori non-null rows of R = rank of R
846  integer q = r; // columns of Q and rows of R
847  integer na = n; // columns of A
848 
849  // cannot be full decomposition if m < n
850  // cannot be full decomposition if m < n
851  if (full && m > n) {
852  q = m; // Q is square
853  na = m; // A is square
854  }
855 
856  // prepare Q and deal with r = 0
857  Q.resize(static_cast<unsigned int>(m), static_cast<unsigned int>(q));
858  if (r == 0) {
859  if (squareR) {
860  R.resize(0, 0);
861  P.resize(0, static_cast<unsigned int>(n));
862  }
863  else {
864  R.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(n));
865  P.resize(static_cast<unsigned int>(n), static_cast<unsigned int>(n));
866  }
867  return 0;
868  }
869 
870  integer dimWork = -1;
871  integer min_q_m = std::min<integer>(q, m);
872  double *qrdata = new double[m * na];
873  double *tau = new double[min_q_m];
874  double *work = new double[1];
875  integer *p = new integer[na];
876  for (int i = 0; i < na; ++i)
877  p[i] = 0;
878 
879  integer info;
880 
881  // copy this to qrdata in Lapack convention
882  for (integer i = 0; i < m; ++i) {
883  for (integer j = 0; j < n; ++j)
884  qrdata[i + m * j] = data[j + n * i];
885  for (integer j = n; j < na; ++j)
886  qrdata[i + m * j] = 0;
887  }
888 
889  // 1) Extract householder reflections (useful to compute Q) and R
890  dgeqp3_(&m, // The number of rows of the matrix A. M >= 0.
891  &na, // The number of columns of the matrix A. N >= 0.
892  qrdata, /*On entry, the M-by-N matrix A. */
893  &m, // The leading dimension of the array A. LDA >= max(1,M).
894  p, // Dimension N
895  tau, /*Dimension (min(M,N)) */
896  work, // Internal working array. dimension (3*N)
897 
898  &dimWork,
899  &info // status
900  );
901 
902  if (info != 0) {
903  std::cout << "dgeqp3_:Preparation:" << -info << "th element had an illegal value" << std::endl;
904  delete[] qrdata;
905  delete[] work;
906  delete[] tau;
907  delete[] p;
909  }
910 
911  dimWork = allocate_work(&work);
912 
913  dgeqp3_(&m, // The number of rows of the matrix A. M >= 0.
914  &na, // The number of columns of the matrix A. N >= 0.
915  qrdata, /*On entry, the M-by-N matrix A. */
916  &m, // The leading dimension of the array A. LDA >= max(1,M).
917  p, // Dimension N
918  tau, /*Dimension (min(M,N)) */
919  work, // Internal working array. dimension (3*N)
920 
921  &dimWork,
922  &info // status
923  );
924 
925  if (info != 0) {
926  std::cout << "dgeqp3_:" << -info << " th element had an illegal value" << std::endl;
927  delete[] qrdata;
928  delete[] work;
929  delete[] tau;
930  delete[] p;
932  }
933 
934  // data now contains the R matrix in its upper triangular (in lapack convention)
935  // get rank of R in r
936  na = std::min<integer>(n, m);
937  for (int i = 0; i < na; ++i)
938  if (std::abs(qrdata[i + m * i]) < tol)
939  r--;
940 
941  // write R
942  if (squareR) // R r x r
943  {
944  R.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(r));
945  for (int i = 0; i < r; ++i)
946  for (int j = i; j < r; ++j)
947  R[i][j] = qrdata[i + m * j];
948 
949  // write P
950  P.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(n));
951  for (int i = 0; i < r; ++i)
952  P[i][p[i] - 1] = 1;
953  }
954  else // R is min(m,n) x n of rank r
955  {
956  R.resize(static_cast<unsigned int>(na), static_cast<unsigned int>(n));
957  for (int i = 0; i < na; ++i)
958  for (int j = i; j < n; ++j)
959  R[i][j] = qrdata[i + m * j];
960  // write P
961  P.resize(static_cast<unsigned int>(n), static_cast<unsigned int>(n));
962  for (int i = 0; i < n; ++i)
963  P[i][p[i] - 1] = 1;
964  }
965 
966  // extract Q
967  dorgqr_(&m, // The number of rows of the matrix Q. M >= 0.
968  &q, // The number of columns of the matrix Q. M >= N >= 0.
969  &q, qrdata,
970  &m, // The leading dimension of the array A. LDA >= max(1,M).
971  tau,
972  work, // Internal working array. dimension (MAX(1,LWORK))
973  &dimWork, // The dimension of the array WORK. LWORK >= max(1,N).
974  &info // status
975  );
976 
977  // write qrdata into Q
978  for (int i = 0; i < m; ++i)
979  for (int j = 0; j < q; ++j)
980  Q[i][j] = qrdata[i + m * j];
981 
982  delete[] qrdata;
983  delete[] work;
984  delete[] tau;
985  delete[] p;
986  return (unsigned int)r;
987 #endif
988 #else
989  (void)Q;
990  (void)R;
991  (void)P;
992  (void)full;
993  (void)squareR;
994  (void)tol;
995  throw(vpException(vpException::fatalError, "Cannot perform QR decomposition. Install Lapack 3rd party"));
996 #endif
997 }
998 
1011 {
1012  if ((rowNum != colNum) || (rowNum == 0)) {
1013  throw(vpException(vpException::dimensionError, "Cannot inverse a triangular matrix (%d, %d) that is not square",
1014  rowNum, colNum));
1015  }
1016 #if defined(VISP_HAVE_LAPACK)
1017 #if defined(VISP_HAVE_GSL)
1018  vpMatrix inv;
1019  inv.resize(colNum, rowNum, false);
1020  gsl_matrix gsl_inv;
1021 
1022  gsl_inv.size1 = inv.rowNum;
1023  gsl_inv.size2 = inv.colNum;
1024  gsl_inv.tda = gsl_inv.size2;
1025  gsl_inv.data = inv.data;
1026  gsl_inv.owner = 0;
1027  gsl_inv.block = 0;
1028 
1029  unsigned int tda = static_cast<unsigned int>(gsl_inv.tda);
1030  size_t len = sizeof(double) * inv.colNum;
1031  for (unsigned int i = 0; i < rowNum; ++i) {
1032  unsigned int k = i * tda;
1033  memcpy(&gsl_inv.data[k], (*this)[i], len);
1034  }
1035 
1036  if (upper) {
1037 #if (GSL_MAJOR_VERSION >= 2 && GSL_MINOR_VERSION >= 2)
1038  gsl_linalg_tri_upper_invert(&gsl_inv);
1039 #else
1040  {
1041  gsl_matrix_view m;
1042  gsl_vector_view v;
1043  for (unsigned int i = 0; i < rowNum; ++i) {
1044  double *Tii = gsl_matrix_ptr(&gsl_inv, i, i);
1045  *Tii = 1.0 / *Tii;
1046  double aii = -(*Tii);
1047  if (i > 0) {
1048  m = gsl_matrix_submatrix(&gsl_inv, 0, 0, i, i);
1049  v = gsl_matrix_subcolumn(&gsl_inv, i, 0, i);
1050  gsl_blas_dtrmv(CblasUpper, CblasNoTrans, CblasNonUnit, &m.matrix, &v.vector);
1051  gsl_blas_dscal(aii, &v.vector);
1052  }
1053  }
1054  }
1055 #endif
1056  }
1057  else {
1058 #if (GSL_MAJOR_VERSION >= 2 && GSL_MINOR_VERSION >= 2)
1059  gsl_linalg_tri_lower_invert(&gsl_inv);
1060 #else
1061  {
1062  gsl_matrix_view m;
1063  gsl_vector_view v;
1064  for (unsigned int i = 0; i < rowNum; ++i) {
1065  size_t j = rowNum - i - 1;
1066  double *Tjj = gsl_matrix_ptr(&gsl_inv, j, j);
1067  *Tjj = 1.0 / (*Tjj);
1068  double ajj = -(*Tjj);
1069  if (j < rowNum - 1) {
1070  m = gsl_matrix_submatrix(&gsl_inv, j + 1, j + 1, rowNum - j - 1, rowNum - j - 1);
1071  v = gsl_matrix_subcolumn(&gsl_inv, j, j + 1, rowNum - j - 1);
1072  gsl_blas_dtrmv(CblasLower, CblasNoTrans, CblasNonUnit, &m.matrix, &v.vector);
1073  gsl_blas_dscal(ajj, &v.vector);
1074  }
1075  }
1076  }
1077 #endif
1078  }
1079 
1080  return inv;
1081 #else
1082  integer n = (integer)rowNum; // lda is the number of rows because we don't use a submatrix
1083 
1084  vpMatrix R = *this;
1085  integer info;
1086 
1087  // we just use the other (upper / lower) method from Lapack
1088  if (rowNum > 1 && upper) // upper triangular
1089  dtrtri_((char *)"L", (char *)"N", &n, R.data, &n, &info);
1090  else
1091  dtrtri_((char *)"U", (char *)"N", &n, R.data, &n, &info);
1092 
1093  if (info != 0) {
1094  if (info < 0)
1095  std::cout << "dtrtri_:" << -info << "th element had an illegal value" << std::endl;
1096  else if (info > 0) {
1097  std::cout << "dtrtri_:R(" << info << "," << info << ")"
1098  << " is exactly zero. The triangular matrix is singular "
1099  "and its inverse can not be computed."
1100  << std::endl;
1102  }
1104  }
1105  return R;
1106 #endif
1107 #else
1108  (void)upper;
1109  throw(vpException(vpException::fatalError, "Cannot perform triangular inverse. Install Lapack 3rd party"));
1110 #endif
1111 }
1112 
1156 {
1157  vpMatrix Q, R, P;
1158  unsigned int r = t().qrPivot(Q, R, P, false, true);
1159  x = Q.extract(0, 0, colNum, r) * R.inverseTriangular().t() * P * b;
1160 }
1161 
1206 {
1207  vpColVector x(colNum);
1208  solveByQR(b, x);
1209  return x;
1210 }
unsigned int getCols() const
Definition: vpArray2D.h:327
Type * data
Address of the first element of the data array.
Definition: vpArray2D.h:139
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition: vpArray2D.h:352
unsigned int rowNum
Number of rows in the array.
Definition: vpArray2D.h:129
unsigned int getRows() const
Definition: vpArray2D.h:337
unsigned int colNum
Number of columns in the array.
Definition: vpArray2D.h:131
Implementation of column vector and the associated operations.
Definition: vpColVector.h:163
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ badValue
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:85
@ dimensionError
Bad dimension.
Definition: vpException.h:83
@ fatalError
Fatal error.
Definition: vpException.h:84
error that can be emitted by the vpMatrix class and its derivatives
@ rankDeficient
Rank deficient.
@ matrixError
Matrix operation error.
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:146
unsigned int qr(vpMatrix &Q, vpMatrix &R, bool full=false, bool squareR=false, double tol=1e-6) const
vpMatrix inverseTriangular(bool upper=true) const
unsigned int qrPivot(vpMatrix &Q, vpMatrix &R, vpMatrix &P, bool full=false, bool squareR=false, double tol=1e-6) const
vpMatrix t() const
Definition: vpMatrix.cpp:465
void solveByQR(const vpColVector &b, vpColVector &x) const
vpMatrix inverseByQR() const
vpMatrix inverseByQRLapack() const
vpMatrix extract(unsigned int r, unsigned int c, unsigned int nrows, unsigned int ncols) const
Definition: vpMatrix.cpp:404