Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ExampleSVD.cpp
1 /* This file is part of the BIAS library (Basic ImageAlgorithmS).
2 
3 Copyright (C) 2003-2009 (see file CONTACT for details)
4  Multimediale Systeme der Informationsverarbeitung
5  Institut fuer Informatik
6  Christian-Albrechts-Universitaet Kiel
7 
8 
9 BIAS is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13 
14 BIAS is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Lesser General Public License for more details.
18 
19 You should have received a copy of the GNU Lesser General Public License
20 along with BIAS; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23 
24 /** @example ExampleSVD.cpp
25  @relates SVD3x3, SVD
26  @ingroup g_examples
27  @brief Example for singular value decomposition
28  @author woelk 07/2004
29 */
30 
31 #include <bias_config.h>
32 #include <MathAlgo/SVD.hh>
33 #include <MathAlgo/SVD3x3.hh>
34 #include <Base/Math/Random.hh>
35 #include <Base/Math/Matrix3x3.hh>
36 #include <Base/Debug/TimeMeasure.hh>
37 
38 using namespace BIAS;
39 using namespace std;
40 
41 #define MAX_PRINT_SIZE 8
42 
43 int main(int argc, char **argv)
44 {
45  int size = 3;
46  if (argc > 1) {
47  size = atoi(argv[1]);
48  }
49  bool useOpenCV = false;
50  if (argc > 2)
51  useOpenCV = (atoi(argv[2]) != 0);
52  if (size < 1) {
53  cout << "Usage : ExampleSVD [<matrix size>] [<use OpenCV?>]" << endl << endl;
54  return 0;
55  }
56 
57  if (useOpenCV) {
58 #ifdef BIAS_HAVE_OPENCV
59  cout << endl << "Using OpenCV singular value decomposition" << endl;
60 #else
61  cout << "BIAS does not support OpenCV, using LAPACK SVD instead" << endl;
62  useOpenCV = false;
63 #endif
64  } else {
65  cout << endl << "Using LAPACK singular value decomposition" << endl;
66  }
67  double errorThreshold = 1e-6 * size * size;
68 
69  // 1.) Compute SVD for random NxN matrix
70 
71  cout << endl << "1.) Compute SVD for random " << size << "x" << size << " matrix" << endl;
72 
73  Random rand;
74  Matrix<double> M(size, size, MatrixZero);
75  SVD svd;
76  SVD3x3 svd3x3;
77  TimeMeasure timer, timer3x3;
78 
79  for (int i = 0; i < size; i++)
80  for (int j = 0; j < size; j++)
81  M[i][j] = rand.GetUniformDistributed(-10.0, 10.0);
82  if (size <= MAX_PRINT_SIZE)
83  M.PrintPretty(cout, "M");
84 
85  int numRepeats = 100;
86  if (size >= 200)
87  numRepeats = 1;
88  else if (size >= 100)
89  numRepeats = 10;
90  if (size == 3) {
91  timer3x3.Start();
92  for (int k = 0; k < numRepeats; k++)
93  svd3x3.Compute(M);
94  timer3x3.Stop();
95  }
96  timer.Start();
97  for (int k = 0; k < numRepeats; k++)
98 #ifdef BIAS_HAVE_OPENCV
99  if (useOpenCV)
100  svd.ComputeOpenCV(M);
101  else
102  svd.Compute(M);
103 #else
104  svd.Compute(M);
105 #endif
106  timer.Stop();
107 
108  if (size <= MAX_PRINT_SIZE)
109  svd.GetU().PrintPretty(cout, "SVD U");
110  if (size == 3) {
111  svd3x3.GetU().PrintPretty(cout, "SVD3x3 U");
112  Matrix<double> dU(svd.GetU() - svd3x3.GetU());
113  dU.PrintPretty(cout, "diff. U ");
114  }
115 
116  if (size <= MAX_PRINT_SIZE)
117  cout << endl << "SVD S = " << svd.GetS() << endl;
118  if (size == 3) {
119  Vector<double> dS(svd.GetS() - svd3x3.GetS());
120  cout << endl << "SVD3x3 S = " << svd3x3.GetS() << endl
121  << endl << "diff. S = " << dS << endl;
122  }
123 
124  if (size <= MAX_PRINT_SIZE)
125  svd.GetVT().PrintPretty(cout, "SVD VT");
126  if (size == 3) {
127  svd3x3.GetVT().PrintPretty(cout, "SVD3x3 VT");
128  Matrix<double> dVT(svd.GetVT() - svd3x3.GetVT());
129  dVT.PrintPretty(cout, "diff. VT");
130  }
131 
132  Matrix<double> S(size, size, MatrixZero);
133  for (int i = 0; i < size; i++)
134  S[i][i] = svd.GetS()[i];
135  Matrix<double> dM = M - svd.GetU() * S * svd.GetVT();
136  cout << endl << "SVD |M - U*S*VT| = " << dM.NormL2() << endl;
137  if (dM.NormL2() > errorThreshold) {
138  BIASERR("SVD failed!");
139  dM.PrintPretty(cout, "M - U*S*VT");
140  }
141  if (size == 3) {
142  for (int i = 0; i < size; i++)
143  S[i][i] = svd3x3.GetS()[i];
144  dM = M - svd3x3.GetU() * S * svd3x3.GetVT();
145  cout << endl << "SVD3x3 |M - U*S*VT| = " << dM.NormL2() << endl;
146  if (dM.NormL2() > errorThreshold) {
147  BIASERR("SVD3x3 failed!");
148  if (size <= MAX_PRINT_SIZE)
149  dM.PrintPretty(cout, "M - U*S*VT");
150  }
151  }
152 
153  cout << endl << "SVD time = " << (0.001 * timer.GetRealTime()) / numRepeats << " ms";
154  if (size == 3) {
155  cout << endl << "SVD3x3 time = " << (0.001 * timer3x3.GetRealTime()) / numRepeats << " ms";
156  }
157 
158  // 2.) Invert matrix with SVD
159 
160  cout << endl << endl << "2.) Invert matrix with SVD" << endl;
161 
162  Matrix<double> I(size, size, MatrixIdentity);
163  Matrix<double> invM;
164 #ifdef BIAS_HAVE_OPENCV
165  if (useOpenCV)
166  invM = svd.InvertOpenCV(M);
167  else
168  invM = svd.Invert(M);
169 #else
170  invM = svd.Invert(M);
171 #endif
172  dM = M * invM - I;
173  cout << endl << "SVD |M*inv(M) - I| = " << dM.NormL2() << endl;
174  if (dM.NormL2() > errorThreshold) {
175  BIASERR("Matrix inversion with SVD failed!");
176  if (size <= MAX_PRINT_SIZE)
177  dM.PrintPretty(cout, "M*inv(M) - I");
178  }
179  if (size == 3) {
180  invM = svd3x3.Invert();
181  dM = M * invM - I;
182  cout << endl << "SVD3x3 |M*inv(M) - I| = " << dM.NormL2() << endl;
183  if (dM.NormL2() > errorThreshold) {
184  BIASERR("Matrix inversion with SVD3x3 failed!");
185  dM.PrintPretty(cout, "M*inv(M) - I");
186  }
187  }
188 
189  // 3.) Compute matrix square root with SVD
190 
191  cout << endl << endl << "3.) Compute matrix square root with SVD" << endl;
192 
193  Matrix<double> MTM = M.Transpose() * M;
194  if (size <= MAX_PRINT_SIZE)
195  MTM.PrintPretty(cout, "MT*M");
196 
197  Matrix<double> sqrtMTM = svd.Sqrt(MTM);
198  if (size <= MAX_PRINT_SIZE)
199  sqrtMTM.PrintPretty(cout, "SVD sqrt(MT*M)");
200  dM = MTM - (sqrtMTM * sqrtMTM);
201  cout << endl << "SVD |MT*M - sqrt(MT*M)^2| = " << dM.NormL2() << endl;
202  if (dM.NormL2() > errorThreshold) {
203  BIASERR("Matrix square root failed!");
204  if (size <= MAX_PRINT_SIZE)
205  dM.PrintPretty(cout, "MT*M - sqrt(MT*M)^2");
206  }
207  if (size == 3) {
208  sqrtMTM = svd3x3.Sqrt(MTM);
209  sqrtMTM.PrintPretty(cout, "SVD3x3 sqrt(MT*M)");
210  dM = MTM - (sqrtMTM * sqrtMTM);
211  cout << endl << "SVD3x3 |MT*M - sqrt(MT*M)^2| = " << dM.NormL2() << endl;
212  if (dM.NormL2() > errorThreshold) {
213  BIASERR("Matrix square root failed!");
214  dM.PrintPretty(cout, "MT*M - sqrt(MT*M)^2");
215  }
216  }
217  cout << endl;
218 
219  return 0;
220 }
221 
std::ostream & PrintPretty(std::ostream &s, const std::string &name="", const int width=8, const bool alignLeft=true) const
computes and holds the singular value decomposition of a rectangular (not necessarily quadratic) Matr...
Definition: SVD.hh:92
int Compute(const Matrix< double > &M, double ZeroThreshold=DEFAULT_DOUBLE_ZERO_THRESHOLD)
set a new matrix and compute its decomposition.
Definition: SVD3x3.cpp:68
int Compute(const Matrix< double > &M, double ZeroThreshold=DEFAULT_DOUBLE_ZERO_THRESHOLD)
set a new matrix and compute its decomposition.
Definition: SVD.cpp:102
double GetUniformDistributed(const double min, const double max)
on succesive calls return uniform distributed random variable between min and max ...
Definition: Random.hh:84
double NormL2() const
Return the L2 norm: a^2 + b^2 + c^2 + ...
Definition: Matrix.hh:878
Matrix< double > InvertOpenCV(const Matrix< double > &A)
Calculates new inverse with OpenCV cvInvert.
Definition: SVD.cpp:182
singular value decomposition for 3x3 matrices
Definition: SVD3x3.hh:74
const Matrix< double > & GetVT() const
return VT (=transposed(V))
Definition: SVD.hh:177
const Vector< double > & GetS() const
return S which is a vector of the singular values of A in descending order.
Definition: SVD.hh:167
double GetRealTime() const
return real time (=wall time clock) in usec JW For Win32: real-time is measured differently from user...
int ComputeOpenCV(const Matrix< double > &M, double ZeroThreshold=DEFAULT_DOUBLE_ZERO_THRESHOLD)
Use OpenCV for decomposition as Lapack frequently leads to crashes under windows. ...
Definition: SVD.cpp:51
const Matrix< double > & GetU() const
return U U is a m x m orthogonal matrix
Definition: SVD.hh:187
Matrix< double > Invert()
returns pseudoinverse of A = U * S * V^T A^+ = V * S^+ * U^T
Definition: SVD.cpp:214
Matrix< double > Sqrt()
returns the square root of a symmetric positive definite matrix M A = sqrt(M) = U * sqrt(S) * V_T...
Definition: SVD.cpp:276
class for producing random numbers from different distributions
Definition: Random.hh:51
class TimeMeasure contains functions for timing real time and cpu time.
Definition: TimeMeasure.hh:111