Visual Servoing Platform  version 3.1.0
vpMatrix_qr.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2017 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 <algorithm> // for (std::min) and (std::max)
40 #include <visp3/core/vpConfig.h>
41 
42 #include <visp3/core/vpColVector.h>
43 #include <visp3/core/vpMath.h>
44 #include <visp3/core/vpMatrix.h>
45 
46 // Exception
47 #include <visp3/core/vpException.h>
48 #include <visp3/core/vpMatrixException.h>
49 
50 // Debug trace
51 #include <visp3/core/vpDebug.h>
52 
53 #ifndef DOXYGEN_SHOULD_SKIP_THIS
54 #ifdef VISP_HAVE_LAPACK
55 #ifdef VISP_HAVE_LAPACK_BUILT_IN
56 typedef long int integer;
57 #else
58 typedef int integer;
59 #endif
60 
61 extern "C" int dgeqrf_(integer *m, integer *n, double *a, integer *lda, double *tau, double *work, integer *lwork,
62  integer *info);
63 extern "C" int dormqr_(char *side, char *trans, integer *m, integer *n, integer *k, double *a, integer *lda,
64  double *tau, double *c__, integer *ldc, double *work, integer *lwork, integer *info);
65 extern "C" int dorgqr_(integer *, integer *, integer *, double *, integer *, double *, double *, integer *, integer *);
66 extern "C" int dtrtri_(char *uplo, char *diag, integer *n, double *a, integer *lda, integer *info);
67 
68 int allocate_work(double **work);
69 
70 int allocate_work(double **work)
71 {
72  unsigned int dimWork = (unsigned int)((*work)[0]);
73  delete[] * work;
74  *work = new double[dimWork];
75  return (int)dimWork;
76 }
77 #endif
78 
79 #ifdef VISP_HAVE_LAPACK
80 
109 vpMatrix vpMatrix::inverseByQRLapack() const
110 {
111  if (rowNum != colNum) {
112  throw(vpMatrixException(vpMatrixException::matrixError, "Cannot inverse a non-square matrix (%ux%u) by QR", rowNum,
113  colNum));
114  }
115 
116  integer rowNum_ = (integer)this->getRows();
117  integer colNum_ = (integer)this->getCols();
118  integer lda = (integer)rowNum_; // lda is the number of rows because we don't use a submatrix
119  integer dimTau = (std::min)(rowNum_, colNum_);
120  integer dimWork = -1;
121  double *tau = new double[dimTau];
122  double *work = new double[1];
123  integer info;
124  vpMatrix C;
125  vpMatrix A = *this;
126 
127  try {
128  // 1) Extract householder reflections (useful to compute Q) and R
129  dgeqrf_(&rowNum_, // The number of rows of the matrix A. M >= 0.
130  &colNum_, // The number of columns of the matrix A. N >= 0.
131  A.data, /*On entry, the M-by-N matrix A.
132  On exit, the elements on and above the diagonal of
133  the array contain the min(M,N)-by-N upper trapezoidal
134  matrix R (R is upper triangular if m >= n); the
135  elements below the diagonal, with the array TAU,
136  represent the orthogonal matrix Q as a product of
137  min(m,n) elementary reflectors.
138  */
139  &lda, // The leading dimension of the array A. LDA >= max(1,M).
140  tau, /*Dimension (min(M,N))
141  The scalar factors of the elementary reflectors
142  */
143  work, // Internal working array. dimension (MAX(1,LWORK))
144  &dimWork, // The dimension of the array WORK. LWORK >= max(1,N).
145  &info // status
146  );
147 
148  if (info != 0) {
149  std::cout << "dgeqrf_:Preparation:" << -info << "th element had an illegal value" << std::endl;
151  }
152  dimWork = allocate_work(&work);
153 
154  dgeqrf_(&rowNum_, // The number of rows of the matrix A. M >= 0.
155  &colNum_, // The number of columns of the matrix A. N >= 0.
156  A.data, /*On entry, the M-by-N matrix A.
157  On exit, the elements on and above the diagonal of
158  the array contain the min(M,N)-by-N upper trapezoidal
159  matrix R (R is upper triangular if m >= n); the
160  elements below the diagonal, with the array TAU,
161  represent the orthogonal matrix Q as a product of
162  min(m,n) elementary reflectors.
163  */
164  &lda, // The leading dimension of the array A. LDA >= max(1,M).
165  tau, /*Dimension (min(M,N))
166  The scalar factors of the elementary reflectors
167  */
168  work, // Internal working array. dimension (MAX(1,LWORK))
169  &dimWork, // The dimension of the array WORK. LWORK >= max(1,N).
170  &info // status
171  );
172 
173  if (info != 0) {
174  std::cout << "dgeqrf_:" << -info << "th element had an illegal value" << std::endl;
176  }
177 
178  // A now contains the R matrix in its upper triangular (in lapack
179  // convention)
180  C = A;
181 
182  // 2) Invert R
183  dtrtri_((char *)"U", (char *)"N", &dimTau, C.data, &lda, &info);
184  if (info != 0) {
185  if (info < 0)
186  std::cout << "dtrtri_:" << -info << "th element had an illegal value" << std::endl;
187  else if (info > 0) {
188  std::cout << "dtrtri_:R(" << info << "," << info << ")"
189  << " is exactly zero. The triangular matrix is singular "
190  "and its inverse can not be computed."
191  << std::endl;
192  std::cout << "R=" << std::endl << C << std::endl;
193  }
195  }
196 
197  // 3) Zero-fill R^-1
198  // the matrix is upper triangular for lapack but lower triangular for visp
199  // we fill it with zeros above the diagonal (where we don't need the
200  // values)
201  for (unsigned int i = 0; i < C.getRows(); i++)
202  for (unsigned int j = 0; j < C.getRows(); j++)
203  if (j > i)
204  C[i][j] = 0.;
205 
206  dimWork = -1;
207  integer ldc = lda;
208 
209  // 4) Transpose Q and left-multiply it by R^-1
210  // get R^-1*tQ
211  // C contains R^-1
212  // A contains Q
213  dormqr_((char *)"R", (char *)"T", &rowNum_, &colNum_, &dimTau, A.data, &lda, tau, C.data, &ldc, work, &dimWork,
214  &info);
215  if (info != 0) {
216  std::cout << "dormqr_:Preparation" << -info << "th element had an illegal value" << std::endl;
218  }
219  dimWork = allocate_work(&work);
220 
221  dormqr_((char *)"R", (char *)"T", &rowNum_, &colNum_, &dimTau, A.data, &lda, tau, C.data, &ldc, work, &dimWork,
222  &info);
223 
224  if (info != 0) {
225  std::cout << "dormqr_:" << -info << "th element had an illegal value" << std::endl;
227  }
228  delete[] tau;
229  delete[] work;
230  } catch (vpMatrixException &) {
231  delete[] tau;
232  delete[] work;
233  throw;
234  }
235 
236  return C;
237 }
238 #endif
239 #endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
240 
272 {
273 #ifdef VISP_HAVE_LAPACK
274  return inverseByQRLapack();
275 #else
276  throw(vpException(vpException::fatalError, "Cannot inverse matrix by QR. Install Lapack 3rd party"));
277 #endif
278 }
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:104
vpMatrix inverseByQR() const
error that can be emited by ViSP classes.
Definition: vpException.h:71
unsigned int getRows() const
Definition: vpArray2D.h:156
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 rowNum
Number of rows in the array.
Definition: vpArray2D.h:74
unsigned int colNum
Number of columns in the array.
Definition: vpArray2D.h:76
error that can be emited by the vpMatrix class and its derivates