ViSP  2.9.0
testMatrixInverse.cpp
1 /****************************************************************************
2  *
3  * $Id: testSvd.cpp 3857 2012-07-25 11:47:30Z 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  * Test various inversions.
36  *
37  * Authors:
38  * Filip Novotny
39  *
40  *****************************************************************************/
41 
42 
50 #include <visp/vpTime.h>
51 
52 #include <visp/vpMatrix.h>
53 #include <visp/vpColVector.h>
54 #include <visp/vpParseArgv.h>
55 #include <vector>
56 #include <stdlib.h>
57 #include <stdio.h>
58 #include <fstream>
59 #include <iostream>
60 #include <cmath>
61 // List of allowed command line options
62 #define GETOPTARGS "n:i:pf:r:c:vh"
63 
64 void usage(const char *name, const char *badparam);
65 bool getOptions(int argc, const char **argv,
66  unsigned int& nb_matrices, unsigned int& nb_iterations,
67  bool& use_plot_file, std::string& plotfile,
68  unsigned int& nbrows, unsigned int& nbcols, bool& verbose);
69 void writeTime(const char *name, double time);
70 vpMatrix makeRandomMatrix(unsigned int nbrows, unsigned int nbcols);
71 
80 void usage(const char *name, const char *badparam)
81 {
82  fprintf(stdout, "\n\
83 Test matrix inversions\n\
84 using LU, QR and Cholesky methods as well as Pseudo-inverse.\n\
85 Outputs a comparison of these methods.\n\
86 \n\
87 SYNOPSIS\n\
88  %s [-n <number of matrices>] [-f <plot filename>]\n\
89  [-r <number of rows>] [-c <number of columns>]\n\
90  [-i <number of iterations>] [-p] [-h]\n", name);
91 
92  fprintf(stdout, "\n\
93 OPTIONS: Default\n\
94  -n <number of matrices> \n\
95  Number of matrices inverted during each test loop.\n\
96 \n\
97  -i <number of iterations> \n\
98  Number of iterations of the test.\n\
99 \n\
100  -f <plot filename> \n\
101  Set output path for plot output.\n\
102  The plot logs the times of \n\
103  the different inversion methods: \n\
104  QR,LU,Cholesky and Pseudo-inverse.\n\
105 \n\
106  -r <number of rows>\n\
107  Number of rows of the automatically generated matrices \n\
108  we test on.\n\
109 \n\
110  -c <number of columns>\n\
111  Number of colums of the automatically generated matrices \n\
112  we test on.\n\
113 \n\
114  -p \n\
115  Plot into filename in the gnuplot format. \n\
116  If this option is used, tests results will be logged \n\
117  into a filename specified with -f.\n\
118 \n\
119  -h\n\
120  Print the help.\n\n");
121 
122  if (badparam) {
123  fprintf(stderr, "ERROR: \n" );
124  fprintf(stderr, "\nBad parameter [%s]\n", badparam);
125  }
126 
127 }
135 bool getOptions(int argc, const char **argv,
136  unsigned int& nb_matrices, unsigned int& nb_iterations,
137  bool& use_plot_file, std::string& plotfile,
138  unsigned int& nbrows, unsigned int& nbcols, bool& verbose)
139 {
140  const char *optarg_;
141  int c;
142  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
143 
144  switch (c) {
145  case 'h': usage(argv[0], NULL); return false; break;
146  case 'n':
147  nb_matrices = (unsigned int)atoi(optarg_);
148  break;
149  case 'i':
150  nb_iterations = (unsigned int)atoi(optarg_);
151  break;
152  case 'f':
153  plotfile = optarg_;
154  use_plot_file = true;
155  break;
156  case 'p':
157  use_plot_file = true;
158  break;
159  case 'r':
160  nbrows = (unsigned int)atoi(optarg_);
161  break;
162  case 'c':
163  nbcols = (unsigned int)atoi(optarg_);
164  break;
165  case 'v':
166  verbose = true;
167  break;
168  default:
169  usage(argv[0], optarg_);
170  return false; break;
171  }
172  }
173 
174  if ((c == 1) || (c == -1)) {
175  // standalone param or error
176  usage(argv[0], NULL);
177  std::cerr << "ERROR: " << std::endl;
178  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
179  return false;
180  }
181 
182  return true;
183 }
184 
185 void writeTime(const char *name, double time)
186 {
187  std::cout << name << " time=" << time << " ms." << std::endl;
188 }
189 
190 vpMatrix makeRandomMatrix(unsigned int nbrows, unsigned int nbcols)
191 {
192  vpMatrix A;
193  A.resize(nbrows,nbcols);
194 
195  for (unsigned int i=0 ; i < A.getRows() ; i++)
196  for (unsigned int j=0 ; j < A.getCols() ; j++)
197  A[i][j] = (double)rand()/(double)RAND_MAX;
198  return A;
199 }
200 
201 
202 int
203 main(int argc, const char ** argv)
204 {
205 #ifdef VISP_HAVE_LAPACK
206  try {
207  unsigned int nb_matrices=1000;
208  unsigned int nb_iterations=10;
209  unsigned int nb_rows = 6;
210  unsigned int nb_cols = 6;
211  bool verbose = false;
212  std::string plotfile("plot.txt");
213  bool use_plot_file=false;
214  std::ofstream of;
215 
216  double t, qr_time, lu_time,pi_time,chol_time;
217  // Read the command line options
218  if (getOptions(argc, argv, nb_matrices,nb_iterations,use_plot_file,plotfile,nb_rows,nb_cols,verbose) == false) {
219  exit (-1);
220  }
221 
222  if(use_plot_file){
223  of.open(plotfile.c_str());
224  }
225 
226  for(unsigned int iter=0;iter<nb_iterations;iter++){
227  std::vector<vpMatrix> benchQR;
228  std::vector<vpMatrix> benchLU;
229  std::vector<vpMatrix> benchCholesky;
230  std::vector<vpMatrix> benchPseudoInverse;
231  if(verbose)
232  std::cout << "********* generating matrices for iteration " << iter << "." << std::endl;
233  for(unsigned int i=0;i<nb_matrices;i++){
234  vpMatrix cur;
235  double det=0.;
236  //don't put singular matrices in the benchmark
237  for(cur=makeRandomMatrix(nb_rows,nb_cols);std::abs(det=cur.AtA().det())<.01;cur = makeRandomMatrix(nb_rows,nb_cols))
238  if(verbose){
239  std::cout << "Generated random matrix A*tA=" << std::endl << cur.AtA() << std::endl;
240  std::cout << "generated random matrix not invertibleL: det="<<det<< ". Retrying..." << std::endl;
241  }
242  benchCholesky.push_back(cur);
243  benchQR.push_back(cur);
244  benchLU.push_back(cur);
245  benchPseudoInverse.push_back(cur);
246  }
247 
248  if(verbose)
249  std::cout << "\t Inverting " << benchCholesky[0].AtA().getRows() << "x" << benchCholesky[0].AtA().getCols() << " matrix using cholesky decomposition." << std::endl;
250  t = vpTime::measureTimeMs() ;
251  for(unsigned int i=0;i<nb_matrices;i++){
252  benchCholesky[i]=benchCholesky[i].AtA().inverseByCholesky()*benchCholesky[i].transpose();
253  }
254  chol_time = vpTime::measureTimeMs() - t ;
255 
256  if(verbose)
257  std::cout << "\t Inverting " << benchLU[0].AtA().getRows() << "x" << benchLU[0].AtA().getCols() << " matrix using LU decomposition." << std::endl;
258  t = vpTime::measureTimeMs() ;
259  for(unsigned int i=0;i<nb_matrices;i++)
260  benchLU[i] = benchLU[i].AtA().inverseByLU()*benchLU[i].transpose();
261  lu_time = vpTime::measureTimeMs() -t ;
262 
263  if(verbose)
264  std::cout << "\t Inverting " << benchQR[0].AtA().getRows() << "x" << benchQR[0].AtA().getCols() << " matrix using QR decomposition." << std::endl;
265  t = vpTime::measureTimeMs() ;
266  for(unsigned int i=0;i<nb_matrices;i++){
267  benchQR[i]=benchQR[i].AtA().inverseByQR()*benchQR[i].transpose();
268  }
269  qr_time = vpTime::measureTimeMs() - t ;
270 
271  if(verbose)
272  std::cout << "\t Inverting " << benchPseudoInverse[0].AtA().getRows() << "x" << benchPseudoInverse[0].AtA().getCols() << " matrix while computing pseudo-inverse." << std::endl;
273  t = vpTime::measureTimeMs() ;
274  for(unsigned int i=0;i<nb_matrices;i++){
275  benchPseudoInverse[i]=benchPseudoInverse[i].pseudoInverse();
276  }
277  pi_time = vpTime::measureTimeMs() - t ;
278 
279  double avg_err_lu_qr=0.;
280  double avg_err_lu_pi=0.;
281  double avg_err_lu_chol=0.;
282  double avg_err_qr_pi=0.;
283  double avg_err_qr_chol=0.;
284  double avg_err_pi_chol=0.;
285 
286  for(unsigned int i=0;i<nb_matrices;i++){
287  avg_err_lu_qr+= (benchQR[i]-benchLU[i]).euclideanNorm();
288  avg_err_lu_pi+= (benchPseudoInverse[i]-benchLU[i]).euclideanNorm();
289  avg_err_qr_pi+= (benchPseudoInverse[i]-benchQR[i]).euclideanNorm();
290  avg_err_qr_chol+= (benchCholesky[i]-benchQR[i]).euclideanNorm();
291  avg_err_lu_chol+= (benchCholesky[i]-benchLU[i]).euclideanNorm();
292  avg_err_pi_chol+= (benchCholesky[i]-benchPseudoInverse[i]).euclideanNorm();
293  }
294 
295  avg_err_lu_qr/=nb_matrices;
296  avg_err_lu_pi/=nb_matrices;
297  avg_err_qr_pi/=nb_matrices;
298 
299  if(use_plot_file){
300  of << iter << "\t" << lu_time << "\t" << qr_time << "\t" << pi_time << "\t" << chol_time << "\t" << avg_err_lu_qr << "\t" << avg_err_qr_pi << "\t" << avg_err_lu_pi << "\t" << avg_err_qr_chol << "\t" << avg_err_lu_chol << "\t" << avg_err_pi_chol << std::endl;
301  }
302  if(verbose || !use_plot_file){
303  writeTime("LU",lu_time);
304  writeTime("QR",qr_time);
305  writeTime("Pseudo-inverse",pi_time);
306  writeTime("Cholesky",chol_time);
307  }
308  }
309  return 0;
310  }
311  catch(vpException e) {
312  std::cout << "Catch an exception: " << e << std::endl;
313  return 1;
314  }
315 
316 #else
317  (void)argc;
318  (void)argv;
319  std::cout << "You don't have lapack installed" << std::endl;
320  return 0;
321 #endif
322 }
323 
Definition of the vpMatrix class.
Definition: vpMatrix.h:98
void resize(const unsigned int nrows, const unsigned int ncols, const bool nullify=true)
Definition: vpMatrix.cpp:183
error that can be emited by ViSP classes.
Definition: vpException.h:76
static double measureTimeMs()
Definition: vpTime.cpp:86
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:79
vpMatrix AtA() const
Definition: vpMatrix.cpp:1408
double det(vpDetMethod method=LU_DECOMPOSITION) const
Definition: vpMatrix.cpp:3496
unsigned int getCols() const
Return the number of columns of the matrix.
Definition: vpMatrix.h:163
unsigned int getRows() const
Return the number of rows of the matrix.
Definition: vpMatrix.h:161