[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

singular_value_decomposition.hxx VIGRA

1 /************************************************************************/
2 /* */
3 /* Copyright 2007 by Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35 
36 
37 #ifndef VIGRA_SINGULAR_VALUE_DECOMPOSITION_HXX
38 #define VIGRA_SINGULAR_VALUE_DECOMPOSITION_HXX
39 
40 #include "matrix.hxx"
41 #include "array_vector.hxx"
42 
43 
44 namespace vigra
45 {
46 
47 namespace linalg
48 {
49 
50  /** Singular Value Decomposition.
51  \ingroup MatrixAlgebra
52 
53  For an m-by-n matrix \a A with m >= n, the singular value decomposition is
54  an m-by-n orthogonal matrix \a U, an n-by-n diagonal matrix S, and
55  an n-by-n orthogonal matrix \a V so that A = U*S*V'.
56 
57  To save memory, this functions stores the matrix \a S in a column vector of
58  appropriate length (a diagonal matrix can be obtained by <tt>diagonalMatrix(S)</tt>).
59  The singular values, sigma[k] = S(k, 0), are ordered so that
60  sigma[0] >= sigma[1] >= ... >= sigma[n-1].
61 
62  The singular value decomposition always exists, so this function will
63  never fail (except if the shapes of the argument matrices don't match).
64  The effective numerical rank of A is returned.
65 
66  (Adapted from JAMA, a Java Matrix Library, developed jointly
67  by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
68 
69  <b>\#include</b> <vigra/singular_value_decomposition.hxx> or<br>
70  <b>\#include</b> <vigra/linear_algebra.hxx><br>
71  Namespaces: vigra and vigra::linalg
72  */
73 template <class T, class C1, class C2, class C3, class C4>
74 unsigned int
77 {
78  typedef T Real;
79 
80  const MultiArrayIndex rows = rowCount(A);
81  const MultiArrayIndex cols = columnCount(A);
82  vigra_precondition(rows >= cols,
83  "singularValueDecomposition(): Input matrix A must be rectangular with rowCount >= columnCount.");
84  vigra_precondition(rowCount(S) == cols && columnCount(S) == 1,
85  "singularValueDecomposition(): Output S must be column vector with rowCount == columnCount(A).");
86  vigra_precondition(rowCount(U) == rows && columnCount(U) == cols,
87  "singularValueDecomposition(): Output matrix U must have the same dimensions as input matrix A.");
88  vigra_precondition(rowCount(V) == cols && columnCount(V) == cols,
89  "singularValueDecomposition(): Output matrix V must be square with n = columnCount(A).");
90 
91  MultiArrayIndex m = rows;
92  MultiArrayIndex n = cols;
93  MultiArrayIndex nu = n;
94 
95  U.init(0.0);
96  S.init(0.0);
97  V.init(0.0);
98 
99  ArrayVector<Real> e(static_cast<unsigned int>(n));
100  ArrayVector<Real> work(static_cast<unsigned int>(m));
101  Matrix<Real> a(A);
103 
104  MultiArrayIndex i=0, j=0, k=0;
105 
106  // Reduce a to bidiagonal form, storing the diagonal elements
107  // in s and the super-diagonal elements in e.
108  MultiArrayIndex nct = std::min(m-1,n);
109  MultiArrayIndex nrt = std::max(static_cast<MultiArrayIndex>(0),n-2);
110  for (k = 0; k < std::max(nct,nrt); ++k)
111  {
112  if (k < nct)
113  {
114  // Compute the transformation for the k-th column and
115  // place the k-th diagonal in s(k).
116  // Compute 2-norm of k-th column without under/overflow.
117  s(k) = 0.0;
118  for (i = k; i < m; ++i)
119  {
120  s(k) = hypot(s(k), a(i, k));
121  }
122  if (s(k) != 0.0)
123  {
124  if (a(k, k) < 0.0)
125  {
126  s(k) = -s(k);
127  }
128  for (i = k; i < m; ++i)
129  {
130  a(i, k) /= s(k);
131  }
132  a(k, k) += 1.0;
133  }
134  s(k) = -s(k);
135  }
136  for (j = k+1; j < n; ++j)
137  {
138  if ((k < nct) && (s(k) != 0.0))
139  {
140  // Apply the transformation.
141  Real t(0.0);
142  for (i = k; i < m; ++i)
143  {
144  t += a(i, k)*a(i, j);
145  }
146  t = -t/a(k, k);
147  for (i = k; i < m; ++i)
148  {
149  a(i, j) += t*a(i, k);
150  }
151  }
152 
153  // Place the k-th row of a into e for the
154  // subsequent calculation of the row transformation.
155 
156  e[j] = a(k, j);
157  }
158  if (k < nct)
159  {
160  // Place the transformation in U for subsequent back
161  // multiplication.
162 
163  for (i = k; i < m; ++i)
164  {
165  U(i, k) = a(i, k);
166  }
167  }
168  if (k < nrt)
169  {
170  // Compute the k-th row transformation and place the
171  // k-th super-diagonal in e[k].
172  // Compute 2-norm without under/overflow.
173  e[k] = 0;
174  for (i = k+1; i < n; ++i)
175  {
176  e[k] = hypot(e[k],e[i]);
177  }
178  if (e[k] != 0.0)
179  {
180  if (e[k+1] < 0.0)
181  {
182  e[k] = -e[k];
183  }
184  for (i = k+1; i < n; ++i)
185  {
186  e[i] /= e[k];
187  }
188  e[k+1] += 1.0;
189  }
190  e[k] = -e[k];
191  if ((k+1 < m) & (e[k] != 0.0))
192  {
193  // Apply the transformation.
194  for (i = k+1; i < m; ++i)
195  {
196  work[i] = 0.0;
197  }
198  for (j = k+1; j < n; ++j)
199  {
200  for (i = k+1; i < m; ++i)
201  {
202  work[i] += e[j]*a(i, j);
203  }
204  }
205  for (j = k+1; j < n; ++j)
206  {
207  Real t(-e[j]/e[k+1]);
208  for (i = k+1; i < m; ++i)
209  {
210  a(i, j) += t*work[i];
211  }
212  }
213  }
214  // Place the transformation in V for subsequent
215  // back multiplication.
216  for (i = k+1; i < n; ++i)
217  {
218  V(i, k) = e[i];
219  }
220  }
221  }
222 
223  // Set up the final bidiagonal matrix of order p.
224 
225  MultiArrayIndex p = n;
226  if (nct < n)
227  {
228  s(nct) = a(nct, nct);
229  }
230  if (m < p)
231  {
232  s(p-1) = 0.0;
233  }
234  if (nrt+1 < p)
235  {
236  e[nrt] = a(nrt, p-1);
237  }
238  e[p-1] = 0.0;
239 
240  // Generate U.
241  for (j = nct; j < nu; ++j)
242  {
243  for (i = 0; i < m; ++i)
244  {
245  U(i, j) = 0.0;
246  }
247  U(j, j) = 1.0;
248  }
249  for (k = nct-1; k >= 0; --k)
250  {
251  if (s(k) != 0.0)
252  {
253  for (j = k+1; j < nu; ++j)
254  {
255  Real t(0.0);
256  for (i = k; i < m; ++i)
257  {
258  t += U(i, k)*U(i, j);
259  }
260  t = -t/U(k, k);
261  for (i = k; i < m; ++i)
262  {
263  U(i, j) += t*U(i, k);
264  }
265  }
266  for (i = k; i < m; ++i )
267  {
268  U(i, k) = -U(i, k);
269  }
270  U(k, k) = 1.0 + U(k, k);
271  for (i = 0; i < k-1; ++i)
272  {
273  U(i, k) = 0.0;
274  }
275  }
276  else
277  {
278  for (i = 0; i < m; ++i)
279  {
280  U(i, k) = 0.0;
281  }
282  U(k, k) = 1.0;
283  }
284  }
285 
286  // Generate V.
287  for (k = n-1; k >= 0; --k)
288  {
289  if ((k < nrt) & (e[k] != 0.0))
290  {
291  for (j = k+1; j < nu; ++j)
292  {
293  Real t(0.0);
294  for (i = k+1; i < n; ++i)
295  {
296  t += V(i, k)*V(i, j);
297  }
298  t = -t/V(k+1, k);
299  for (i = k+1; i < n; ++i)
300  {
301  V(i, j) += t*V(i, k);
302  }
303  }
304  }
305  for (i = 0; i < n; ++i)
306  {
307  V(i, k) = 0.0;
308  }
309  V(k, k) = 1.0;
310  }
311 
312  // Main iteration loop for the singular values.
313 
314  MultiArrayIndex pp = p-1;
315  int iter = 0;
316  Real eps = NumericTraits<Real>::epsilon()*2.0;
317  while (p > 0)
318  {
319  k=0;
320  int kase=0;
321 
322  // Here is where a test for too many iterations would go.
323 
324  // This section of the program inspects for
325  // negligible elements in the s and e arrays. On
326  // completion the variables kase and k are set as follows.
327 
328  // kase = 1 if s(p) and e[k-1] are negligible and k<p
329  // kase = 2 if s(k) is negligible and k<p
330  // kase = 3 if e[k-1] is negligible, k<p, and
331  // s(k), ..., s(p) are not negligible (qr step).
332  // kase = 4 if e(p-1) is negligible (convergence).
333 
334  for (k = p-2; k >= -1; --k)
335  {
336  if (k == -1)
337  {
338  break;
339  }
340  if (abs(e[k]) <= eps*(abs(s(k)) + abs(s(k+1))))
341  {
342  e[k] = 0.0;
343  break;
344  }
345  }
346  if (k == p-2)
347  {
348  kase = 4;
349  }
350  else
351  {
352  MultiArrayIndex ks;
353  for (ks = p-1; ks >= k; --ks)
354  {
355  if (ks == k)
356  {
357  break;
358  }
359  Real t( (ks != p ? abs(e[ks]) : 0.) +
360  (ks != k+1 ? abs(e[ks-1]) : 0.));
361  if (abs(s(ks)) <= eps*t)
362  {
363  s(ks) = 0.0;
364  break;
365  }
366  }
367  if (ks == k)
368  {
369  kase = 3;
370  }
371  else if (ks == p-1)
372  {
373  kase = 1;
374  }
375  else
376  {
377  kase = 2;
378  k = ks;
379  }
380  }
381  ++k;
382 
383  // Perform the task indicated by kase.
384 
385  switch (kase)
386  {
387  case 1: // Deflate negligible s(p).
388  {
389  Real f(e[p-2]);
390  e[p-2] = 0.0;
391  for (j = p-2; j >= k; --j)
392  {
393  Real t( hypot(s(j),f));
394  Real cs(s(j)/t);
395  Real sn(f/t);
396  s(j) = t;
397  if (j != k)
398  {
399  f = -sn*e[j-1];
400  e[j-1] = cs*e[j-1];
401  }
402  for (i = 0; i < n; ++i)
403  {
404  t = cs*V(i, j) + sn*V(i, p-1);
405  V(i, p-1) = -sn*V(i, j) + cs*V(i, p-1);
406  V(i, j) = t;
407  }
408  }
409  break;
410  }
411  case 2: // Split at negligible s(k).
412  {
413  Real f(e[k-1]);
414  e[k-1] = 0.0;
415  for (j = k; j < p; ++j)
416  {
417  Real t(hypot(s(j),f));
418  Real cs( s(j)/t);
419  Real sn(f/t);
420  s(j) = t;
421  f = -sn*e[j];
422  e[j] = cs*e[j];
423  for (i = 0; i < m; ++i)
424  {
425  t = cs*U(i, j) + sn*U(i, k-1);
426  U(i, k-1) = -sn*U(i, j) + cs*U(i, k-1);
427  U(i, j) = t;
428  }
429  }
430  break;
431  }
432  case 3: // Perform one qr step.
433  {
434  // Calculate the shift.
435  Real scale = std::max(std::max(std::max(std::max(
436  abs(s(p-1)),abs(s(p-2))),abs(e[p-2])),
437  abs(s(k))),abs(e[k]));
438  Real sp = s(p-1)/scale;
439  Real spm1 = s(p-2)/scale;
440  Real epm1 = e[p-2]/scale;
441  Real sk = s(k)/scale;
442  Real ek = e[k]/scale;
443  Real b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
444  Real c = (sp*epm1)*(sp*epm1);
445  Real shift = 0.0;
446  if ((b != 0.0) || (c != 0.0))
447  {
448  shift = VIGRA_CSTD::sqrt(b*b + c);
449  if (b < 0.0)
450  {
451  shift = -shift;
452  }
453  shift = c/(b + shift);
454  }
455  Real f = (sk + sp)*(sk - sp) + shift;
456  Real g = sk*ek;
457 
458  // Chase zeros.
459  for (j = k; j < p-1; ++j)
460  {
461  Real t = hypot(f,g);
462  Real cs = f/t;
463  Real sn = g/t;
464  if (j != k)
465  {
466  e[j-1] = t;
467  }
468  f = cs*s(j) + sn*e[j];
469  e[j] = cs*e[j] - sn*s(j);
470  g = sn*s(j+1);
471  s(j+1) = cs*s(j+1);
472  for (i = 0; i < n; ++i)
473  {
474  t = cs*V(i, j) + sn*V(i, j+1);
475  V(i, j+1) = -sn*V(i, j) + cs*V(i, j+1);
476  V(i, j) = t;
477  }
478  t = hypot(f,g);
479  cs = f/t;
480  sn = g/t;
481  s(j) = t;
482  f = cs*e[j] + sn*s(j+1);
483  s(j+1) = -sn*e[j] + cs*s(j+1);
484  g = sn*e[j+1];
485  e[j+1] = cs*e[j+1];
486  if (j < m-1)
487  {
488  for (i = 0; i < m; ++i)
489  {
490  t = cs*U(i, j) + sn*U(i, j+1);
491  U(i, j+1) = -sn*U(i, j) + cs*U(i, j+1);
492  U(i, j) = t;
493  }
494  }
495  }
496  e[p-2] = f;
497  iter = iter + 1;
498  break;
499  }
500  case 4: // Convergence.
501  {
502  // Make the singular values positive.
503  if (s(k) <= 0.0)
504  {
505  s(k) = (s(k) < 0.0 ? -s(k) : 0.0);
506  for (i = 0; i <= pp; ++i)
507  {
508  V(i, k) = -V(i, k);
509  }
510  }
511 
512  // Order the singular values.
513 
514  while (k < pp)
515  {
516  if (s(k) >= s(k+1))
517  {
518  break;
519  }
520  Real t = s(k);
521  s(k) = s(k+1);
522  s(k+1) = t;
523  if (k < n-1)
524  {
525  for (i = 0; i < n; ++i)
526  {
527  t = V(i, k+1); V(i, k+1) = V(i, k); V(i, k) = t;
528  }
529  }
530  if (k < m-1)
531  {
532  for (i = 0; i < m; ++i)
533  {
534  t = U(i, k+1); U(i, k+1) = U(i, k); U(i, k) = t;
535  }
536  }
537  ++k;
538  }
539  iter = 0;
540  --p;
541  break;
542  }
543  default:
544  vigra_fail("vigra::svd(): Internal error.");
545  }
546  }
547  Real tol = std::max(m,n)*s(0)*eps;
548  unsigned int rank = 0;
549  for (i = 0; i < n; ++i)
550  {
551  if (s(i) > tol)
552  {
553  ++rank;
554  }
555  }
556  return rank; // effective rank
557 }
558 
559 } // namespace linalg
560 
562 
563 } // namespace vigra
564 
565 #endif // VIGRA_SINGULAR_VALUE_DECOMPOSITION_HXX
MultiArrayIndex rowCount(const MultiArrayView< 2, T, C > &x)
Definition: matrix.hxx:671
Definition: matrix.hxx:123
std::ptrdiff_t MultiArrayIndex
Definition: multi_fwd.hxx:60
FixedPoint16< IntBits, OverflowHandling > hypot(FixedPoint16< IntBits, OverflowHandling > v1, FixedPoint16< IntBits, OverflowHandling > v2)
Length of hypotenuse.
Definition: fixedpoint.hxx:1640
Definition: array_vector.hxx:58
MultiArrayIndex columnCount(const MultiArrayView< 2, T, C > &x)
Definition: matrix.hxx:684
MultiArrayView & init(const U &init)
Definition: multi_array.hxx:1206
unsigned int singularValueDecomposition(MultiArrayView< 2, T, C1 > const &A, MultiArrayView< 2, T, C2 > &U, MultiArrayView< 2, T, C3 > &S, MultiArrayView< 2, T, C4 > &V)
Definition: singular_value_decomposition.hxx:75
linalg::TemporaryMatrix< T > abs(MultiArrayView< 2, T, C > const &v)
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition: fixedpoint.hxx:616
MultiArrayView< N-M, T, StrideTag > bindOuter(const TinyVector< Index, M > &d) const
Definition: multi_array.hxx:2184

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.11.1 (Fri May 19 2017)