Visual Servoing Platform  version 3.0.1
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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
7  * modify it under the terms of the GNU General Public License
8  * ("GPL") version 2 as published by the Free Software Foundation.
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 http://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  * Authors:
34  * Filip Novotny
35  *
36  *****************************************************************************/
37 
38 #include <algorithm> // for std::min and std::max
39 #include <visp3/core/vpConfig.h>
40 
41 #include <visp3/core/vpMatrix.h>
42 #include <visp3/core/vpMath.h>
43 #include <visp3/core/vpColVector.h>
44 
45 // Exception
46 #include <visp3/core/vpException.h>
47 #include <visp3/core/vpMatrixException.h>
48 
49 // Debug trace
50 #include <visp3/core/vpDebug.h>
51 
52 int allocate_work(double** work);
53 
54 #ifdef VISP_HAVE_LAPACK_C
55 extern "C" int dgeqrf_(int *m, int *n, double*a, int *lda, double *tau, double *work, int *lwork, int *info);
56 extern "C" int dormqr_(char *side, char *trans, int *m, int *n,
57  int *k, double *a, int *lda, double *tau, double *c__,
58  int *ldc, double *work, int *lwork, int *info);
59 extern "C" int dorgqr_(int *, int *, int *, double *, int *,
60  double *, double *, int *, int *);
61 extern "C" int dtrtri_(char *uplo, char *diag, int *n, double *a, int *lda, int *info);
62 #endif
63 
64 int allocate_work(double** work)
65 {
66  unsigned int dimWork = (unsigned int)((*work)[0]);
67  delete[] *work;
68  *work = new double[dimWork];
69  return (int)dimWork;
70 }
71 #ifdef VISP_HAVE_LAPACK_C
73  int rowNum_ = (int)this->getRows();
74  int colNum_ = (int)this->getCols();
75  int lda = (int)rowNum_; //lda is the number of rows because we don't use a submatrix
76  int dimTau = std::min(rowNum_,colNum_);
77  int dimWork = -1;
78  double *tau = new double[dimTau];
79  double *work = new double[1];
80  int info;
81  vpMatrix C;
82  vpMatrix A = *this;
83 
84  try{
85  //1) Extract householder reflections (useful to compute Q) and R
86  dgeqrf_(
87  &rowNum_, //The number of rows of the matrix A. M >= 0.
88  &colNum_, //The number of columns of the matrix A. N >= 0.
89  A.data, /*On entry, the M-by-N matrix A.
90  On exit, the elements on and above the diagonal of the array
91  contain the min(M,N)-by-N upper trapezoidal matrix R (R is
92  upper triangular if m >= n); the elements below the diagonal,
93  with the array TAU, represent the orthogonal matrix Q as a
94  product of min(m,n) elementary reflectors.
95  */
96  &lda, //The leading dimension of the array A. LDA >= max(1,M).
97  tau, /*Dimension (min(M,N))
98  The scalar factors of the elementary reflectors
99  */
100  work, //Internal working array. dimension (MAX(1,LWORK))
101  &dimWork, //The dimension of the array WORK. LWORK >= max(1,N).
102  &info //status
103  );
104 
105  if(info != 0){
106  std::cout << "dgeqrf_:Preparation:" << -info << "th element had an illegal value" << std::endl;
108  }
109  dimWork = allocate_work(&work);
110 
111  dgeqrf_(
112  &rowNum_, //The number of rows of the matrix A. M >= 0.
113  &colNum_, //The number of columns of the matrix A. N >= 0.
114  A.data, /*On entry, the M-by-N matrix A.
115  On exit, the elements on and above the diagonal of the array
116  contain the min(M,N)-by-N upper trapezoidal matrix R (R is
117  upper triangular if m >= n); the elements below the diagonal,
118  with the array TAU, represent the orthogonal matrix Q as a
119  product of min(m,n) elementary reflectors.
120  */
121  &lda, //The leading dimension of the array A. LDA >= max(1,M).
122  tau, /*Dimension (min(M,N))
123  The scalar factors of the elementary reflectors
124  */
125  work, //Internal working array. dimension (MAX(1,LWORK))
126  &dimWork, //The dimension of the array WORK. LWORK >= max(1,N).
127  &info //status
128  );
129 
130 
131  if(info != 0){
132  std::cout << "dgeqrf_:" << -info << "th element had an illegal value" << std::endl;
134  }
135 
136  //A now contains the R matrix in its upper triangular (in lapack convention)
137  C = A;
138 
139  //2) Invert R
140  dtrtri_((char*)"U",(char*)"N",&dimTau,C.data,&lda,&info);
141  if(info!=0){
142  if(info < 0)
143  std::cout << "dtrtri_:"<< -info << "th element had an illegal value" << std::endl;
144  else if(info > 0){
145  std::cout << "dtrtri_:R("<< info << "," <<info << ")"<< " is exactly zero. The triangular matrix is singular and its inverse can not be computed." << std::endl;
146  std::cout << "R=" << std::endl << C << std::endl;
147  }
149  }
150 
151  //3) Zero-fill R^-1
152  //the matrix is upper triangular for lapack but lower triangular for visp
153  //we fill it with zeros above the diagonal (where we don't need the values)
154  for(unsigned int i=0;i<C.getRows();i++)
155  for(unsigned int j=0;j<C.getRows();j++)
156  if(j>i) C[i][j] = 0.;
157 
158  dimWork = -1;
159  int ldc = lda;
160 
161  //4) Transpose Q and left-multiply it by R^-1
162  //get R^-1*tQ
163  //C contains R^-1
164  //A contains Q
165  dormqr_((char*)"R", (char*)"T", &rowNum_, &colNum_, &dimTau, A.data, &lda, tau, C.data, &ldc, work, &dimWork, &info);
166  if(info != 0){
167  std::cout << "dormqr_:Preparation"<< -info << "th element had an illegal value" << std::endl;
169  }
170  dimWork = allocate_work(&work);
171 
172  dormqr_((char*)"R", (char*)"T", &rowNum_, &colNum_, &dimTau, A.data, &lda, tau, C.data, &ldc, work, &dimWork, &info);
173 
174  if(info != 0){
175  std::cout << "dormqr_:"<< -info << "th element had an illegal value" << std::endl;
177  }
178  delete[] tau;
179  delete[] work;
180  }catch(vpMatrixException&){
181  delete[] tau;
182  delete[] work;
183  throw;
184  }
185 
186  return C;
187 
188 }
189 #endif
190 
222 #if defined(VISP_HAVE_LAPACK_C)
223 vpMatrix
225 {
226 
227  if ( rowNum != colNum)
228  {
229  vpERROR_TRACE("\n\t\tCannot invert a non-square vpMatrix") ;
231  "Cannot invert a non-square vpMatrix")) ;
232  }
233 #ifdef VISP_HAVE_LAPACK_C
234  return inverseByQRLapack();
235 #endif
236 }
237 
238 #endif
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:97
#define vpERROR_TRACE
Definition: vpDebug.h:391
Type * data
Address of the first element of the data array.
Definition: vpArray2D.h:84
unsigned int getCols() const
Return the number of columns of the 2D array.
Definition: vpArray2D.h:154
unsigned int rowNum
Number of rows in the array.
Definition: vpArray2D.h:74
unsigned int getRows() const
Return the number of rows of the 2D array.
Definition: vpArray2D.h:152
unsigned int colNum
Number of columns in the array.
Definition: vpArray2D.h:76
vpMatrix inverseByQR() const
error that can be emited by the vpMatrix class and its derivates
vpMatrix inverseByQRLapack() const
Definition: vpMatrix_qr.cpp:72