home *** CD-ROM | disk | FTP | other *** search
- //====================================================================
- // eigensys.hpp
- //
- // Version 1.1
- //
- // Written by:
- // Brent Worden
- // WordenWare
- // email: Brent@Worden.org
- //
- // Copyright (c) 1998-1999 WordenWare
- //
- // Created: August 28, 1998
- // Revised: April 10, 1999
- //====================================================================
-
- #ifndef _EIGENSYS_HPP_
- #define _EIGENSYS_HPP_
-
- #include "mathx.h"
- #include "matrix.hpp"
- #include "numerics.h"
- #include "utility.hpp"
-
- NUM_BEGIN
-
- template<class T>
- void tridred(Matrix<T>& a, Vector<T>& d, Vector<T>& e)
- //--------------------------------------------------------------------
- // Householder reduction of a real, symmetric matrix a. On output, a
- // is replaced by the orthogonal matrix effecting the transformation.
- // d returns the diagonal elements of the tridiagonal matrix, and e
- // the off-diagonal elements, with e[0] = 0.
- //--------------------------------------------------------------------
- {
- int n = a.rows();
- T zero(0);
- T f, g, h;
- int i, j, k;
- T scale, tmp;
- d.resize(n);
- e.resize(n);
-
- for(i = 0; i < n; ++i){
- d[i] = a[i][n - 1];
- a[i][n - 1] = a[i][i];
- }
- for(i = n - 1; i >= 0; --i){
- h = zero;
- scale = zero;
- if(i < 1){
- e[i] = zero;
- } else {
- for(k = 0; k <= i; ++k){
- scale += absoluteValue(d[k]);
- }
- if(scale == zero){
- for(j = 0; j < i; ++j){
- d[j] = a[j][i - 1];
- a[j][i - 1] = a[j][i];
- a[j][i] = zero;
- }
- e[i] = zero;
- } else {
- for(k = 0; k < i; ++k){
- tmp = (d[k] /= scale);
- h += tmp * tmp;
- }
- f = d[i - 1];
- g = (f >= zero ? -sqrt(h) : sqrt(h));
- e[i] = scale * g;
- h -= f * g;
- d[i - 1] = f - g;
- if(i != 1){
- for(j = 0; j < i; ++j){
- e[j] = zero;
- }
- for(j = 0; j < i; ++j){
- f = d[j];
- g = e[j] + a[j][j] * f;
- k = j + 1;
- if(i > k){
- for(; k < i; ++k){
- g += a[j][k] * d[k];
- e[k] += a[j][k] * f;
- }
- }
- e[j] = g;
- }
- f = zero;
- for(j = 0; j < i; ++j){
- e[j] /= h;
- f += e[j] * d[j];
- }
- h = f / (h + h);
- for(j = 0; j < i; ++j){
- e[j] -= h * d[j];
- }
- for(j = 0; j < i; ++j){
- f = d[j];
- g = e[j];
- for(k = j; k < i; ++k){
- a[j][k] -= (f * e[k] + g * d[k]);
- }
- }
- }
- for(j = 0; j < i; ++j){
- f = d[j];
- d[j] = a[j][i - 1];
- a[j][i - 1] = a[j][i];
- a[j][i] = f * scale;
- }
- }
- }
- }
- };
-
- template<class T>
- void trideig(Vector<T>& d, Vector<T>& e)
- //--------------------------------------------------------------------
- // Algorithm to determine the eigenvalues of a real, symetric,
- // tridiagonal matrix, or of a real, symmetric matrix previously
- // reduced by tridred(). On input, d contains the diagonal elements
- // of the tridaigonal matrix. On output, it returns the eigenvalues.
- // e inputs the subdiagonal elements of the tridiagonal matrix, with
- // e[0] arbitrary. On output, e is destroyed.
- //--------------------------------------------------------------------
- {
- int n = d.size();
- T zero(0), one(1), two(2);
-
- T b, c, f, g;
- int i, j, k, m;
- T p, r, s;
- T tmp;
-
- if(n != 1) {
- for(i = 1; i < n; ++i){
- e[i - 1] = e[i];
- }
- e[n - 1] = zero;
- for(k = 0; k < n; ++k){
- j = 0;
- for(m = k + 1; m < n; ++m){
- tmp = absoluteValue(d[m - 1]) + absoluteValue(d[m]);
- if(tmp == absoluteValue(e[m - 1]) + tmp){
- break;
- }
- }
- p = d[k];
- if(m != k + 1){
- if(j++ == NUMERICS_ITMAX){
- throw Exception("tridql", "Routine failed to converge.");
- return;
- }
- g = (d[k + 1] - p) / (e[k] * two);
- r = pythag(g, one);
- g = d[m - 1] - p + e[k] / (g + (g >= zero ? r : -r));
- s = one;
- c = one;
- p = zero;
- for(i = m - 2; i >= 0; --i){
- tmp = e[i];
- f = s * tmp;
- b = c * tmp;
- r = pythag(f, g);
- e[i + 1] = r;
- if(r == zero){
- d[i + 1] -= p;
- e[m - 1] = zero;
- break;
- }
- s = f / r;
- c = g / r;
- g = d[i + 1] - p;
- r = (d[i] - g) * s + c * two * b;
- p = s * r;
- d[i + 1] = g + p;
- g = c * r - b;
- }
- if(i <= k + 1 || r != zero){
- d[k] -= p;
- e[k] = g;
- e[m - 1] = zero;
- }
- }
- }
- }
- };
-
- NUM_END
-
- #endif
-
- //===================================================================
- // Revision History
- //
- // Version 1.0 - 08/28/1998 - New.
- // Version 1.1 - 04/10/1999 - Added Numerics namespace.
- // Removed calcution of eigenvectors from
- // tridred and trideig
- //===================================================================
-