Visual Servoing Platform  version 3.2.0 under development (2019-01-22)
vpMatrix_qr.cpp
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  *
37  *****************************************************************************/
38 
39 #include <cmath> // For std::abs() on iOS
40 #include <cstdlib> // For std::abs() on iOS
41 #include <algorithm> // for (std::min) and (std::max)
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_LAPACK_BUILT_IN
57 typedef long int integer;
58 #else
59 typedef int integer;
60 #endif
61 
62 extern "C" int dgeqrf_(integer *m, integer *n, double *a, integer *lda, double *tau, double *work, integer *lwork,
63  integer *info);
64 extern "C" int dormqr_(char *side, char *trans, integer *m, integer *n, integer *k, double *a, integer *lda,
65  double *tau, double *c__, integer *ldc, double *work, integer *lwork, integer *info);
66 extern "C" int dorgqr_(integer *, integer *, integer *, double *, integer *, double *, double *, integer *, integer *);
67 extern "C" int dtrtri_(char *uplo, char *diag, integer *n, double *a, integer *lda, integer *info);
68 extern "C" int dgeqp3_(integer *m, integer *n, double*a, integer *lda, integer *p,
69  double *tau, double *work, integer* lwork, integer *info);
70 
71 int allocate_work(double **work);
72 
73 int allocate_work(double **work)
74 {
75  unsigned int dimWork = (unsigned int)((*work)[0]);
76  delete[] * work;
77  *work = new double[dimWork];
78  return (int)dimWork;
79 }
80 #endif
81 
82 #ifdef VISP_HAVE_LAPACK
83 
113 {
114  if (rowNum != colNum) {
115  throw(vpMatrixException(vpMatrixException::matrixError, "Cannot inverse a non-square matrix (%ux%u) by QR", rowNum,
116  colNum));
117  }
118 
119  integer rowNum_ = (integer)this->getRows();
120  integer colNum_ = (integer)this->getCols();
121  integer lda = (integer)rowNum_; // lda is the number of rows because we don't use a submatrix
122  integer dimTau = (std::min)(rowNum_, colNum_);
123  integer dimWork = -1;
124  double *tau = new double[dimTau];
125  double *work = new double[1];
126  integer info;
127  vpMatrix C;
128  vpMatrix A = *this;
129 
130  try {
131  // 1) Extract householder reflections (useful to compute Q) and R
132  dgeqrf_(&rowNum_, // The number of rows of the matrix A. M >= 0.
133  &colNum_, // The number of columns of the matrix A. N >= 0.
134  A.data, /*On entry, the M-by-N matrix A.
135  On exit, the elements on and above the diagonal of
136  the array contain the min(M,N)-by-N upper trapezoidal
137  matrix R (R is upper triangular if m >= n); the
138  elements below the diagonal, with the array TAU,
139  represent the orthogonal matrix Q as a product of
140  min(m,n) elementary reflectors.
141  */
142  &lda, // The leading dimension of the array A. LDA >= max(1,M).
143  tau, /*Dimension (min(M,N))
144  The scalar factors of the elementary reflectors
145  */
146  work, // Internal working array. dimension (MAX(1,LWORK))
147  &dimWork, // The dimension of the array WORK. LWORK >= max(1,N).
148  &info // status
149  );
150 
151  if (info != 0) {
152  std::cout << "dgeqrf_:Preparation:" << -info << "th element had an illegal value" << std::endl;
154  }
155  dimWork = allocate_work(&work);
156 
157  dgeqrf_(&rowNum_, // The number of rows of the matrix A. M >= 0.
158  &colNum_, // The number of columns of the matrix A. N >= 0.
159  A.data, /*On entry, the M-by-N matrix A.
160  On exit, the elements on and above the diagonal of
161  the array contain the min(M,N)-by-N upper trapezoidal
162  matrix R (R is upper triangular if m >= n); the
163  elements below the diagonal, with the array TAU,
164  represent the orthogonal matrix Q as a product of
165  min(m,n) elementary reflectors.
166  */
167  &lda, // The leading dimension of the array A. LDA >= max(1,M).
168  tau, /*Dimension (min(M,N))
169  The scalar factors of the elementary reflectors
170  */
171  work, // Internal working array. dimension (MAX(1,LWORK))
172  &dimWork, // The dimension of the array WORK. LWORK >= max(1,N).
173  &info // status
174  );
175 
176  if (info != 0) {
177  std::cout << "dgeqrf_:" << -info << "th element had an illegal value" << std::endl;
179  }
180 
181  // A now contains the R matrix in its upper triangular (in lapack
182  // convention)
183  C = A;
184 
185  // 2) Invert R
186  dtrtri_((char *)"U", (char *)"N", &dimTau, C.data, &lda, &info);
187  if (info != 0) {
188  if (info < 0)
189  std::cout << "dtrtri_:" << -info << "th element had an illegal value" << std::endl;
190  else if (info > 0) {
191  std::cout << "dtrtri_:R(" << info << "," << info << ")"
192  << " is exactly zero. The triangular matrix is singular "
193  "and its inverse can not be computed."
194  << std::endl;
195  std::cout << "R=" << std::endl << C << std::endl;
196  }
198  }
199 
200  // 3) Zero-fill R^-1
201  // the matrix is upper triangular for lapack but lower triangular for visp
202  // we fill it with zeros above the diagonal (where we don't need the
203  // values)
204  for (unsigned int i = 0; i < C.getRows(); i++)
205  for (unsigned int j = 0; j < C.getRows(); j++)
206  if (j > i)
207  C[i][j] = 0.;
208 
209  dimWork = -1;
210  integer ldc = lda;
211 
212  // 4) Transpose Q and left-multiply it by R^-1
213  // get R^-1*tQ
214  // C contains R^-1
215  // A contains Q
216  dormqr_((char *)"R", (char *)"T", &rowNum_, &colNum_, &dimTau, A.data, &lda, tau, C.data, &ldc, work, &dimWork,
217  &info);
218  if (info != 0) {
219  std::cout << "dormqr_:Preparation" << -info << "th element had an illegal value" << std::endl;
221  }
222  dimWork = allocate_work(&work);
223 
224  dormqr_((char *)"R", (char *)"T", &rowNum_, &colNum_, &dimTau, A.data, &lda, tau, C.data, &ldc, work, &dimWork,
225  &info);
226 
227  if (info != 0) {
228  std::cout << "dormqr_:" << -info << "th element had an illegal value" << std::endl;
230  }
231  delete[] tau;
232  delete[] work;
233  } catch (vpMatrixException &) {
234  delete[] tau;
235  delete[] work;
236  throw;
237  }
238 
239  return C;
240 }
241 #endif
242 
274 {
275 #ifdef VISP_HAVE_LAPACK
276  return inverseByQRLapack();
277 #else
278  throw(vpException(vpException::fatalError, "Cannot inverse matrix by QR. Install Lapack 3rd party"));
279 #endif
280 }
281 
282 
337 unsigned int vpMatrix::qr(vpMatrix &Q, vpMatrix &R, bool full, bool squareR, double tol) const
338 {
339 #ifdef VISP_HAVE_LAPACK
340  integer m = (integer) rowNum; // also rows of Q
341  integer n = (integer) colNum; // also columns of R
342  integer r = std::min(n,m); // a priori non-null rows of R = rank of R
343  integer q = r; // columns of Q and rows of R
344  integer na = n; // columns of A
345 
346  // cannot be full decomposition if m < n
347  if(full && m > n)
348  {
349  q = m; // Q is square
350  na = m; // A is square
351  }
352 
353  // prepare matrices and deal with r = 0
354  Q.resize(static_cast<unsigned int>(m), static_cast<unsigned int>(q));
355  if(squareR)
356  R.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(r));
357  else
358  R.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(n));
359  if(r == 0)
360  return 0;
361 
362  integer dimWork = -1;
363  double * qrdata = new double[m*na];
364  double *tau = new double[std::min(m,q)];
365  double *work = new double[1];
366  integer info;
367 
368  // copy this to qrdata in Lapack convention
369  for(integer i = 0; i < m; ++i)
370  {
371  for(integer j = 0; j < n; ++j)
372  qrdata[i+m*j] = data[j + n*i];
373  for(integer j = n; j < na; ++j)
374  qrdata[i+m*j] = 0;
375  }
376 
377  // work = new double[1];
378  //1) Extract householder reflections (useful to compute Q) and R
379  dgeqrf_(
380  &m, //The number of rows of the matrix A. M >= 0.
381  &na, //The number of columns of the matrix A. N >= 0.
382  qrdata,
383  &m,
384  tau,
385  work, //Internal working array. dimension (MAX(1,LWORK))
386  &dimWork, //The dimension of the array WORK. LWORK >= max(1,N).
387  &info //status
388  );
389 
390  if(info != 0){
391  std::cout << "dgeqrf_:Preparation:" << -info << "th element had an illegal value" << std::endl;
392  delete[] qrdata;
393  delete[] work;
394  delete[] tau;
396  }
397  dimWork = allocate_work(&work);
398 
399  dgeqrf_(
400  &m, //The number of rows of the matrix A. M >= 0.
401  &na, //The number of columns of the matrix A. N >= 0.
402  qrdata,
403  &m, //The leading dimension of the array A. LDA >= max(1,M).
404  tau,
405  work, //Internal working array. dimension (MAX(1,LWORK))
406  &dimWork, //The dimension of the array WORK. LWORK >= max(1,N).
407  &info //status
408  );
409 
410  if(info != 0){
411  std::cout << "dgeqrf_:" << -info << "th element had an illegal value" << std::endl;
412  delete[] qrdata;
413  delete[] work;
414  delete[] tau;
416  }
417 
418  // data now contains the R matrix in its upper triangular (in lapack convention)
419 
420  // copy useful part of R from Q and update rank
421  na = std::min(m,n);
422  if(squareR)
423  {
424  for(int i=0;i<na;i++)
425  {
426  for(int j=i;j<na;j++)
427  R[i][j] = qrdata[i+m*j];
428  if(std::abs(qrdata[i+m*i]) < tol)
429  r--;
430  }
431  }
432  else
433  {
434  for(int i=0;i<na;i++)
435  {
436  for(int j=i;j<n;j++)
437  R[i][j] = qrdata[i+m*j];
438  if(std::abs(qrdata[i+m*i]) < tol)
439  r--;
440  }
441  }
442 
443  // extract Q
444  dorgqr_(&m, // The number of rows of the matrix Q. M >= 0.
445  &q, // The number of columns of the matrix Q. M >= N >= 0.
446  &q,
447  qrdata,
448  &m, //The leading dimension of the array A. LDA >= max(1,M).
449  tau,
450  work, //Internal working array. dimension (MAX(1,LWORK))
451  &dimWork, //The dimension of the array WORK. LWORK >= max(1,N).
452  &info //status
453  );
454 
455  // write qrdata into Q
456  for(int i = 0; i < m; ++i)
457  for(int j = 0; j < q; ++j)
458  Q[i][j] = qrdata[i+m*j];
459 
460  delete[] qrdata;
461  delete[] work;
462  delete[] tau;
463  return (unsigned int) r;
464 #else
465  (void)Q;
466  (void)R;
467  (void)full;
468  (void)squareR;
469  (void)tol;
470  throw(vpException(vpException::fatalError, "Cannot perform QR decomposition. Install Lapack 3rd party"));
471 #endif
472 }
473 
474 
537 unsigned int vpMatrix::qrPivot(vpMatrix &Q, vpMatrix &R, vpMatrix &P, bool full, bool squareR, double tol) const
538 {
539 #ifdef VISP_HAVE_LAPACK
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;
545 
546  // cannot be full decomposition if m < n
547  if(full && m > n)
548  {
549  q = m; // Q is square
550  na = m;
551  }
552 
553  // prepare Q and deal with r = 0
554  Q.resize(static_cast<unsigned int>(m), static_cast<unsigned int>(q));
555  if(r == 0)
556  {
557  if(squareR)
558  {
559  R.resize(0, 0);
560  P.resize(0, static_cast<unsigned int>(n));
561  }
562  else
563  {
564  R.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(n));
565  P.resize(static_cast<unsigned int>(n), static_cast<unsigned int>(n));
566  }
567  return 0;
568  }
569 
570  integer dimWork = -1;
571  double* qrdata = new double[m*na];
572  double* tau = new double[std::min(q,m)];
573  double* work = new double[1];
574  integer* p = new integer[na];
575  for(int i = 0; i < na; ++i)
576  p[i] = 0;
577 
578  integer info;
579 
580  // copy this to qrdata in Lapack convention
581  for(integer i = 0; i < m; ++i)
582  {
583  for(integer j = 0; j < n; ++j)
584  qrdata[i+m*j] = data[j + n*i];
585  for(integer j = n; j < na; ++j)
586  qrdata[i+m*j] = 0;
587  }
588 
589  //1) Extract householder reflections (useful to compute Q) and R
590  dgeqp3_(
591  &m, //The number of rows of the matrix A. M >= 0.
592  &na, //The number of columns of the matrix A. N >= 0.
593  qrdata, /*On entry, the M-by-N matrix A. */
594  &m, //The leading dimension of the array A. LDA >= max(1,M).
595  p, // Dimension N
596  tau, /*Dimension (min(M,N)) */
597  work, //Internal working array. dimension (3*N)
598 
599  &dimWork,
600  &info //status
601  );
602 
603  if(info != 0){
604  std::cout << "dgeqp3_:Preparation:" << -info << "th element had an illegal value" << std::endl;
605  delete[] qrdata;
606  delete[] work;
607  delete[] tau;
608  delete[] p;
610  }
611 
612  dimWork = allocate_work(&work);
613 
614  dgeqp3_(
615  &m, //The number of rows of the matrix A. M >= 0.
616  &na, //The number of columns of the matrix A. N >= 0.
617  qrdata, /*On entry, the M-by-N matrix A. */
618  &m, //The leading dimension of the array A. LDA >= max(1,M).
619  p, // Dimension N
620  tau, /*Dimension (min(M,N)) */
621  work, //Internal working array. dimension (3*N)
622 
623  &dimWork,
624  &info //status
625  );
626 
627  if(info != 0){
628  std::cout << "dgeqp3_:" << -info << " th element had an illegal value" << std::endl;
629  delete[] qrdata;
630  delete[] work;
631  delete[] tau;
632  delete[] p;
634  }
635 
636 
637  // data now contains the R matrix in its upper triangular (in lapack convention)
638  // get rank of R in r
639  na = std::min(n,m);
640  for(int i = 0; i < na; ++i)
641  if(std::abs(qrdata[i+m*i]) < tol)
642  r--;
643 
644  // write R
645  if(squareR) // R r x r
646  {
647  R.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(r));
648  for(int i=0;i<r;i++)
649  for(int j=i;j<r;j++)
650  R[i][j] = qrdata[i+m*j];
651 
652  // write P
653  P.resize(static_cast<unsigned int>(r), static_cast<unsigned int>(n));
654  for(int i = 0; i < r; ++i)
655  P[i][p[i]-1] = 1;
656  }
657  else // R is min(m,n) x n of rank r
658  {
659  R.resize(static_cast<unsigned int>(na), static_cast<unsigned int>(n));
660  for(int i=0;i<na;i++)
661  for(int j=i;j<n;j++)
662  R[i][j] = qrdata[i+m*j];
663  // write P
664  P.resize(static_cast<unsigned int>(n), static_cast<unsigned int>(n));
665  for(int i = 0; i < n; ++i)
666  P[i][p[i]-1] = 1;
667  }
668 
669  // extract Q
670  dorgqr_(&m, // The number of rows of the matrix Q. M >= 0.
671  &q, // The number of columns of the matrix Q. M >= N >= 0.
672  &q,
673  qrdata,
674  &m, //The leading dimension of the array A. LDA >= max(1,M).
675  tau,
676  work, //Internal working array. dimension (MAX(1,LWORK))
677  &dimWork, //The dimension of the array WORK. LWORK >= max(1,N).
678  &info //status
679  );
680 
681  // write qrdata into Q
682  for(int i = 0; i < m; ++i)
683  for(int j = 0; j < q; ++j)
684  Q[i][j] = qrdata[i+m*j];
685 
686  delete[] qrdata;
687  delete[] work;
688  delete[] tau;
689  delete[] p;
690  return (unsigned int) r;
691 #else
692  (void)Q;
693  (void)R;
694  (void)P;
695  (void)full;
696  (void)squareR;
697  (void)tol;
698  throw(vpException(vpException::fatalError, "Cannot perform QR decomposition. Install Lapack 3rd party"));
699 #endif
700 }
701 
714 {
715 #ifdef VISP_HAVE_LAPACK
716  if(rowNum != colNum || rowNum == 0)
718 
719  integer n = (integer) rowNum; // lda is the number of rows because we don't use a submatrix
720 
721  vpMatrix R = *this;
722  integer info;
723 
724  // we just use the other (upper / lower) method from Lapack
725  if(rowNum > 1 && upper) // upper triangular
726  dtrtri_((char *)"L", (char *)"N", &n, R.data, &n, &info);
727  else
728  dtrtri_((char *)"U", (char *)"N", &n, R.data, &n, &info);
729 
730  if (info != 0) {
731  if (info < 0)
732  std::cout << "dtrtri_:" << -info << "th element had an illegal value" << std::endl;
733  else if (info > 0) {
734  std::cout << "dtrtri_:R(" << info << "," << info << ")"
735  << " is exactly zero. The triangular matrix is singular "
736  "and its inverse can not be computed."
737  << std::endl;
739  }
741  }
742  return R;
743 #else
744  (void)upper;
745  throw(vpException(vpException::fatalError, "Cannot perform triangular inverse. Install Lapack 3rd party"));
746 #endif
747 }
748 
749 
793 {
794  vpMatrix Q, R, P;
795  unsigned int r = t().qrPivot(Q, R, P, false, true);
796  x = Q.extract(0, 0, colNum, r)
797  * R.inverseTriangular().t()
798  * P * b;
799 }
800 
845 {
846  vpColVector x(colNum);
847  solveByQR(b, x);
848  return x;
849 }
850 
851 
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:97
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:104
void resize(const unsigned int nrows, const unsigned int ncols, const bool flagNullify=true, const bool recopy_=true)
Definition: vpArray2D.h:171
vpMatrix inverseTriangular(bool upper=true) const
error that can be emited by ViSP classes.
Definition: vpException.h:71
Type * data
Address of the first element of the data array.
Definition: vpArray2D.h:84
unsigned int getCols() const
Definition: vpArray2D.h:146
unsigned int qrPivot(vpMatrix &Q, vpMatrix &R, vpMatrix &P, bool full=false, bool squareR=false, double tol=1e-6) const
unsigned int qr(vpMatrix &Q, vpMatrix &R, bool full=false, bool squareR=false, double tol=1e-6) const
unsigned int rowNum
Number of rows in the array.
Definition: vpArray2D.h:74
vpMatrix extract(unsigned int r, unsigned int c, unsigned int nrows, unsigned int ncols) const
Definition: vpMatrix.cpp:319
unsigned int getRows() const
Definition: vpArray2D.h:156
unsigned int colNum
Number of columns in the array.
Definition: vpArray2D.h:76
void solveByQR(const vpColVector &b, vpColVector &x) const
vpMatrix inverseByQR() const
vpMatrix t() const
Definition: vpMatrix.cpp:375
Implementation of column vector and the associated operations.
Definition: vpColVector.h:72
error that can be emited by the vpMatrix class and its derivates
vpMatrix inverseByQRLapack() const