1 /************************************************************************/
2 /*                                                                      */
3 /*                  Copyright 2004 by Ullrich Koethe                    */
4 /*       Cognitive Systems Group, University of Hamburg, Germany        */
5 /*                                                                      */
6 /*    This file is part of the VIGRA computer vision library.           */
7 /*    ( Version 1.5.0, Dec 07 2006 )                                    */
8 /*    The VIGRA Website is                                              */
9 /*        http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/      */
10 /*    Please direct questions, bug reports, and contributions to        */
11 /*        koethe@informatik.uni-hamburg.de          or                  */
12 /*        vigra@kogs1.informatik.uni-hamburg.de                         */
13 /*                                                                      */
14 /*    Permission is hereby granted, free of charge, to any person       */
15 /*    obtaining a copy of this software and associated documentation    */
16 /*    files (the "Software"), to deal in the Software without           */
17 /*    restriction, including without limitation the rights to use,      */
18 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
19 /*    sell copies of the Software, and to permit persons to whom the    */
20 /*    Software is furnished to do so, subject to the following          */
21 /*    conditions:                                                       */
22 /*                                                                      */
23 /*    The above copyright notice and this permission notice shall be    */
24 /*    included in all copies or substantial portions of the             */
25 /*    Software.                                                         */
26 /*                                                                      */
27 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
28 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
29 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
30 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
31 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
32 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
33 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
34 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */
35 /*                                                                      */
36 /************************************************************************/
37 
38 
39 #ifndef VIGRA_EIGENSYSTEM_HXX
40 #define VIGRA_EIGENSYSTEM_HXX
41 
42 #include <algorithm>
43 #include <complex>
44 #include "matrix.hxx"
45 #include "array_vector.hxx"
46 #include "polynomial.hxx"
47 
48 namespace vigra
49 {
50 
51 namespace linalg
52 {
53 
54 namespace detail
55 {
56 
57 // code adapted from JAMA
58 // a and b will be overwritten
59 template <class T, class C1, class C2>
60 void
housholderTridiagonalization(MultiArrayView<2,T,C1> & a,MultiArrayView<2,T,C2> & b)61 housholderTridiagonalization(MultiArrayView<2, T, C1> &a, MultiArrayView<2, T, C2> &b)
62 {
63     const unsigned int n = rowCount(a);
64     vigra_precondition(n == columnCount(a),
65         "housholderTridiagonalization(): matrix must be square.");
66     vigra_precondition(n == rowCount(b) && 2 <= columnCount(b),
67         "housholderTridiagonalization(): matrix size mismatch.");
68 
69     MultiArrayView<1, T, C2> d = b.bindOuter(0);
70     MultiArrayView<1, T, C2> e = b.bindOuter(1);
71 
72     for(unsigned int j = 0; j < n; ++j)
73     {
74         d(j) = a(n-1, j);
75     }
76 
77     // Householder reduction to tridiagonalMatrix form.
78 
79     for(int i = n-1; i > 0; --i)
80     {
81         // Scale to avoid under/overflow.
82 
83         T scale = 0.0;
84         T h = 0.0;
85         for(int k = 0; k < i; ++k)
86         {
87             scale = scale + abs(d(k));
88         }
89         if(scale == 0.0)
90         {
91             e(i) = d(i-1);
92             for(int j = 0; j < i; ++j)
93             {
94                 d(j) = a(i-1, j);
95                 a(i, j) = 0.0;
96                 a(j, i) = 0.0;
97             }
98         }
99         else
100         {
101             // Generate Householder vector.
102 
103             for(int k = 0; k < i; ++k)
104             {
105                 d(k) /= scale;
106                 h += sq(d(k));
107             }
108             T f = d(i-1);
109             T g = VIGRA_CSTD::sqrt(h);
110             if(f > 0) {
111                 g = -g;
112             }
113             e(i) = scale * g;
114             h -= f * g;
115             d(i-1) = f - g;
116             for(int j = 0; j < i; ++j)
117             {
118                e(j) = 0.0;
119             }
120 
121             // Apply similarity transformation to remaining columns.
122 
123             for(int j = 0; j < i; ++j)
124             {
125                f = d(j);
126                a(j, i) = f;
127                g = e(j) + a(j, j) * f;
128                for(int k = j+1; k <= i-1; ++k)
129                {
130                    g += a(k, j) * d(k);
131                    e(k) += a(k, j) * f;
132                }
133                e(j) = g;
134             }
135             f = 0.0;
136             for(int j = 0; j < i; ++j)
137             {
138                 e(j) /= h;
139                 f += e(j) * d(j);
140             }
141             T hh = f / (h + h);
142             for(int j = 0; j < i; ++j)
143             {
144                 e(j) -= hh * d(j);
145             }
146             for(int j = 0; j < i; ++j)
147             {
148                 f = d(j);
149                 g = e(j);
150                 for(int k = j; k <= i-1; ++k)
151                 {
152                     a(k, j) -= (f * e(k) + g * d(k));
153                 }
154                 d(j) = a(i-1, j);
155                 a(i, j) = 0.0;
156             }
157         }
158         d(i) = h;
159     }
160 
161     // Accumulate transformations.
162 
163     for(unsigned int i = 0; i < n-1; ++i)
164     {
165         a(n-1, i) = a(i, i);
166         a(i, i) = 1.0;
167         T h = d(i+1);
168         if(h != 0.0)
169         {
170             for(unsigned int k = 0; k <= i; ++k)
171             {
172                 d(k) = a(k, i+1) / h;
173             }
174             for(unsigned int j = 0; j <= i; ++j)
175             {
176                 T g = 0.0;
177                 for(unsigned int k = 0; k <= i; ++k)
178                 {
179                     g += a(k, i+1) * a(k, j);
180                 }
181                 for(unsigned int k = 0; k <= i; ++k)
182                 {
183                     a(k, j) -= g * d(k);
184                 }
185             }
186         }
187         for(unsigned int k = 0; k <= i; ++k)
188         {
189             a(k, i+1) = 0.0;
190         }
191     }
192     for(unsigned int j = 0; j < n; ++j)
193     {
194         d(j) = a(n-1, j);
195         a(n-1, j) = 0.0;
196     }
197     a(n-1, n-1) = 1.0;
198     e(0) = 0.0;
199 }
200 
201 // code adapted from JAMA
202 // de and z will be overwritten
203 template <class T, class C1, class C2>
204 bool
tridiagonalMatrixEigensystem(MultiArrayView<2,T,C1> & de,MultiArrayView<2,T,C2> & z)205 tridiagonalMatrixEigensystem(MultiArrayView<2, T, C1> &de, MultiArrayView<2, T, C2> &z)
206 {
207     const unsigned int n = rowCount(z);
208     vigra_precondition(n == columnCount(z),
209         "tridiagonalMatrixEigensystem(): matrix must be square.");
210     vigra_precondition(n == rowCount(de) && 2 <= columnCount(de),
211         "tridiagonalMatrixEigensystem(): matrix size mismatch.");
212 
213     MultiArrayView<1, T, C2> d = de.bindOuter(0);
214     MultiArrayView<1, T, C2> e = de.bindOuter(1);
215 
216     for(unsigned int i = 1; i < n; i++) {
217        e(i-1) = e(i);
218     }
219     e(n-1) = 0.0;
220 
221     T f = 0.0;
222     T tst1 = 0.0;
223     T eps = VIGRA_CSTD::pow(2.0,-52.0);
224     for(unsigned int l = 0; l < n; ++l)
225     {
226         // Find small subdiagonalMatrix element
227 
228         tst1 = std::max(tst1, abs(d(l)) + abs(e(l)));
229         unsigned int m = l;
230 
231         // Original while-loop from Java code
232         while(m < n)
233         {
234             if(abs(e(m)) <= eps*tst1)
235                 break;
236             ++m;
237         }
238 
239         // If m == l, d(l) is an eigenvalue,
240         // otherwise, iterate.
241 
242         if(m > l)
243         {
244             int iter = 0;
245             do
246             {
247                 if(++iter > 50)
248                    return false; // too many iterations
249 
250                 // Compute implicit shift
251 
252                 T g = d(l);
253                 T p = (d(l+1) - g) / (2.0 * e(l));
254                 T r = hypot(p,1.0);
255                 if(p < 0)
256                 {
257                     r = -r;
258                 }
259                 d(l) = e(l) / (p + r);
260                 d(l+1) = e(l) * (p + r);
261                 T dl1 = d(l+1);
262                 T h = g - d(l);
263                 for(unsigned int i = l+2; i < n; ++i)
264                 {
265                    d(i) -= h;
266                 }
267                 f = f + h;
268 
269                 // Implicit QL transformation.
270 
271                 p = d(m);
272                 T c = 1.0;
273                 T c2 = c;
274                 T c3 = c;
275                 T el1 = e(l+1);
276                 T s = 0.0;
277                 T s2 = 0.0;
278                 for(int i = m-1; i >= (int)l; --i)
279                 {
280                     c3 = c2;
281                     c2 = c;
282                     s2 = s;
283                     g = c * e(i);
284                     h = c * p;
285                     r = hypot(p,e(i));
286                     e(i+1) = s * r;
287                     s = e(i) / r;
288                     c = p / r;
289                     p = c * d(i) - s * g;
290                     d(i+1) = h + s * (c * g + s * d(i));
291 
292                     // Accumulate transformation.
293 
294                     for(unsigned int k = 0; k < n; ++k)
295                     {
296                          h = z(k, i+1);
297                          z(k, i+1) = s * z(k, i) + c * h;
298                         z(k, i) = c * z(k, i) - s * h;
299                     }
300                 }
301                 p = -s * s2 * c3 * el1 * e(l) / dl1;
302                 e(l) = s * p;
303                 d(l) = c * p;
304 
305                 // Check for convergence.
306 
307             } while(abs(e(l)) > eps*tst1);
308         }
309         d(l) = d(l) + f;
310         e(l) = 0.0;
311     }
312 
313     // Sort eigenvalues and corresponding vectors.
314 
315     for(unsigned int i = 0; i < n-1; ++i)
316     {
317         int k = i;
318         T p = abs(d(i));
319         for(unsigned int j = i+1; j < n; ++j)
320         {
321             T p1 = abs(d(j));
322             if(p < p1)
323             {
324                 k = j;
325                 p = p1;
326             }
327         }
328         if(k != i)
329         {
330             std::swap(d(k), d(i));
331             for(unsigned int j = 0; j < n; ++j)
332             {
333                 std::swap(z(j, i), z(j, k));
334             }
335         }
336     }
337     return true;
338 }
339 
340 // Nonsymmetric reduction to Hessenberg form.
341 
342 template <class T, class C1, class C2>
nonsymmetricHessenbergReduction(MultiArrayView<2,T,C1> & H,MultiArrayView<2,T,C2> & V)343 void nonsymmetricHessenbergReduction(MultiArrayView<2, T, C1> & H, MultiArrayView<2, T, C2> & V)
344 {
345     //  This is derived from the Algol procedures orthes and ortran,
346     //  by Martin and Wilkinson, Handbook for Auto. Comp.,
347     //  Vol.ii-Linear Algebra, and the corresponding
348     //  Fortran subroutines in EISPACK.
349 
350     int n = rowCount(H);
351     int low = 0;
352     int high = n-1;
353     ArrayVector<T> ort(n);
354 
355     for(int m = low+1; m <= high-1; ++m)
356     {
357         // Scale column.
358 
359         T scale = 0.0;
360         for(int i = m; i <= high; ++i)
361         {
362             scale = scale + abs(H(i, m-1));
363         }
364         if(scale != 0.0)
365         {
366 
367             // Compute Householder transformation.
368 
369             T h = 0.0;
370             for(int i = high; i >= m; --i)
371             {
372                 ort[i] = H(i, m-1)/scale;
373                 h += sq(ort[i]);
374             }
375             T g = VIGRA_CSTD::sqrt(h);
376             if(ort[m] > 0)
377             {
378                 g = -g;
379             }
380             h = h - ort[m] * g;
381             ort[m] = ort[m] - g;
382 
383             // Apply Householder similarity transformation
384             // H = (I-u*u'/h)*H*(I-u*u')/h)
385 
386             for(int j = m; j < n; ++j)
387             {
388                 T f = 0.0;
389                 for(int i = high; i >= m; --i)
390                 {
391                     f += ort[i]*H(i, j);
392                 }
393                 f = f/h;
394                 for(int i = m; i <= high; ++i)
395                 {
396                     H(i, j) -= f*ort[i];
397                 }
398             }
399 
400             for(int i = 0; i <= high; ++i)
401             {
402                 T f = 0.0;
403                 for(int j = high; j >= m; --j)
404                 {
405                     f += ort[j]*H(i, j);
406                 }
407                 f = f/h;
408                 for(int j = m; j <= high; ++j)
409                 {
410                     H(i, j) -= f*ort[j];
411                 }
412             }
413             ort[m] = scale*ort[m];
414             H(m, m-1) = scale*g;
415         }
416     }
417 
418     // Accumulate transformations (Algol's ortran).
419 
420     for(int i = 0; i < n; ++i)
421     {
422         for(int j = 0; j < n; ++j)
423         {
424             V(i, j) = (i == j ? 1.0 : 0.0);
425         }
426     }
427 
428     for(int m = high-1; m >= low+1; --m)
429     {
430         if(H(m, m-1) != 0.0)
431         {
432             for(int i = m+1; i <= high; ++i)
433             {
434                 ort[i] = H(i, m-1);
435             }
436             for(int j = m; j <= high; ++j)
437             {
438                 T g = 0.0;
439                 for(int i = m; i <= high; ++i)
440                 {
441                     g += ort[i] * V(i, j);
442                 }
443                 // Double division avoids possible underflow
444                 g = (g / ort[m]) / H(m, m-1);
445                 for(int i = m; i <= high; ++i)
446                 {
447                     V(i, j) += g * ort[i];
448                 }
449             }
450         }
451     }
452 }
453 
454 
455 // Complex scalar division.
456 
457 template <class T>
cdiv(T xr,T xi,T yr,T yi,T & cdivr,T & cdivi)458 void cdiv(T xr, T xi, T yr, T yi, T & cdivr, T & cdivi)
459 {
460     T r,d;
461     if(abs(yr) > abs(yi))
462     {
463         r = yi/yr;
464         d = yr + r*yi;
465         cdivr = (xr + r*xi)/d;
466         cdivi = (xi - r*xr)/d;
467     }
468     else
469     {
470         r = yr/yi;
471         d = yi + r*yr;
472         cdivr = (r*xr + xi)/d;
473         cdivi = (r*xi - xr)/d;
474     }
475 }
476 
477 template <class T, class C>
hessenbergQrDecompositionHelper(MultiArrayView<2,T,C> & H,int n,int l,double eps,T & p,T & q,T & r,T & s,T & w,T & x,T & y,T & z)478 int hessenbergQrDecompositionHelper(MultiArrayView<2, T, C> & H, int n, int l, double eps,
479              T & p, T & q, T & r, T & s, T & w, T & x, T & y, T & z)
480 {
481     int m = n-2;
482     while(m >= l)
483     {
484         z = H(m, m);
485         r = x - z;
486         s = y - z;
487         p = (r * s - w) / H(m+1, m) + H(m, m+1);
488         q = H(m+1, m+1) - z - r - s;
489         r = H(m+2, m+1);
490         s = abs(p) + abs(q) + abs(r);
491         p = p / s;
492         q = q / s;
493         r = r / s;
494         if(m == l)
495         {
496             break;
497         }
498         if(abs(H(m, m-1)) * (abs(q) + abs(r)) <
499             eps * (abs(p) * (abs(H(m-1, m-1)) + abs(z) +
500             abs(H(m+1, m+1)))))
501         {
502                 break;
503         }
504         --m;
505     }
506     return m;
507 }
508 
509 
510 
511 // Nonsymmetric reduction from Hessenberg to real Schur form.
512 
513 template <class T, class C1, class C2, class C3>
hessenbergQrDecomposition(MultiArrayView<2,T,C1> & H,MultiArrayView<2,T,C2> & V,MultiArrayView<2,T,C3> & de)514 bool hessenbergQrDecomposition(MultiArrayView<2, T, C1> & H, MultiArrayView<2, T, C2> & V,
515                                      MultiArrayView<2, T, C3> & de)
516 {
517 
518     //  This is derived from the Algol procedure hqr2,
519     //  by Martin and Wilkinson, Handbook for Auto. Comp.,
520     //  Vol.ii-Linear Algebra, and the corresponding
521     //  Fortran subroutine in EISPACK.
522 
523     // Initialize
524     MultiArrayView<1, T, C3> d = de.bindOuter(0);
525     MultiArrayView<1, T, C3> e = de.bindOuter(1);
526 
527     int nn = rowCount(H);
528     int n = nn-1;
529     int low = 0;
530     int high = nn-1;
531     T eps = VIGRA_CSTD::pow(2.0, sizeof(T) == sizeof(float)
532                                      ? -23.0
533                                      : -52.0);
534     T exshift = 0.0;
535     T p=0,q=0,r=0,s=0,z=0,t,w,x,y;
536     T norm = vigra::norm(H);
537 
538     // Outer loop over eigenvalue index
539     int iter = 0;
540     while(n >= low)
541     {
542 
543         // Look for single small sub-diagonal element
544         int l = n;
545         while (l > low)
546         {
547             s = abs(H(l-1, l-1)) + abs(H(l, l));
548             if(s == 0.0)
549             {
550                 s = norm;
551             }
552             if(abs(H(l, l-1)) < eps * s)
553             {
554                 break;
555             }
556             --l;
557         }
558 
559         // Check for convergence
560         // One root found
561         if(l == n)
562         {
563             H(n, n) = H(n, n) + exshift;
564             d(n) = H(n, n);
565             e(n) = 0.0;
566             --n;
567             iter = 0;
568 
569         // Two roots found
570 
571         }
572         else if(l == n-1)
573         {
574             w = H(n, n-1) * H(n-1, n);
575             p = (H(n-1, n-1) - H(n, n)) / 2.0;
576             q = p * p + w;
577             z = VIGRA_CSTD::sqrt(abs(q));
578             H(n, n) = H(n, n) + exshift;
579             H(n-1, n-1) = H(n-1, n-1) + exshift;
580             x = H(n, n);
581 
582             // Real pair
583 
584             if(q >= 0)
585             {
586                 if(p >= 0)
587                 {
588                     z = p + z;
589                 }
590                 else
591                 {
592                     z = p - z;
593                 }
594                 d(n-1) = x + z;
595                 d(n) = d(n-1);
596                 if(z != 0.0)
597                 {
598                     d(n) = x - w / z;
599                 }
600                 e(n-1) = 0.0;
601                 e(n) = 0.0;
602                 x = H(n, n-1);
603                 s = abs(x) + abs(z);
604                 p = x / s;
605                 q = z / s;
606                 r = VIGRA_CSTD::sqrt(p * p+q * q);
607                 p = p / r;
608                 q = q / r;
609 
610                 // Row modification
611 
612                 for(int j = n-1; j < nn; ++j)
613                 {
614                     z = H(n-1, j);
615                     H(n-1, j) = q * z + p * H(n, j);
616                     H(n, j) = q * H(n, j) - p * z;
617                 }
618 
619                 // Column modification
620 
621                 for(int i = 0; i <= n; ++i)
622                 {
623                     z = H(i, n-1);
624                     H(i, n-1) = q * z + p * H(i, n);
625                     H(i, n) = q * H(i, n) - p * z;
626                 }
627 
628                 // Accumulate transformations
629 
630                 for(int i = low; i <= high; ++i)
631                 {
632                     z = V(i, n-1);
633                     V(i, n-1) = q * z + p * V(i, n);
634                     V(i, n) = q * V(i, n) - p * z;
635                 }
636 
637             // Complex pair
638 
639             }
640             else
641             {
642                 d(n-1) = x + p;
643                 d(n) = x + p;
644                 e(n-1) = z;
645                 e(n) = -z;
646             }
647             n = n - 2;
648             iter = 0;
649 
650         // No convergence yet
651 
652         }
653         else
654         {
655 
656             // Form shift
657 
658             x = H(n, n);
659             y = 0.0;
660             w = 0.0;
661             if(l < n)
662             {
663                 y = H(n-1, n-1);
664                 w = H(n, n-1) * H(n-1, n);
665             }
666 
667             // Wilkinson's original ad hoc shift
668 
669             if(iter == 10)
670             {
671                 exshift += x;
672                 for(int i = low; i <= n; ++i)
673                 {
674                     H(i, i) -= x;
675                 }
676                 s = abs(H(n, n-1)) + abs(H(n-1, n-2));
677                 x = y = 0.75 * s;
678                 w = -0.4375 * s * s;
679             }
680 
681             // MATLAB's new ad hoc shift
682 
683             if(iter == 30)
684             {
685                  s = (y - x) / 2.0;
686                  s = s * s + w;
687                  if(s > 0)
688                  {
689                       s = VIGRA_CSTD::sqrt(s);
690                       if(y < x)
691                       {
692                           s = -s;
693                       }
694                       s = x - w / ((y - x) / 2.0 + s);
695                       for(int i = low; i <= n; ++i)
696                       {
697                           H(i, i) -= s;
698                       }
699                       exshift += s;
700                       x = y = w = 0.964;
701                  }
702             }
703 
704             iter = iter + 1;
705             if(iter > 60)
706                 return false;
707 
708             // Look for two consecutive small sub-diagonal elements
709             int m = hessenbergQrDecompositionHelper(H, n, l, eps, p, q, r, s, w, x, y, z);
710             for(int i = m+2; i <= n; ++i)
711             {
712                 H(i, i-2) = 0.0;
713                 if(i > m+2)
714                 {
715                     H(i, i-3) = 0.0;
716                 }
717             }
718 
719             // Double QR step involving rows l:n and columns m:n
720 
721             for(int k = m; k <= n-1; ++k)
722             {
723                 int notlast = (k != n-1);
724                 if(k != m) {
725                     p = H(k, k-1);
726                     q = H(k+1, k-1);
727                     r = (notlast ? H(k+2, k-1) : 0.0);
728                     x = abs(p) + abs(q) + abs(r);
729                     if(x != 0.0)
730                     {
731                         p = p / x;
732                         q = q / x;
733                         r = r / x;
734                     }
735                 }
736                 if(x == 0.0)
737                 {
738                     break;
739                 }
740                 s = VIGRA_CSTD::sqrt(p * p + q * q + r * r);
741                 if(p < 0)
742                 {
743                     s = -s;
744                 }
745                 if(s != 0)
746                 {
747                     if(k != m)
748                     {
749                         H(k, k-1) = -s * x;
750                     }
751                     else if(l != m)
752                     {
753                         H(k, k-1) = -H(k, k-1);
754                     }
755                     p = p + s;
756                     x = p / s;
757                     y = q / s;
758                     z = r / s;
759                     q = q / p;
760                     r = r / p;
761 
762                     // Row modification
763 
764                     for(int j = k; j < nn; ++j)
765                     {
766                         p = H(k, j) + q * H(k+1, j);
767                         if(notlast)
768                         {
769                             p = p + r * H(k+2, j);
770                             H(k+2, j) = H(k+2, j) - p * z;
771                         }
772                         H(k, j) = H(k, j) - p * x;
773                         H(k+1, j) = H(k+1, j) - p * y;
774                     }
775 
776                     // Column modification
777 
778                     for(int i = 0; i <= std::min(n,k+3); ++i)
779                     {
780                         p = x * H(i, k) + y * H(i, k+1);
781                         if(notlast)
782                         {
783                             p = p + z * H(i, k+2);
784                             H(i, k+2) = H(i, k+2) - p * r;
785                         }
786                         H(i, k) = H(i, k) - p;
787                         H(i, k+1) = H(i, k+1) - p * q;
788                     }
789 
790                     // Accumulate transformations
791 
792                     for(int i = low; i <= high; ++i)
793                     {
794                         p = x * V(i, k) + y * V(i, k+1);
795                         if(notlast)
796                         {
797                             p = p + z * V(i, k+2);
798                             V(i, k+2) = V(i, k+2) - p * r;
799                         }
800                         V(i, k) = V(i, k) - p;
801                         V(i, k+1) = V(i, k+1) - p * q;
802                     }
803                 }  // (s != 0)
804             }  // k loop
805         }  // check convergence
806     }  // while (n >= low)
807 
808     // Backsubstitute to find vectors of upper triangular form
809 
810     if(norm == 0.0)
811     {
812         return false;
813     }
814 
815     for(n = nn-1; n >= 0; --n)
816     {
817         p = d(n);
818         q = e(n);
819 
820         // Real vector
821 
822         if(q == 0)
823         {
824             int l = n;
825             H(n, n) = 1.0;
826             for(int i = n-1; i >= 0; --i)
827             {
828                 w = H(i, i) - p;
829                 r = 0.0;
830                 for(int j = l; j <= n; ++j)
831                 {
832                     r = r + H(i, j) * H(j, n);
833                 }
834                 if(e(i) < 0.0)
835                 {
836                     z = w;
837                     s = r;
838                 }
839                 else
840                 {
841                     l = i;
842                     if(e(i) == 0.0)
843                     {
844                         if(w != 0.0)
845                         {
846                             H(i, n) = -r / w;
847                         }
848                         else
849                         {
850                             H(i, n) = -r / (eps * norm);
851                         }
852 
853                     // Solve real equations
854 
855                     }
856                     else
857                     {
858                         x = H(i, i+1);
859                         y = H(i+1, i);
860                         q = (d(i) - p) * (d(i) - p) + e(i) * e(i);
861                         t = (x * s - z * r) / q;
862                         H(i, n) = t;
863                         if(abs(x) > abs(z))
864                         {
865                             H(i+1, n) = (-r - w * t) / x;
866                         }
867                         else
868                         {
869                             H(i+1, n) = (-s - y * t) / z;
870                         }
871                     }
872 
873                     // Overflow control
874 
875                     t = abs(H(i, n));
876                     if((eps * t) * t > 1)
877                     {
878                         for(int j = i; j <= n; ++j)
879                         {
880                             H(j, n) = H(j, n) / t;
881                         }
882                     }
883                 }
884             }
885 
886         // Complex vector
887 
888         }
889         else if(q < 0)
890         {
891             int l = n-1;
892 
893             // Last vector component imaginary so matrix is triangular
894 
895             if(abs(H(n, n-1)) > abs(H(n-1, n)))
896             {
897                 H(n-1, n-1) = q / H(n, n-1);
898                 H(n-1, n) = -(H(n, n) - p) / H(n, n-1);
899             }
900             else
901             {
902                 cdiv(0.0,-H(n-1, n),H(n-1, n-1)-p,q, H(n-1, n-1), H(n-1, n));
903             }
904             H(n, n-1) = 0.0;
905             H(n, n) = 1.0;
906             for(int i = n-2; i >= 0; --i)
907             {
908                 T ra,sa,vr,vi;
909                 ra = 0.0;
910                 sa = 0.0;
911                 for(int j = l; j <= n; ++j)
912                 {
913                     ra = ra + H(j, n-1) * H(i, j);
914                     sa = sa + H(j, n) * H(i, j);
915                 }
916                 w = H(i, i) - p;
917 
918                 if(e(i) < 0.0)
919                 {
920                     z = w;
921                     r = ra;
922                     s = sa;
923                 }
924                 else
925                 {
926                     l = i;
927                     if(e(i) == 0)
928                     {
929                         cdiv(-ra,-sa,w,q, H(i, n-1), H(i, n));
930                     }
931                     else
932                     {
933                         // Solve complex equations
934 
935                         x = H(i, i+1);
936                         y = H(i+1, i);
937                         vr = (d(i) - p) * (d(i) - p) + e(i) * e(i) - q * q;
938                         vi = (d(i) - p) * 2.0 * q;
939                         if((vr == 0.0) && (vi == 0.0))
940                         {
941                             vr = eps * norm * (abs(w) + abs(q) +
942                             abs(x) + abs(y) + abs(z));
943                         }
944                         cdiv(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi, H(i, n-1), H(i, n));
945                         if(abs(x) > (abs(z) + abs(q)))
946                         {
947                             H(i+1, n-1) = (-ra - w * H(i, n-1) + q * H(i, n)) / x;
948                             H(i+1, n) = (-sa - w * H(i, n) - q * H(i, n-1)) / x;
949                         }
950                         else
951                         {
952                             cdiv(-r-y*H(i, n-1),-s-y*H(i, n),z,q, H(i+1, n-1), H(i+1, n));
953                         }
954                     }
955 
956                     // Overflow control
957 
958                     t = std::max(abs(H(i, n-1)),abs(H(i, n)));
959                     if((eps * t) * t > 1)
960                     {
961                         for(int j = i; j <= n; ++j)
962                         {
963                             H(j, n-1) = H(j, n-1) / t;
964                             H(j, n) = H(j, n) / t;
965                         }
966                     }
967                 }
968             }
969         }
970     }
971 
972     // Back transformation to get eigenvectors of original matrix
973 
974     for(int j = nn-1; j >= low; --j)
975     {
976         for(int i = low; i <= high; ++i)
977         {
978             z = 0.0;
979             for(int k = low; k <= std::min(j,high); ++k)
980             {
981                 z = z + V(i, k) * H(k, j);
982             }
983             V(i, j) = z;
984         }
985     }
986     return true;
987 }
988 
989 } // namespace detail
990 
991 /** \addtogroup LinearAlgebraFunctions Matrix functions
992  */
993 //@{
994     /** Compute the eigensystem of a symmetric matrix.
995 
996         \a a is a real symmetric matrix, \a ew is a single-column matrix
997         holding the eigenvalues, and \a ev is a matrix of the same size as
998         \a a whose columns are the corresponding eigenvectors. Eigenvalues
999         will be sorted from largest to smallest magnitude.
1000         The algorithm returns <tt>false</tt> when it doesn't
1001         converge. It can be applied in-place, i.e. <tt>&a == &ev</tt> is allowed.
1002         The code of this function was adapted from JAMA.
1003 
1004     <b>\#include</b> "<a href="eigensystem_8hxx-source.html">vigra/eigensystem.hxx</a>" or<br>
1005     <b>\#include</b> "<a href="linear__algebra_8hxx-source.html">vigra/linear_algebra.hxx</a>"<br>
1006         Namespaces: vigra and vigra::linalg
1007      */
1008 template <class T, class C1, class C2, class C3>
1009 bool
symmetricEigensystem(MultiArrayView<2,T,C1> const & a,MultiArrayView<2,T,C2> & ew,MultiArrayView<2,T,C3> & ev)1010 symmetricEigensystem(MultiArrayView<2, T, C1> const & a,
1011             MultiArrayView<2, T, C2> & ew, MultiArrayView<2, T, C3> & ev)
1012 {
1013     vigra_precondition(isSymmetric(a),
1014         "symmetricEigensystem(): symmetric input matrix required.");
1015     unsigned int acols = columnCount(a);
1016     vigra_precondition(1 == columnCount(ew) && acols == rowCount(ew) &&
1017                        acols == columnCount(ev) && acols == rowCount(ev),
1018         "symmetricEigensystem(): matrix shape mismatch.");
1019 
1020     ev.copy(a); // does nothing if &ev == &a
1021     Matrix<T> de(acols, 2);
1022     detail::housholderTridiagonalization(ev, de);
1023     if(!detail::tridiagonalMatrixEigensystem(de, ev))
1024         return false;
1025 
1026     ew.copy(columnVector(de, 0));
1027     return true;
1028 }
1029 
1030     /** Compute the eigensystem of a square, but
1031         not necessarily symmetric matrix.
1032 
1033         \a a is a real square matrix, \a ew is a single-column matrix
1034         holding the possibly complex eigenvalues, and \a ev is a matrix of
1035         the same size as \a a whose columns are the corresponding eigenvectors.
1036         Eigenvalues will be sorted from largest to smallest magnitude.
1037         The algorithm returns <tt>false</tt> when it doesn't
1038         converge. It can be applied in-place, i.e. <tt>&a == &ev</tt> is allowed.
1039         The code of this function was adapted from JAMA.
1040 
1041     <b>\#include</b> "<a href="eigensystem_8hxx-source.html">vigra/eigensystem.hxx</a>" or<br>
1042     <b>\#include</b> "<a href="linear__algebra_8hxx-source.html">vigra/linear_algebra.hxx</a>"<br>
1043         Namespaces: vigra and vigra::linalg
1044      */
1045 template <class T, class C1, class C2, class C3>
1046 bool
nonsymmetricEigensystem(MultiArrayView<2,T,C1> const & a,MultiArrayView<2,std::complex<T>,C2> & ew,MultiArrayView<2,T,C3> & ev)1047 nonsymmetricEigensystem(MultiArrayView<2, T, C1> const & a,
1048          MultiArrayView<2, std::complex<T>, C2> & ew, MultiArrayView<2, T, C3> & ev)
1049 {
1050     unsigned int acols = columnCount(a);
1051     vigra_precondition(acols == rowCount(a),
1052         "nonsymmetricEigensystem(): square input matrix required.");
1053     vigra_precondition(1 == columnCount(ew) && acols == rowCount(ew) &&
1054                        acols == columnCount(ev) && acols == rowCount(ev),
1055         "nonsymmetricEigensystem(): matrix shape mismatch.");
1056 
1057     Matrix<T> H(a);
1058     Matrix<T> de(acols, 2);
1059     detail::nonsymmetricHessenbergReduction(H, ev);
1060     if(!detail::hessenbergQrDecomposition(H, ev, de))
1061         return false;
1062 
1063     for(unsigned int i=0; i < acols; ++i)
1064     {
1065         ew(i,0) = std::complex<T>(de(i, 0), de(i, 1));
1066     }
1067     return true;
1068 }
1069 
1070     /** Compute the roots of a polynomial using the eigenvalue method.
1071 
1072         \a poly is a real polynomial (compatible to \ref vigra::PolynomialView),
1073         and \a roots a complex valued vector (compatible to <tt>std::vector</tt>
1074         with a <tt>value_type</tt> compatible to the type <tt>POLYNOMIAL::Complex</tt>) to which
1075         the roots are appended. The function calls \ref nonsymmetricEigensystem() with the standard
1076         companion matrix yielding the roots as eigenvalues. It returns <tt>false</tt> if
1077         it fails to converge.
1078 
1079         <b>\#include</b> "<a href="eigensystem_8hxx-source.html">vigra/eigensystem.hxx</a>" or<br>
1080         <b>\#include</b> "<a href="linear__algebra_8hxx-source.html">vigra/linear_algebra.hxx</a>"<br>
1081         Namespaces: vigra and vigra::linalg
1082 
1083         \see polynomialRoots(), vigra::Polynomial
1084      */
1085 template <class POLYNOMIAL, class VECTOR>
polynomialRootsEigenvalueMethod(POLYNOMIAL const & poly,VECTOR & roots,bool polishRoots)1086 bool polynomialRootsEigenvalueMethod(POLYNOMIAL const & poly, VECTOR & roots, bool polishRoots)
1087 {
1088     typedef typename POLYNOMIAL::value_type T;
1089     typedef typename POLYNOMIAL::Real    Real;
1090     typedef typename POLYNOMIAL::Complex Complex;
1091     typedef Matrix<T> TMatrix;
1092     typedef Matrix<Complex> ComplexMatrix;
1093 
1094     int const degree = poly.order();
1095     double const eps = poly.epsilon();
1096 
1097     TMatrix inMatrix(degree, degree);
1098     for(int i = 0; i < degree; ++i)
1099         inMatrix(0, i) = -poly[degree - i - 1] / poly[degree];
1100     for(int i = 0; i < degree - 1; ++i)
1101         inMatrix(i + 1, i) = NumericTraits<T>::one();
1102     ComplexMatrix ew(degree, 1);
1103     TMatrix ev(degree, degree);
1104     bool success = nonsymmetricEigensystem(inMatrix, ew, ev);
1105     if(!success)
1106         return false;
1107     for(int i = 0; i < degree; ++i)
1108     {
1109         if(polishRoots)
1110             vigra::detail::laguerre1Root(poly, ew(i,0), 1);
1111         roots.push_back(vigra::detail::deleteBelowEpsilon(ew(i,0), eps));
1112     }
1113     std::sort(roots.begin(), roots.end(), vigra::detail::PolynomialRootCompare<Real>(eps));
1114     return true;
1115 }
1116 
1117 template <class POLYNOMIAL, class VECTOR>
polynomialRootsEigenvalueMethod(POLYNOMIAL const & poly,VECTOR & roots)1118 bool polynomialRootsEigenvalueMethod(POLYNOMIAL const & poly, VECTOR & roots)
1119 {
1120     return polynomialRootsEigenvalueMethod(poly, roots, true);
1121 }
1122 
1123     /** Compute the real roots of a real polynomial using the eigenvalue method.
1124 
1125         \a poly is a real polynomial (compatible to \ref vigra::PolynomialView),
1126         and \a roots a real valued vector (compatible to <tt>std::vector</tt>
1127         with a <tt>value_type</tt> compatible to the type <tt>POLYNOMIAL::Real</tt>) to which
1128         the roots are appended. The function calls \ref polynomialRootsEigenvalueMethod() and
1129         throws away all complex roots. It returns <tt>false</tt> if it fails to converge.
1130 
1131         <b>\#include</b> "<a href="eigensystem_8hxx-source.html">vigra/eigensystem.hxx</a>" or<br>
1132         <b>\#include</b> "<a href="linear__algebra_8hxx-source.html">vigra/linear_algebra.hxx</a>"<br>
1133         Namespaces: vigra and vigra::linalg
1134 
1135         \see polynomialRealRoots(), vigra::Polynomial
1136      */
1137 template <class POLYNOMIAL, class VECTOR>
polynomialRealRootsEigenvalueMethod(POLYNOMIAL const & p,VECTOR & roots,bool polishRoots)1138 bool polynomialRealRootsEigenvalueMethod(POLYNOMIAL const & p, VECTOR & roots, bool polishRoots)
1139 {
1140     typedef typename NumericTraits<typename VECTOR::value_type>::ComplexPromote Complex;
1141     ArrayVector<Complex> croots;
1142     if(!polynomialRootsEigenvalueMethod(p, croots))
1143         return false;
1144     for(unsigned int i = 0; i < croots.size(); ++i)
1145         if(croots[i].imag() == 0.0)
1146             roots.push_back(croots[i].real());
1147     return true;
1148 }
1149 
1150 template <class POLYNOMIAL, class VECTOR>
polynomialRealRootsEigenvalueMethod(POLYNOMIAL const & p,VECTOR & roots)1151 bool polynomialRealRootsEigenvalueMethod(POLYNOMIAL const & p, VECTOR & roots)
1152 {
1153     return polynomialRealRootsEigenvalueMethod(p, roots, true);
1154 }
1155 
1156 
1157 //@}
1158 
1159 } // namespace linalg
1160 
1161 using linalg::symmetricEigensystem;
1162 using linalg::nonsymmetricEigensystem;
1163 using linalg::polynomialRootsEigenvalueMethod;
1164 using linalg::polynomialRealRootsEigenvalueMethod;
1165 
1166 } // namespace vigra
1167 
1168 #endif // VIGRA_EIGENSYSTEM_HXX
1169