TooN
GR_SVD.h
1 // -*- c++ -*-
2 
3 // Copyright (C) 2009 Georg Klein (gk@robots.ox.ac.uk)
4 
5 //All rights reserved.
6 //
7 //Redistribution and use in source and binary forms, with or without
8 //modification, are permitted provided that the following conditions
9 //are met:
10 //1. Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 //2. Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
15 //
16 //THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
17 //AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 //IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 //ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
20 //LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 //CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 //SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 //INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 //CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 //ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 //POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef __GR_SVD_H
29 #define __GR_SVD_H
30 
31 #include <TooN/TooN.h>
32 #include <cmath>
33 #include <vector>
34 #include <algorithm>
35 
36 namespace TooN
37 {
38 
57  template<int M, int N = M, class Precision = DefaultPrecision, bool WANT_U = 1, bool WANT_V = 1>
58  class GR_SVD
59  {
60  public:
61 
62  template<class Precision2, class Base> GR_SVD(const Matrix<M, N, Precision2, Base> &A);
63 
64  static const int BigDim = M>N?M:N;
65  static const int SmallDim = M<N?M:N;
66 
67  const Matrix<M,N,Precision>& get_U() { if(!WANT_U) throw(0); return mU;}
68  const Matrix<N,N,Precision>& get_V() { if(!WANT_V) throw(0); return mV;}
69  const Vector<N, Precision>& get_diagonal() {return vDiagonal;}
70 
71  Precision get_largest_singular_value();
72  Precision get_smallest_singular_value();
73  int get_smallest_singular_value_index();
74 
80  void get_inv_diag(Vector<N>& inv_diag, const Precision condition)
81  {
82  Precision dMax = get_largest_singular_value();
83  for(int i=0; i<N; ++i)
84  inv_diag[i] = (vDiagonal[i] * condition > dMax) ?
85  static_cast<Precision>(1)/vDiagonal[i] : 0;
86  }
87 
92  template <int Rows2, int Cols2, typename P2, typename B2>
94  backsub(const Matrix<Rows2,Cols2,P2,B2>& rhs, const Precision condition=1e9)
95  {
96  Vector<N,Precision> inv_diag;
97  get_inv_diag(inv_diag,condition);
98  return (get_V() * diagmult(inv_diag, (get_U().T() * rhs)));
99  }
100 
105  template <int Size, typename P2, typename B2>
107  backsub(const Vector<Size,P2,B2>& rhs, const Precision condition=1e9)
108  {
109  Vector<N,Precision> inv_diag;
110  get_inv_diag(inv_diag,condition);
111  return (get_V() * diagmult(inv_diag, (get_U().T() * rhs)));
112  }
113 
115  Matrix<N,M,Precision> get_pinv(const Precision condition=1e9)
116  {
117  Vector<N,Precision> inv_diag(N);
118  get_inv_diag(inv_diag,condition);
119  return diagmult(get_V(),inv_diag) * get_U().T();
120  }
121 
123  void reorder();
124 
125  protected:
126  void Bidiagonalize();
127  void Accumulate_RHS();
128  void Accumulate_LHS();
129  void Diagonalize();
130  bool Diagonalize_SubLoop(int k, Precision &z);
131 
132  Vector<N,Precision> vDiagonal;
133  Vector<BigDim, Precision> vOffDiagonal;
136 
137  int nError;
138  int nIterations;
139  Precision anorm;
140  };
141 
142 
143 
144  template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
145  template<class Precision2, class Base>
147  {
148  nError = 0;
149  mU = mA;
150  Bidiagonalize();
151  Accumulate_RHS();
152  Accumulate_LHS();
153  Diagonalize();
154  };
155 
156  template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
158  {
159  using std::abs;
160  using std::max;
161  using std::sqrt;
162  // ------------ Householder reduction to bidiagonal form
163  Precision g = 0.0;
164  Precision scale = 0.0;
165  anorm = 0.0;
166  for(int i=0; i<N; ++i) // 300
167  {
168  const int l = i+1;
169  vOffDiagonal[i] = scale * g;
170  g = 0.0;
171  Precision s = 0.0;
172  scale = 0.0;
173  if( i < M )
174  {
175  for(int k=i; k<M; ++k)
176  scale += abs(mU[k][i]);
177  if(scale != 0.0)
178  {
179  for(int k=i; k<M; ++k)
180  {
181  mU[k][i] /= scale;
182  s += mU[k][i] * mU[k][i];
183  }
184  Precision f = mU[i][i];
185  g = -(f>=0?sqrt(s):-sqrt(s));
186  Precision h = f * g - s;
187  mU[i][i] = f - g;
188  if(i!=(N-1))
189  {
190  for(int j=l; j<N; ++j)
191  {
192  s = 0.0;
193  for(int k=i; k<M; ++k)
194  s += mU[k][i] * mU[k][j];
195  f = s / h;
196  for(int k=i; k<M; ++k)
197  mU[k][j] += f * mU[k][i];
198  } // 150
199  }// 190
200  for(int k=i; k<M; ++k)
201  mU[k][i] *= scale;
202  } // 210
203  } // 210
204  vDiagonal[i] = scale * g;
205  g = 0.0;
206  s = 0.0;
207  scale = 0.0;
208  if(!(i >= M || i == (N-1)))
209  {
210  for(int k=l; k<N; ++k)
211  scale += abs(mU[i][k]);
212  if(scale != 0.0)
213  {
214  for(int k=l; k<N; k++)
215  {
216  mU[i][k] /= scale;
217  s += mU[i][k] * mU[i][k];
218  }
219  Precision f = mU[i][l];
220  g = -(f>=0?sqrt(s):-sqrt(s));
221  Precision h = f * g - s;
222  mU[i][l] = f - g;
223  for(int k=l; k<N; ++k)
224  vOffDiagonal[k] = mU[i][k] / h;
225  if(i != (M-1)) // 270
226  {
227  for(int j=l; j<M; ++j)
228  {
229  s = 0.0;
230  for(int k=l; k<N; ++k)
231  s += mU[j][k] * mU[i][k];
232  for(int k=l; k<N; ++k)
233  mU[j][k] += s * vOffDiagonal[k];
234  } // 260
235  } // 270
236  for(int k=l; k<N; ++k)
237  mU[i][k] *= scale;
238  } // 290
239  } // 290
240  anorm = max(anorm, abs(vDiagonal[i]) + abs(vOffDiagonal[i]));
241  } // 300
242 
243  // Accumulation of right-hand transformations
244  }
245 
246  template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
248  {
249  // Get rid of fakey loop over ii, do a loop over i directly
250  // This here would happen on the first run of the loop with
251  // i = N-1
252  mV[N-1][N-1] = static_cast<Precision>(1);
253  Precision g = vOffDiagonal[N-1];
254 
255  // The loop
256  for(int i=N-2; i>=0; --i) // 400
257  {
258  const int l = i + 1;
259  if( g!=0) // 360
260  {
261  for(int j=l; j<N; ++j)
262  mV[j][i] = (mU[i][j] / mU[i][l]) / g; // double division avoids possible underflow
263  for(int j=l; j<N; ++j)
264  { // 350
265  Precision s = 0;
266  for(int k=l; k<N; ++k)
267  s += mU[i][k] * mV[k][j];
268  for(int k=l; k<N; ++k)
269  mV[k][j] += s * mV[k][i];
270  } // 350
271  } // 360
272  for(int j=l; j<N; ++j)
273  mV[i][j] = mV[j][i] = 0;
274  mV[i][i] = static_cast<Precision>(1);
275  g = vOffDiagonal[i];
276  } // 400
277  }
278 
279  template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
281  {
282  // Same thing; remove loop over dummy ii and do straight over i
283  // Some implementations start from N here
284  for(int i=SmallDim-1; i>=0; --i)
285  { // 500
286  const int l = i+1;
287  Precision g = vDiagonal[i];
288  // SqSVD here uses i<N ?
289  if(i != (N-1))
290  for(int j=l; j<N; ++j)
291  mU[i][j] = 0.0;
292  if(g == 0.0)
293  for(int j=i; j<M; ++j)
294  mU[j][i] = 0.0;
295  else
296  { // 475
297  // Can pre-divide g here
298  Precision inv_g = static_cast<Precision>(1) / g;
299  if(i != (SmallDim-1))
300  { // 460
301  for(int j=l; j<N; ++j)
302  { // 450
303  Precision s = 0;
304  for(int k=l; k<M; ++k)
305  s += mU[k][i] * mU[k][j];
306  Precision f = (s / mU[i][i]) * inv_g; // double division
307  for(int k=i; k<M; ++k)
308  mU[k][j] += f * mU[k][i];
309  } // 450
310  } // 460
311  for(int j=i; j<M; ++j)
312  mU[j][i] *= inv_g;
313  } // 475
314  mU[i][i] += static_cast<Precision>(1);
315  } // 500
316  }
317 
318  template<int M, int N, class Precision,bool WANT_U, bool WANT_V>
320  {
321  // Loop directly over descending k
322  for(int k=N-1; k>=0; --k)
323  { // 700
324  nIterations = 0;
325  Precision z;
326  bool bConverged_Or_Error = false;
327  do
328  bConverged_Or_Error = Diagonalize_SubLoop(k, z);
329  while(!bConverged_Or_Error);
330 
331  if(nError)
332  return;
333 
334  if(z < 0)
335  {
336  vDiagonal[k] = -z;
337  if(WANT_V)
338  for(int j=0; j<N; ++j)
339  mV[j][k] = -mV[j][k];
340  }
341  } // 700
342  };
343 
344 
345  template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
347  {
348  using std::abs;
349  using std::sqrt;
350  const int k1 = k-1;
351  // 520 is here!
352  for(int l=k; l>=0; --l)
353  { // 530
354  const int l1 = l-1;
355  if((abs(vOffDiagonal[l]) + anorm) == anorm)
356  goto line_565;
357  if((abs(vDiagonal[l1]) + anorm) == anorm)
358  goto line_540;
359  continue;
360 
361  line_540:
362  {
363  Precision c = 0;
364  Precision s = 1.0;
365  for(int i=l; i<=k; ++i)
366  { // 560
367  Precision f = s * vOffDiagonal[i];
368  vOffDiagonal[i] *= c;
369  if((abs(f) + anorm) == anorm)
370  break; // goto 565, effectively
371  Precision g = vDiagonal[i];
372  Precision h = sqrt(f * f + g * g); // Other implementations do this bit better
373  vDiagonal[i] = h;
374  c = g / h;
375  s = -f / h;
376  if(WANT_U)
377  for(int j=0; j<M; ++j)
378  {
379  Precision y = mU[j][l1];
380  Precision z = mU[j][i];
381  mU[j][l1] = y*c + z*s;
382  mU[j][i] = -y*s + z*c;
383  }
384  } // 560
385  }
386 
387  line_565:
388  {
389  // Check for convergence..
390  z = vDiagonal[k];
391  if(l == k)
392  return true; // convergence.
393  if(nIterations == 30)
394  {
395  nError = k;
396  return true;
397  }
398  ++nIterations;
399  Precision x = vDiagonal[l];
400  Precision y = vDiagonal[k1];
401  Precision g = vOffDiagonal[k1];
402  Precision h = vOffDiagonal[k];
403  Precision f = ((y-z)*(y+z) + (g-h)*(g+h)) / (2.0*h*y);
404  g = sqrt(f*f + 1.0);
405  Precision signed_g = (f>=0)?g:-g;
406  f = ((x-z)*(x+z) + h*(y/(f + signed_g) - h)) / x;
407 
408  // Next QR transformation
409  Precision c = 1.0;
410  Precision s = 1.0;
411  for(int i1 = l; i1<=k1; ++i1)
412  { // 600
413  const int i=i1+1;
414  g = vOffDiagonal[i];
415  y = vDiagonal[i];
416  h = s*g;
417  g = c*g;
418  z = sqrt(f*f + h*h);
419  vOffDiagonal[i1] = z;
420  c = f/z;
421  s = h/z;
422  f = x*c + g*s;
423  g = -x*s + g*c;
424  h = y*s;
425  y *= c;
426  if(WANT_V)
427  for(int j=0; j<N; ++j)
428  {
429  Precision xx = mV[j][i1];
430  Precision zz = mV[j][i];
431  mV[j][i1] = xx*c + zz*s;
432  mV[j][i] = -xx*s + zz*c;
433  }
434  z = sqrt(f*f + h*h);
435  vDiagonal[i1] = z;
436  if(z!=0)
437  {
438  c = f/z;
439  s = h/z;
440  }
441  f = c*g + s*y;
442  x = -s*g + c*y;
443  if(WANT_U)
444  for(int j=0; j<M; ++j)
445  {
446  Precision yy = mU[j][i1];
447  Precision zz = mU[j][i];
448  mU[j][i1] = yy*c + zz*s;
449  mU[j][i] = -yy*s + zz*c;
450  }
451  } // 600
452  vOffDiagonal[l] = 0;
453  vOffDiagonal[k] = f;
454  vDiagonal[k] = x;
455  return false;
456  // EO IF NOT CONVERGED CHUNK
457  } // EO IF TESTS HOLD
458  } // 530
459  // Code should never get here!
460  throw(0);
461  //return false;
462  }
463 
464 
465  template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
467  {
468  using std::max;
469  Precision d = vDiagonal[0];
470  for(int i=1; i<N; ++i) d = max(d, vDiagonal[i]);
471  return d;
472  }
473 
474  template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
476  {
477  using std::min;
478  Precision d = vDiagonal[0];
479  for(int i=1; i<N; ++i) d = min(d, vDiagonal[i]);
480  return d;
481  }
482 
483  template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
485  {
486  using std::min;
487  int nMin=0;
488  Precision d = vDiagonal[0];
489  for(int i=1; i<N; ++i)
490  if(vDiagonal[i] < d)
491  {
492  d = vDiagonal[i];
493  nMin = i;
494  }
495  return nMin;
496  }
497 
498  template<int M, int N, class Precision, bool WANT_U, bool WANT_V>
500  {
501  std::vector<std::pair<Precision, unsigned int> > vSort;
502  vSort.reserve(N);
503  for(unsigned int i=0; i<N; ++i)
504  vSort.push_back(std::make_pair(-vDiagonal[i], i));
505  std::sort(vSort.begin(), vSort.end());
506  for(unsigned int i=0; i<N; ++i)
507  vDiagonal[i] = -vSort[i].first;
508  if(WANT_U)
509  {
510  Matrix<M, N, Precision> mU_copy = mU;
511  for(unsigned int i=0; i<N; ++i)
512  mU.T()[i] = mU_copy.T()[vSort[i].second];
513  }
514  if(WANT_V)
515  {
516  Matrix<N, N, Precision> mV_copy = mV;
517  for(unsigned int i=0; i<N; ++i)
518  mV.T()[i] = mV_copy.T()[vSort[i].second];
519  }
520  }
521 
522 }
523 #endif
524 
525 
526 
527 
528 
529 
Vector< N, typename Internal::MultiplyType< Precision, P2 >::type > backsub(const Vector< Size, P2, B2 > &rhs, const Precision condition=1e9)
Calculate result of multiplying the (pseudo-)inverse of M by a vector.
Definition: GR_SVD.h:107
Pretty generic SFINAE introspection generator.
Definition: vec_test.cc:21
A matrix.
Definition: matrix.hh:105
Performs SVD and back substitute to solve equations.
Definition: GR_SVD.h:58
void get_inv_diag(Vector< N > &inv_diag, const Precision condition)
Return the pesudo-inverse diagonal.
Definition: GR_SVD.h:80
Matrix< N, Cols2, typename Internal::MultiplyType< Precision, P2 >::type > backsub(const Matrix< Rows2, Cols2, P2, B2 > &rhs, const Precision condition=1e9)
Calculate result of multiplying the (pseudo-)inverse of M by another matrix.
Definition: GR_SVD.h:94
Matrix< R, C, P > sqrt(const Matrix< R, C, P, B > &m)
computes a matrix square root of a matrix m by the product form of the Denman and Beavers iteration a...
Definition: helpers.h:350
void reorder()
Reorder the components so the singular values are in descending order.
Definition: GR_SVD.h:499
Matrix< N, M, Precision > get_pinv(const Precision condition=1e9)
Get the pseudo-inverse .
Definition: GR_SVD.h:115