ViSP  2.9.0
vpMatrix_qr.cpp
1 /****************************************************************************
2  *
3  * $Id: vpMatrix_lu.cpp 3530 2012-01-03 10:52:12Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2014 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.txt at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * Matrix QR decomposition.
36  *
37  * Authors:
38  * Filip Novotny
39  *
40  *****************************************************************************/
41 
42 #include <algorithm> // for std::min and std::max
43 #include <visp/vpConfig.h>
44 
45 #include <visp/vpMatrix.h>
46 #include <visp/vpMath.h>
47 #include <visp/vpColVector.h>
48 
49 // Exception
50 #include <visp/vpException.h>
51 #include <visp/vpMatrixException.h>
52 
53 // Debug trace
54 #include <visp/vpDebug.h>
55 
56 int allocate_work(double** work);
57 
58 #ifdef VISP_HAVE_LAPACK
59 extern "C" int dgeqrf_(int *m, int *n, double*a, int *lda, double *tau, double *work, int *lwork, int *info);
60 extern "C" int dormqr_(char *side, char *trans, int *m, int *n,
61  int *k, double *a, int *lda, double *tau, double *c__,
62  int *ldc, double *work, int *lwork, int *info);
63 extern "C" int dorgqr_(int *, int *, int *, double *, int *,
64  double *, double *, int *, int *);
65 extern "C" int dtrtri_(char *uplo, char *diag, int *n, double *a, int *lda, int *info);
66 #endif
67 
68 int allocate_work(double** work)
69 {
70  unsigned int dimWork = (unsigned int)((*work)[0]);
71  delete[] *work;
72  *work = new double[dimWork];
73  return (int)dimWork;
74 }
75 #ifdef VISP_HAVE_LAPACK
77  int rowNum_ = (int)this->getRows();
78  int colNum_ = (int)this->getCols();
79  int lda = (int)rowNum_; //lda is the number of rows because we don't use a submatrix
80  int dimTau = std::min(rowNum_,colNum_);
81  int dimWork = -1;
82  double *tau = new double[dimTau];
83  double *work = new double[1];
84  int info;
85  vpMatrix C;
86  vpMatrix A = *this;
87 
88  try{
89  //1) Extract householder reflections (useful to compute Q) and R
90  dgeqrf_(
91  &rowNum_, //The number of rows of the matrix A. M >= 0.
92  &colNum_, //The number of columns of the matrix A. N >= 0.
93  A.data, /*On entry, the M-by-N matrix A.
94  On exit, the elements on and above the diagonal of the array
95  contain the min(M,N)-by-N upper trapezoidal matrix R (R is
96  upper triangular if m >= n); the elements below the diagonal,
97  with the array TAU, represent the orthogonal matrix Q as a
98  product of min(m,n) elementary reflectors.
99  */
100  &lda, //The leading dimension of the array A. LDA >= max(1,M).
101  tau, /*Dimension (min(M,N))
102  The scalar factors of the elementary reflectors
103  */
104  work, //Internal working array. dimension (MAX(1,LWORK))
105  &dimWork, //The dimension of the array WORK. LWORK >= max(1,N).
106  &info //status
107  );
108 
109  if(info != 0){
110  std::cout << "dgeqrf_:Preparation:" << -info << "th element had an illegal value" << std::endl;
112  }
113  dimWork = allocate_work(&work);
114 
115  dgeqrf_(
116  &rowNum_, //The number of rows of the matrix A. M >= 0.
117  &colNum_, //The number of columns of the matrix A. N >= 0.
118  A.data, /*On entry, the M-by-N matrix A.
119  On exit, the elements on and above the diagonal of the array
120  contain the min(M,N)-by-N upper trapezoidal matrix R (R is
121  upper triangular if m >= n); the elements below the diagonal,
122  with the array TAU, represent the orthogonal matrix Q as a
123  product of min(m,n) elementary reflectors.
124  */
125  &lda, //The leading dimension of the array A. LDA >= max(1,M).
126  tau, /*Dimension (min(M,N))
127  The scalar factors of the elementary reflectors
128  */
129  work, //Internal working array. dimension (MAX(1,LWORK))
130  &dimWork, //The dimension of the array WORK. LWORK >= max(1,N).
131  &info //status
132  );
133 
134 
135  if(info != 0){
136  std::cout << "dgeqrf_:" << -info << "th element had an illegal value" << std::endl;
138  }
139 
140  //A now contains the R matrix in its upper triangular (in lapack convention)
141  C = A;
142 
143  //2) Invert R
144  dtrtri_((char*)"U",(char*)"N",&dimTau,C.data,&lda,&info);
145  if(info!=0){
146  if(info < 0)
147  std::cout << "dtrtri_:"<< -info << "th element had an illegal value" << std::endl;
148  else if(info > 0){
149  std::cout << "dtrtri_:R("<< info << "," <<info << ")"<< " is exactly zero. The triangular matrix is singular and its inverse can not be computed." << std::endl;
150  std::cout << "R=" << std::endl << C << std::endl;
151  }
153  }
154 
155  //3) Zero-fill R^-1
156  //the matrix is upper triangular for lapack but lower triangular for visp
157  //we fill it with zeros above the diagonal (where we don't need the values)
158  for(unsigned int i=0;i<C.getRows();i++)
159  for(unsigned int j=0;j<C.getRows();j++)
160  if(j>i) C[i][j] = 0.;
161 
162  dimWork = -1;
163  int ldc = lda;
164 
165  //4) Transpose Q and left-multiply it by R^-1
166  //get R^-1*tQ
167  //C contains R^-1
168  //A contains Q
169  dormqr_((char*)"R", (char*)"T", &rowNum_, &colNum_, &dimTau, A.data, &lda, tau, C.data, &ldc, work, &dimWork, &info);
170  if(info != 0){
171  std::cout << "dormqr_:Preparation"<< -info << "th element had an illegal value" << std::endl;
173  }
174  dimWork = allocate_work(&work);
175 
176  dormqr_((char*)"R", (char*)"T", &rowNum_, &colNum_, &dimTau, A.data, &lda, tau, C.data, &ldc, work, &dimWork, &info);
177 
178  if(info != 0){
179  std::cout << "dormqr_:"<< -info << "th element had an illegal value" << std::endl;
181  }
182  delete[] tau;
183  delete[] work;
184  }catch(vpMatrixException&){
185  delete[] tau;
186  delete[] work;
187  throw;
188  }
189 
190  return C;
191 
192 }
193 #endif
194 
226 #if defined(VISP_HAVE_LAPACK)
227 vpMatrix
229 {
230 
231  if ( rowNum != colNum)
232  {
233  vpERROR_TRACE("\n\t\tCannot invert a non-square vpMatrix") ;
235  "Cannot invert a non-square vpMatrix")) ;
236  }
237 #ifdef VISP_HAVE_LAPACK
238  return inverseByQRLapack();
239 #endif
240 }
241 
242 #endif
Definition of the vpMatrix class.
Definition: vpMatrix.h:98
#define vpERROR_TRACE
Definition: vpDebug.h:395
double * data
address of the first element of the data array
Definition: vpMatrix.h:118
vpMatrix inverseByQR() const
unsigned int rowNum
number of rows
Definition: vpMatrix.h:112
unsigned int getCols() const
Return the number of columns of the matrix.
Definition: vpMatrix.h:163
error that can be emited by the vpMatrix class and its derivates
unsigned int colNum
number of columns
Definition: vpMatrix.h:114
unsigned int getRows() const
Return the number of rows of the matrix.
Definition: vpMatrix.h:161
vpMatrix inverseByQRLapack() const
Definition: vpMatrix_qr.cpp:76