Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
vpMatrix_qr.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  * Matrix QR decomposition.
32  */
33 
34 #include <algorithm> // for (std::min) and (std::max)
35 #include <cmath> // For std::abs() on iOS
36 #include <cstdlib> // For std::abs() on iOS
37 #include <visp3/core/vpConfig.h>
38 
39 #include <visp3/core/vpColVector.h>
40 #include <visp3/core/vpMath.h>
41 #include <visp3/core/vpMatrix.h>
42 
43 // Exception
44 #include <visp3/core/vpException.h>
45 #include <visp3/core/vpMatrixException.h>
46 
47 BEGIN_VISP_NAMESPACE
48 #ifdef VISP_HAVE_LAPACK
49 #ifdef VISP_HAVE_GSL
50 #if !(GSL_MAJOR_VERSION >= 2 && GSL_MINOR_VERSION >= 2)
51 // Needed for GSL_VERSION < 2.2 where gsl_linalg_tri_*_invert() not present
52 #include <gsl/gsl_blas.h>
53 #include <gsl/gsl_math.h>
54 #include <gsl/gsl_matrix.h>
55 #include <gsl/gsl_vector.h>
56 #endif
57 #include <gsl/gsl_linalg.h>
58 #include <gsl/gsl_permutation.h>
59 #endif
60 #ifdef VISP_HAVE_MKL
61 #include <mkl.h>
62 typedef MKL_INT integer;
63 
64 integer allocate_work(double **work)
65 {
66  integer dimWork = (integer)((*work)[0]);
67  delete[] * work;
68  *work = new double[dimWork];
69  return (integer)dimWork;
70 }
71 #elif !defined(VISP_HAVE_GSL)
72 #ifdef VISP_HAVE_LAPACK_BUILT_IN
73 typedef long int integer;
74 #else
75 typedef int integer;
76 #endif
77 extern "C" int dgeqrf_(integer *m, integer *n, double *a, integer *lda, double *tau, double *work, integer *lwork,
78  integer *info);
79 extern "C" int dormqr_(char *side, char *trans, integer *m, integer *n, integer *k, double *a, integer *lda,
80  double *tau, double *c__, integer *ldc, double *work, integer *lwork, integer *info);
81 extern "C" int dorgqr_(integer *, integer *, integer *, double *, integer *, double *, double *, integer *, integer *);
82 extern "C" int dtrtri_(char *uplo, char *diag, integer *n, double *a, integer *lda, integer *info);
83 extern "C" int dgeqp3_(integer *m, integer *n, double *a, integer *lda, integer *p, double *tau, double *work,
84  integer *lwork, integer *info);
85 
86 int allocate_work(double **work);
87 
88 int allocate_work(double **work)
89 {
90  unsigned int dimWork = (unsigned int)((*work)[0]);
91  delete[] * work;
92  *work = new double[dimWork];
93  return (int)dimWork;
94 }
95 #endif
96 #endif
97 
98 #if defined(VISP_HAVE_GSL)
99 #ifndef DOXYGEN_SHOULD_SKIP_THIS
100 void display_gsl(gsl_matrix *M)
101 {
102  // display
103  for (unsigned int i = 0; i < M->size1; ++i) {
104  unsigned int k = i * M->tda;
105  for (unsigned int j = 0; j < M->size2; ++j) {
106  std::cout << M->data[k + j] << " ";
107  }
108  std::cout << std::endl;
109  }
110 }
111 #endif
112 #endif
113 
114 #if defined(VISP_HAVE_LAPACK)
149 {
150 #if defined(VISP_HAVE_GSL)
151  {
152  vpMatrix inv;
153  inv.resize(colNum, rowNum, false);
154  gsl_matrix *gsl_A, *gsl_Q, *gsl_R, gsl_inv;
155  gsl_vector *gsl_tau;
156 
157  gsl_A = gsl_matrix_alloc(rowNum, colNum);
158  gsl_Q = gsl_matrix_alloc(rowNum, rowNum); // M by M
159  gsl_R = gsl_matrix_alloc(rowNum, colNum); // M by N
160  gsl_tau = gsl_vector_alloc(std::min<unsigned int>(rowNum, colNum));
161 
162  gsl_inv.size1 = inv.rowNum;
163  gsl_inv.size2 = inv.colNum;
164  gsl_inv.tda = gsl_inv.size2;
165  gsl_inv.data = inv.data;
166  gsl_inv.owner = 0;
167  gsl_inv.block = 0;
168 
169  // copy input matrix since gsl_linalg_QR_decomp() is destructive
170  unsigned int Atda = static_cast<unsigned int>(gsl_A->tda);
171  size_t len = sizeof(double) * colNum;
172  for (unsigned int i = 0; i < rowNum; ++i) {
173  unsigned int k = i * Atda;
174  memcpy(&gsl_A->data[k], (*this)[i], len);
175  }
176  gsl_linalg_QR_decomp(gsl_A, gsl_tau);
177  gsl_linalg_QR_unpack(gsl_A, gsl_tau, gsl_Q, gsl_R);
178 #if (GSL_MAJOR_VERSION >= 2 && GSL_MINOR_VERSION >= 2)
179  gsl_linalg_tri_upper_invert(gsl_R);
180 #else
181  {
182  gsl_matrix_view m;
183  gsl_vector_view v;
184  for (unsigned int i = 0; i < rowNum; ++i) {
185  double *Tii = gsl_matrix_ptr(gsl_R, i, i);
186  *Tii = 1.0 / (*Tii);
187  double aii = -(*Tii);
188  if (i > 0) {
189  m = gsl_matrix_submatrix(gsl_R, 0, 0, i, i);
190  v = gsl_matrix_subcolumn(gsl_R, i, 0, i);
191  gsl_blas_dtrmv(CblasUpper, CblasNoTrans, CblasNonUnit, &m.matrix, &v.vector);
192  gsl_blas_dscal(aii, &v.vector);
193  }
194  }
195  }
196 #endif
197  gsl_matrix_transpose(gsl_Q);
198 
199  gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, gsl_R, gsl_Q, 0, &gsl_inv);
200  unsigned int gsl_inv_tda = static_cast<unsigned int>(gsl_inv.tda);
201  size_t inv_len = sizeof(double) * inv.colNum;
202  for (unsigned int i = 0; i < inv.rowNum; ++i) {
203  unsigned int k = i * gsl_inv_tda;
204  memcpy(inv[i], &gsl_inv.data[k], inv_len);
205  }
206 
207  gsl_matrix_free(gsl_A);
208  gsl_matrix_free(gsl_Q);
209  gsl_matrix_free(gsl_R);
210  gsl_vector_free(gsl_tau);
211 
212  return inv;
213  }
214 #else
215  {
216  if (rowNum != colNum) {
217  throw(vpMatrixException(vpMatrixException::matrixError, "Cannot inverse a non-square matrix (%ux%u) by QR",
218  rowNum, colNum));
219  }
220 
221  integer rowNum_ = (integer)this->getRows();
222  integer colNum_ = (integer)this->getCols();
223  integer lda = (integer)rowNum_; // lda is the number of rows because we don't use a submatrix
224  integer dimTau = std::min<integer>(rowNum_, colNum_);
225  integer dimWork = -1;
226  double *tau = new double[dimTau];
227  double *work = new double[1];
228  integer info;
229  vpMatrix C;
230  vpMatrix A = *this;
231 
232  try {
233  // 1) Extract householder reflections (useful to compute Q) and R
234  dgeqrf_(&rowNum_, // The number of rows of the matrix A. M >= 0.
235  &colNum_, // The number of columns of the matrix A. N >= 0.
236  A.data, /*On entry, the M-by-N matrix A.
237  On exit, the elements on and above the diagonal of
238  the array contain the min(M,N)-by-N upper trapezoidal
239  matrix R (R is upper triangular if m >= n); the
240  elements below the diagonal, with the array TAU,
241  represent the orthogonal matrix Q as a product of
242  min(m,n) elementary reflectors.
243  */
244  &lda, // The leading dimension of the array A. LDA >= max(1,M).
245  tau, /*Dimension (min(M,N))
246  The scalar factors of the elementary reflectors
247  */
248  work, // Internal working array. dimension (MAX(1,LWORK))
249  &dimWork, // The dimension of the array WORK. LWORK >= max(1,N).
250  &info // status
251  );
252 
253  if (info != 0) {
254  std::cout << "dgeqrf_:Preparation:" << -info << "th element had an illegal value" << std::endl;
256  }
257  dimWork = allocate_work(&work);
258 
259  dgeqrf_(&rowNum_, // The number of rows of the matrix A. M >= 0.
260  &colNum_, // The number of columns of the matrix A. N >= 0.
261  A.data, /*On entry, the M-by-N matrix A.
262  On exit, the elements on and above the diagonal of
263  the array contain the min(M,N)-by-N upper trapezoidal
264  matrix R (R is upper triangular if m >= n); the
265  elements below the diagonal, with the array TAU,
266  represent the orthogonal matrix Q as a product of
267  min(m,n) elementary reflectors.
268  */
269  &lda, // The leading dimension of the array A. LDA >= max(1,M).
270  tau, /*Dimension (min(M,N))
271  The scalar factors of the elementary reflectors
272  */
273  work, // Internal working array. dimension (MAX(1,LWORK))
274  &dimWork, // The dimension of the array WORK. LWORK >= max(1,N).
275  &info // status
276  );
277 
278  if (info != 0) {
279  std::cout << "dgeqrf_:" << -info << "th element had an illegal value" << std::endl;
281  }
282 
283  // A now contains the R matrix in its upper triangular (in lapack
284  // convention)
285  C = A;
286 
287  // 2) Invert R
288  dtrtri_((char *)"U", (char *)"N", &dimTau, C.data, &lda, &info);
289  if (info != 0) {
290  if (info < 0)
291  std::cout << "dtrtri_:" << -info << "th element had an illegal value" << std::endl;
292  else if (info > 0) {
293  std::cout << "dtrtri_:R(" << info << "," << info << ")"
294  << " is exactly zero. The triangular matrix is singular "
295  "and its inverse can not be computed."
296  << std::endl;
297  std::cout << "R=" << std::endl << C << std::endl;
298  }
300  }
301 
302  // 3) Zero-fill R^-1
303  // the matrix is upper triangular for lapack but lower triangular for visp
304  // we fill it with zeros above the diagonal (where we don't need the
305  // values)
306  for (unsigned int i = 0; i < C.getRows(); ++i)
307  for (unsigned int j = 0; j < C.getRows(); ++j)
308  if (j > i)
309  C[i][j] = 0.;
310 
311  dimWork = -1;
312  integer ldc = lda;
313 
314  // 4) Transpose Q and left-multiply it by R^-1
315  // get R^-1*tQ
316  // C contains R^-1
317  // A contains Q
318  dormqr_((char *)"R", (char *)"T", &rowNum_, &colNum_, &dimTau, A.data, &lda, tau, C.data, &ldc, work, &dimWork,
319  &info);
320  if (info != 0) {
321  std::cout << "dormqr_:Preparation" << -info << "th element had an illegal value" << std::endl;
323  }
324  dimWork = allocate_work(&work);
325 
326  dormqr_((char *)"R", (char *)"T", &rowNum_, &colNum_, &dimTau, A.data, &lda, tau, C.data, &ldc, work, &dimWork,
327  &info);
328 
329  if (info != 0) {
330  std::cout << "dormqr_:" << -info << "th element had an illegal value" << std::endl;
332  }
333  delete[] tau;
334  delete[] work;
335  }
336  catch (vpMatrixException &) {
337  delete[] tau;
338  delete[] work;
339  throw;
340  }
341 
342  return C;
343  }
344 #endif
345 }
346 #endif
347 
383 {
384 #if defined(VISP_HAVE_LAPACK)
385  return inverseByQRLapack();
386 #else
387  throw(vpException(vpException::fatalError, "Cannot inverse matrix by QR. Install Lapack 3rd party"));
388 #endif
389 }
390 
449 unsigned int vpMatrix::qr(vpMatrix &Q, vpMatrix &R, bool full, bool squareR, double tol) const
450 {
451 #if defined(VISP_HAVE_LAPACK)
452 #if defined(VISP_HAVE_GSL)
453  unsigned int m = rowNum; // also rows of Q
454  unsigned int n = colNum; // also columns of R
455  unsigned int r = std::min<unsigned int>(n, m); // a priori non-null rows of R = rank of R
456  unsigned int q = r; // columns of Q and rows of R
457  unsigned int na = n; // columns of A
458 
459  // cannot be full decomposition if m < n
460  if (full && m > n) {
461  q = m; // Q is square
462  na = m; // A is square
463  }
464 
465  // prepare matrices and deal with r = 0
466  Q.resize(m, q, false);
467  if (squareR)
468  R.resize(r, r, false);
469  else
470  R.resize(r, n, false);
471  if (r == 0)
472  return 0;
473 
474  gsl_matrix *gsl_A, *gsl_Q, *gsl_R, gsl_Qfull;
475  gsl_vector *gsl_tau;
476 
477  gsl_A = gsl_matrix_alloc(rowNum, colNum);
478  gsl_R = gsl_matrix_alloc(rowNum, colNum); // M by N
479  gsl_tau = gsl_vector_alloc(std::min<unsigned int>(rowNum, colNum));
480 
481  // copy input matrix since gsl_linalg_QR_decomp() is destructive
482  unsigned int Atda = static_cast<unsigned int>(gsl_A->tda);
483  size_t len = sizeof(double) * colNum;
484  for (unsigned int i = 0; i < rowNum; ++i) {
485  unsigned int k = i * Atda;
486  memcpy(&gsl_A->data[k], (*this)[i], len);
487  // for (unsigned int j = 0; j < colNum; ++j)
488  // gsl_A->data[k + j] = (*this)[i][j];
489  }
490 
491  gsl_linalg_QR_decomp(gsl_A, gsl_tau);
492 
493  if (full) {
494  // Q is M by M as expected by gsl_linalg_QR_unpack()
495  // for performance purpose dont allocate gsl_Q, but rather use gsl_Qfull = Q
496  gsl_Qfull.size1 = Q.rowNum;
497  gsl_Qfull.size2 = Q.colNum;
498  gsl_Qfull.tda = gsl_Qfull.size2;
499  gsl_Qfull.data = Q.data;
500  gsl_Qfull.owner = 0;
501  gsl_Qfull.block = 0;
502 
503  gsl_linalg_QR_unpack(gsl_A, gsl_tau, &gsl_Qfull, gsl_R);
504  // std::cout << "gsl_Qfull:\n "; display_gsl(&gsl_Qfull);
505  // std::cout << "gsl_R:\n "; display_gsl(gsl_R);
506  }
507  else {
508  gsl_Q = gsl_matrix_alloc(rowNum, rowNum); // M by M
509 
510  gsl_linalg_QR_unpack(gsl_A, gsl_tau, gsl_Q, gsl_R);
511  // std::cout << "gsl_Q:\n "; display_gsl(gsl_Q);
512  // std::cout << "gsl_R:\n "; display_gsl(gsl_R);
513 
514  unsigned int Qtda = static_cast<unsigned int>(gsl_Q->tda);
515  size_t len = sizeof(double) * Q.colNum;
516  for (unsigned int i = 0; i < Q.rowNum; ++i) {
517  unsigned int k = i * Qtda;
518  memcpy(Q[i], &gsl_Q->data[k], len);
519  // for(unsigned int j = 0; j < Q.colNum; ++j) {
520  // Q[i][j] = gsl_Q->data[k + j];
521  // }
522  }
523  gsl_matrix_free(gsl_Q);
524  }
525 
526  // copy useful part of R and update rank
527  na = std::min<unsigned int>(m, n);
528  unsigned int Rtda = static_cast<unsigned int>(gsl_R->tda);
529  size_t Rlen = sizeof(double) * R.colNum;
530  for (unsigned int i = 0; i < na; ++i) {
531  unsigned int k = i * Rtda;
532  memcpy(R[i], &gsl_R->data[k], Rlen);
533  // for(unsigned int j = i; j < na; ++j)
534  // R[i][j] = gsl_R->data[k + j];
535  if (std::abs(gsl_R->data[k + i]) < tol)
536  r--;
537  }
538 
539  gsl_matrix_free(gsl_A);
540  gsl_matrix_free(gsl_R);
541  gsl_vector_free(gsl_tau);
542 
543  return r;
544 #else
545  integer m = (integer)rowNum; // also rows of Q
546  integer n = (integer)colNum; // also columns of R
547  integer r = std::min<integer>(n, m); // a priori non-null rows of R = rank of R
548  integer q = r; // columns of Q and rows of R
549  integer na = n; // columns of A
550 
551  // cannot be full decomposition if m < n
552  if (full && m > n) {
553  q = m; // Q is square
554  na = m; // A is square
555  }
556 
557  // prepare matrices and deal with r = 0
558  Q.resize(static_cast<unsigned int>(m), static_cast<unsigned int>(q));
559  if (squareR)
560  R.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(r));
561  else
562  R.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(n));
563  if (r == 0)
564  return 0;
565 
566  integer dimWork = -1;
567  double *qrdata = new double[m * na];
568  double *tau = new double[std::min<integer>(m, q)];
569  double *work = new double[1];
570  integer info;
571 
572  // copy this to qrdata in Lapack convention
573  for (integer i = 0; i < m; ++i) {
574  for (integer j = 0; j < n; ++j)
575  qrdata[i + m * j] = data[j + n * i];
576  for (integer j = n; j < na; ++j)
577  qrdata[i + m * j] = 0;
578  }
579 
580  // work = new double[1];
581  // 1) Extract householder reflections (useful to compute Q) and R
582  dgeqrf_(&m, // The number of rows of the matrix A. M >= 0.
583  &na, // The number of columns of the matrix A. N >= 0.
584  qrdata, &m, tau,
585  work, // Internal working array. dimension (MAX(1,LWORK))
586  &dimWork, // The dimension of the array WORK. LWORK >= max(1,N).
587  &info // status
588  );
589 
590  if (info != 0) {
591  std::cout << "dgeqrf_:Preparation:" << -info << "th element had an illegal value" << std::endl;
592  delete[] qrdata;
593  delete[] work;
594  delete[] tau;
596  }
597  dimWork = allocate_work(&work);
598 
599  dgeqrf_(&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;
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<integer>(m, n);
621  if (squareR) {
622  for (int i = 0; i < na; ++i) {
623  for (int j = i; j < na; ++j)
624  R[i][j] = qrdata[i + m * j];
625  if (std::abs(qrdata[i + m * i]) < tol)
626  r--;
627  }
628  }
629  else {
630  for (int i = 0; i < na; ++i) {
631  for (int j = i; j < n; ++j)
632  R[i][j] = qrdata[i + m * j];
633  if (std::abs(qrdata[i + m * i]) < tol)
634  r--;
635  }
636  }
637 
638  // extract Q
639  dorgqr_(&m, // The number of rows of the matrix Q. M >= 0.
640  &q, // The number of columns of the matrix Q. M >= N >= 0.
641  &q, qrdata,
642  &m, // The leading dimension of the array A. LDA >= max(1,M).
643  tau,
644  work, // Internal working array. dimension (MAX(1,LWORK))
645  &dimWork, // The dimension of the array WORK. LWORK >= max(1,N).
646  &info // status
647  );
648 
649  // write qrdata into Q
650  for (int i = 0; i < m; ++i)
651  for (int j = 0; j < q; ++j)
652  Q[i][j] = qrdata[i + m * j];
653 
654  delete[] qrdata;
655  delete[] work;
656  delete[] tau;
657  return (unsigned int)r;
658 #endif // defined(VISP_HAVE_GSL)
659 #else
660  (void)Q;
661  (void)R;
662  (void)full;
663  (void)squareR;
664  (void)tol;
665  throw(vpException(vpException::fatalError, "Cannot perform QR decomposition. Install Lapack 3rd party"));
666 #endif
667 }
668 
669 #if defined(VISP_HAVE_LAPACK)
670 #if !defined(VISP_HAVE_GSL)
736 unsigned int vpMatrix::qrPivotLapack(vpMatrix &Q, vpMatrix &R, vpMatrix &P, bool full, bool squareR, double tol) const
737 {
738  integer m = static_cast<integer>(rowNum); // also rows of Q
739  integer n = static_cast<integer>(colNum); // also columns of R
740  integer r = std::min<integer>(n, m); // a priori non-null rows of R = rank of R
741  integer q = r; // columns of Q and rows of R
742  integer na = n; // columns of A
743 
744  // cannot be full decomposition if m < n
745  // cannot be full decomposition if m < n
746  if (full && m > n) {
747  q = m; // Q is square
748  na = m; // A is square
749  }
750 
751  // prepare Q and deal with r = 0
752  Q.resize(static_cast<unsigned int>(m), static_cast<unsigned int>(q));
753  if (r == 0) {
754  if (squareR) {
755  R.resize(0, 0);
756  P.resize(0, static_cast<unsigned int>(n));
757  }
758  else {
759  R.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(n));
760  P.resize(static_cast<unsigned int>(n), static_cast<unsigned int>(n));
761  }
762  return 0;
763  }
764 
765  integer dimWork = -1;
766  integer min_q_m = std::min<integer>(q, m);
767  double *qrdata = new double[m * na];
768  double *tau = new double[min_q_m];
769  double *work = new double[1];
770  integer *p = new integer[na];
771  for (int i = 0; i < na; ++i) {
772  p[i] = 0;
773  }
774 
775  integer info;
776 
777  // copy this to qrdata in Lapack convention
778  for (integer i = 0; i < m; ++i) {
779  for (integer j = 0; j < n; ++j) {
780  qrdata[i + m * j] = data[j + n * i];
781  }
782  for (integer j = n; j < na; ++j) {
783  qrdata[i + m * j] = 0;
784  }
785  }
786 
787  // 1) Extract householder reflections (useful to compute Q) and R
788  // m: The number of rows of the matrix A. M >= 0.
789  // na: The number of columns of the matrix A. N >= 0.
790  // qrdata: On entry, the M-by-N matrix A.
791  // m: The leading dimension of the array A. LDA >= max(1,M).
792  // p: Dimension N
793  // tau: dimension (min(M,N))
794  // work: Internal working array. dimension (3*N)
795  // info: status
796  dgeqp3_(&m, &na, qrdata, &m, p, tau, work, &dimWork, &info);
797 
798  if (info != 0) {
799  std::cout << "dgeqp3_:Preparation:" << -info << "th element had an illegal value" << std::endl;
800  delete[] qrdata;
801  delete[] work;
802  delete[] tau;
803  delete[] p;
805  }
806 
807  dimWork = allocate_work(&work);
808 
809  // m: The number of rows of the matrix A. M >= 0.
810  // na: The number of columns of the matrix A. N >= 0.
811  // qrdata: On entry, the M-by-N matrix A.
812  // m: The leading dimension of the array A. LDA >= max(1,M).
813  // p: Dimension N
814  // tau: Dimension (min(M,N))
815  // work: Internal working array. dimension (3*N)
816  // info: status
817  dgeqp3_(&m, &na, qrdata, &m, p, tau, work, &dimWork, &info);
818 
819  if (info != 0) {
820  std::cout << "dgeqp3_:" << -info << " th element had an illegal value" << std::endl;
821  delete[] qrdata;
822  delete[] work;
823  delete[] tau;
824  delete[] p;
826  }
827 
828  // data now contains the R matrix in its upper triangular (in lapack convention)
829  // get rank of R in r
830  na = std::min<integer>(n, m);
831  for (int i = 0; i < na; ++i) {
832  if (std::abs(qrdata[i + m * i]) < tol) {
833  --r;
834  }
835  }
836 
837  // write R
838  if (squareR) // R r x r
839  {
840  R.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(r));
841  for (int i = 0; i < r; ++i) {
842  for (int j = i; j < r; ++j) {
843  R[i][j] = qrdata[i + m * j];
844  }
845  }
846 
847  // write P
848  P.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(n));
849  for (int i = 0; i < r; ++i) {
850  P[i][p[i] - 1] = 1;
851  }
852  }
853  else // R is min(m,n) x n of rank r
854  {
855  R.resize(static_cast<unsigned int>(na), static_cast<unsigned int>(n));
856  for (int i = 0; i < na; ++i) {
857  for (int j = i; j < n; ++j) {
858  R[i][j] = qrdata[i + m * j];
859  }
860  }
861  // write P
862  P.resize(static_cast<unsigned int>(n), static_cast<unsigned int>(n));
863  for (int i = 0; i < n; ++i) {
864  P[i][p[i] - 1] = 1;
865  }
866  }
867 
868  // extract Q
869  // m: The number of rows of the matrix Q. M >= 0.
870  // q: The number of columns of the matrix Q. M >= N >= 0.
871  // m: The leading dimension of the array A. LDA >= max(1,M).
872  // ork: Internal working array. dimension (MAX(1,LWORK))
873  // dimWork: The dimension of the array WORK. LWORK >= max(1,N).
874  // info; status
875  dorgqr_(&m, &q, &q, qrdata, &m, tau, work, &dimWork, &info);
876 
877  // write qrdata into Q
878  for (int i = 0; i < m; ++i) {
879  for (int j = 0; j < q; ++j) {
880  Q[i][j] = qrdata[i + m * j];
881  }
882  }
883 
884  delete[] qrdata;
885  delete[] work;
886  delete[] tau;
887  delete[] p;
888  return static_cast<unsigned int>(r);
889 }
890 #endif // VISP_HAVE_GSL
891 
892 #ifdef VISP_HAVE_GSL
958 unsigned int vpMatrix::qrPivotLapackGSL(vpMatrix &Q, vpMatrix &R, vpMatrix &P, bool full, bool squareR, double tol) const
959 {
960  unsigned int m = rowNum; // also rows of Q
961  unsigned int n = colNum; // also columns of R
962  unsigned int r = std::min<unsigned int>(n, m); // a priori non-null rows of R = rank of R
963  unsigned int q = r; // columns of Q and rows of R
964  unsigned int na = n; // columns of A
965 
966  // cannot be full decomposition if m < n
967  if (full && m > n) {
968  q = m; // Q is square
969  na = m; // A is square
970  }
971 
972  // prepare Q and deal with r = 0
973  Q.resize(m, q, false);
974  if (r == 0) {
975  if (squareR) {
976  R.resize(0, 0, false);
977  P.resize(0, n, false);
978  }
979  else {
980  R.resize(r, n, false);
981  P.resize(n, n);
982  }
983  return 0;
984  }
985 
986  gsl_matrix gsl_A, *gsl_Q, *gsl_R, gsl_Qfull;
987  gsl_vector *gsl_tau;
988  gsl_permutation *gsl_p;
989  gsl_vector *gsl_norm;
990  int gsl_signum;
991 
992  gsl_A.size1 = rowNum;
993  gsl_A.size2 = colNum;
994  gsl_A.tda = gsl_A.size2;
995  gsl_A.data = this->data;
996  gsl_A.owner = 0;
997  gsl_A.block = 0;
998 
999  gsl_R = gsl_matrix_alloc(rowNum, colNum); // M by N
1000  gsl_tau = gsl_vector_alloc(std::min<unsigned int>(rowNum, colNum));
1001  gsl_norm = gsl_vector_alloc(colNum);
1002  gsl_p = gsl_permutation_alloc(n);
1003 
1004  if (full) {
1005  // Q is M by M as expected by gsl_linalg_QR_unpack()
1006  // for performance purpose dont allocate gsl_Q, but rather use gsl_Qfull = Q
1007  gsl_Qfull.size1 = Q.rowNum;
1008  gsl_Qfull.size2 = Q.colNum;
1009  gsl_Qfull.tda = gsl_Qfull.size2;
1010  gsl_Qfull.data = Q.data;
1011  gsl_Qfull.owner = 0;
1012  gsl_Qfull.block = 0;
1013 
1014  gsl_linalg_QRPT_decomp2(&gsl_A, &gsl_Qfull, gsl_R, gsl_tau, gsl_p, &gsl_signum, gsl_norm);
1015  // std::cout << "gsl_Qfull:\n "; display_gsl(&gsl_Qfull);
1016  // std::cout << "gsl_R:\n "; display_gsl(gsl_R);
1017  }
1018  else {
1019  gsl_Q = gsl_matrix_alloc(rowNum, rowNum); // M by M
1020 
1021  gsl_linalg_QRPT_decomp2(&gsl_A, gsl_Q, gsl_R, gsl_tau, gsl_p, &gsl_signum, gsl_norm);
1022  // std::cout << "gsl_Q:\n "; display_gsl(gsl_Q);
1023  // std::cout << "gsl_R:\n "; display_gsl(gsl_R);
1024 
1025  unsigned int Qtda = static_cast<unsigned int>(gsl_Q->tda);
1026  size_t len = sizeof(double) * Q.colNum;
1027  for (unsigned int i = 0; i < Q.rowNum; ++i) {
1028  unsigned int k = i * Qtda;
1029  memcpy(Q[i], &gsl_Q->data[k], len);
1030  // for(unsigned int j = 0; j < Q.colNum; ++j) {
1031  // Q[i][j] = gsl_Q->data[k + j];
1032  // }
1033  }
1034  gsl_matrix_free(gsl_Q);
1035  }
1036 
1037  // update rank
1038  na = std::min<unsigned int>(m, n);
1039  unsigned int Rtda = static_cast<unsigned int>(gsl_R->tda);
1040  for (unsigned int i = 0; i < na; ++i) {
1041  unsigned int k = i * Rtda;
1042  if (std::abs(gsl_R->data[k + i]) < tol)
1043  r--;
1044  }
1045 
1046  if (squareR) {
1047  R.resize(r, r, false); // R r x r
1048  P.resize(r, n);
1049  for (unsigned int i = 0; i < r; ++i)
1050  P[i][gsl_p->data[i]] = 1;
1051  }
1052  else {
1053  R.resize(na, n, false); // R is min(m,n) x n of rank r
1054  P.resize(n, n);
1055  for (unsigned int i = 0; i < n; ++i)
1056  P[i][gsl_p->data[i]] = 1;
1057  }
1058 
1059  // copy useful part of R
1060  size_t Rlen = sizeof(double) * R.colNum;
1061  for (unsigned int i = 0; i < na; ++i) {
1062  unsigned int k = i * Rtda;
1063  memcpy(R[i], &gsl_R->data[k], Rlen);
1064  }
1065 
1066  gsl_matrix_free(gsl_R);
1067  gsl_vector_free(gsl_tau);
1068  gsl_vector_free(gsl_norm);
1069  gsl_permutation_free(gsl_p);
1070 
1071  return r;
1072 }
1073 #endif
1074 #endif
1075 
1142 unsigned int vpMatrix::qrPivot(vpMatrix &Q, vpMatrix &R, vpMatrix &P, bool full, bool squareR, double tol) const
1143 {
1144 #if defined(VISP_HAVE_LAPACK)
1145 #if defined(VISP_HAVE_GSL)
1146  return qrPivotLapackGSL(Q, R, P, full, squareR, tol);
1147 #else
1148  return qrPivotLapack(Q, R, P, full, squareR, tol);
1149 #endif
1150 #else
1151  (void)Q;
1152  (void)R;
1153  (void)P;
1154  (void)full;
1155  (void)squareR;
1156  (void)tol;
1157  throw(vpException(vpException::fatalError, "Cannot perform QR decomposition. Install Lapack 3rd party"));
1158 #endif
1159 }
1160 
1173 {
1174  if ((rowNum != colNum) || (rowNum == 0)) {
1175  throw(vpException(vpException::dimensionError, "Cannot inverse a triangular matrix (%d, %d) that is not square",
1176  rowNum, colNum));
1177  }
1178 #if defined(VISP_HAVE_LAPACK)
1179 #if defined(VISP_HAVE_GSL)
1180  vpMatrix inv;
1181  inv.resize(colNum, rowNum, false);
1182  gsl_matrix gsl_inv;
1183 
1184  gsl_inv.size1 = inv.rowNum;
1185  gsl_inv.size2 = inv.colNum;
1186  gsl_inv.tda = gsl_inv.size2;
1187  gsl_inv.data = inv.data;
1188  gsl_inv.owner = 0;
1189  gsl_inv.block = 0;
1190 
1191  unsigned int tda = static_cast<unsigned int>(gsl_inv.tda);
1192  size_t len = sizeof(double) * inv.colNum;
1193  for (unsigned int i = 0; i < rowNum; ++i) {
1194  unsigned int k = i * tda;
1195  memcpy(&gsl_inv.data[k], (*this)[i], len);
1196  }
1197 
1198  if (upper) {
1199 #if (GSL_MAJOR_VERSION >= 2 && GSL_MINOR_VERSION >= 2)
1200  gsl_linalg_tri_upper_invert(&gsl_inv);
1201 #else
1202  {
1203  gsl_matrix_view m;
1204  gsl_vector_view v;
1205  for (unsigned int i = 0; i < rowNum; ++i) {
1206  double *Tii = gsl_matrix_ptr(&gsl_inv, i, i);
1207  *Tii = 1.0 / *Tii;
1208  double aii = -(*Tii);
1209  if (i > 0) {
1210  m = gsl_matrix_submatrix(&gsl_inv, 0, 0, i, i);
1211  v = gsl_matrix_subcolumn(&gsl_inv, i, 0, i);
1212  gsl_blas_dtrmv(CblasUpper, CblasNoTrans, CblasNonUnit, &m.matrix, &v.vector);
1213  gsl_blas_dscal(aii, &v.vector);
1214  }
1215  }
1216  }
1217 #endif
1218  }
1219  else {
1220 #if (GSL_MAJOR_VERSION >= 2 && GSL_MINOR_VERSION >= 2)
1221  gsl_linalg_tri_lower_invert(&gsl_inv);
1222 #else
1223  {
1224  gsl_matrix_view m;
1225  gsl_vector_view v;
1226  for (unsigned int i = 0; i < rowNum; ++i) {
1227  size_t j = rowNum - i - 1;
1228  double *Tjj = gsl_matrix_ptr(&gsl_inv, j, j);
1229  *Tjj = 1.0 / (*Tjj);
1230  double ajj = -(*Tjj);
1231  if (j < rowNum - 1) {
1232  m = gsl_matrix_submatrix(&gsl_inv, j + 1, j + 1, rowNum - j - 1, rowNum - j - 1);
1233  v = gsl_matrix_subcolumn(&gsl_inv, j, j + 1, rowNum - j - 1);
1234  gsl_blas_dtrmv(CblasLower, CblasNoTrans, CblasNonUnit, &m.matrix, &v.vector);
1235  gsl_blas_dscal(ajj, &v.vector);
1236  }
1237  }
1238  }
1239 #endif
1240  }
1241 
1242  return inv;
1243 #else
1244  integer n = (integer)rowNum; // lda is the number of rows because we don't use a submatrix
1245 
1246  vpMatrix R = *this;
1247  integer info;
1248 
1249  // we just use the other (upper / lower) method from Lapack
1250  if (rowNum > 1 && upper) // upper triangular
1251  dtrtri_((char *)"L", (char *)"N", &n, R.data, &n, &info);
1252  else
1253  dtrtri_((char *)"U", (char *)"N", &n, R.data, &n, &info);
1254 
1255  if (info != 0) {
1256  if (info < 0)
1257  std::cout << "dtrtri_:" << -info << "th element had an illegal value" << std::endl;
1258  else if (info > 0) {
1259  std::cout << "dtrtri_:R(" << info << "," << info << ")"
1260  << " is exactly zero. The triangular matrix is singular "
1261  "and its inverse can not be computed."
1262  << std::endl;
1264  }
1266  }
1267  return R;
1268 #endif
1269 #else
1270  (void)upper;
1271  throw(vpException(vpException::fatalError, "Cannot perform triangular inverse. Install Lapack 3rd party"));
1272 #endif
1273 }
1274 
1323 {
1324  vpMatrix Q, R, P;
1325  unsigned int r = t().qrPivot(Q, R, P, false, true);
1326  x = Q.extract(0, 0, colNum, r) * R.inverseTriangular().t() * P * b;
1327 }
1328 
1378 {
1379  vpColVector x(colNum);
1380  solveByQR(b, x);
1381  return x;
1382 }
1383 END_VISP_NAMESPACE
unsigned int getCols() const
Definition: vpArray2D.h:337
Type * data
Address of the first element of the data array.
Definition: vpArray2D.h:148
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition: vpArray2D.h:362
unsigned int rowNum
Number of rows in the array.
Definition: vpArray2D.h:1101
unsigned int getRows() const
Definition: vpArray2D.h:347
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
@ badValue
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:73
@ dimensionError
Bad dimension.
Definition: vpException.h:71
@ fatalError
Fatal error.
Definition: vpException.h:72
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:169
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 inverseByQRLapack() const
void solveByQR(const vpColVector &b, vpColVector &x) const
vpMatrix inverseByQR() const
vpMatrix t() const
vpMatrix extract(unsigned int r, unsigned int c, unsigned int nrows, unsigned int ncols) const
Definition: vpMatrix.cpp:424