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

singular_value_decomposition.hxx |

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
75 singularValueDecomposition(MultiArrayView<2, T, C1> const & A,
76 MultiArrayView<2, T, C2> &U, MultiArrayView<2, T, C3> &S, MultiArrayView<2, T, C4> &V)
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);
102 MultiArrayView<1, T, C3> s = S.bindOuter(0);
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
561 using linalg::singularValueDecomposition;
562
563 } // namespace vigra
564
565 #endif // VIGRA_SINGULAR_VALUE_DECOMPOSITION_HXX
vigra::linalg::rowCount
MultiArrayIndex rowCount(const MultiArrayView< 2, T, C > &x)
Definition: matrix.hxx:671
vigra::linalg::Matrix
Definition: matrix.hxx:123
vigra::MultiArrayIndex
std::ptrdiff_t MultiArrayIndex
Definition: multi_fwd.hxx:60
vigra::hypot
FixedPoint16< IntBits, OverflowHandling > hypot(FixedPoint16< IntBits, OverflowHandling > v1, FixedPoint16< IntBits, OverflowHandling > v2)
Length of hypotenuse.
Definition: fixedpoint.hxx:1640
vigra::ArrayVector
Definition: array_vector.hxx:58
vigra::linalg::columnCount
MultiArrayIndex columnCount(const MultiArrayView< 2, T, C > &x)
Definition: matrix.hxx:684
vigra::MultiArrayView< 2, T, C1 >
vigra::MultiArrayView::init
MultiArrayView & init(const U &init)
Definition: multi_array.hxx:1206
vigra::linalg::singularValueDecomposition
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
vigra::linalg::abs
linalg::TemporaryMatrix< T > abs(MultiArrayView< 2, T, C > const &v)
vigra::sqrt
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition: fixedpoint.hxx:616
vigra::MultiArrayView::bindOuter
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.0 (Fri May 19 2017)