jacobirot.h

00001 /*************************************************************************************
00002  * MechSys - A C++ library to simulate (Continuum) Mechanical Systems                *
00003  * Copyright (C) 2005 Dorival de Moraes Pedroso <dorival.pedroso at gmail.com>       *
00004  * Copyright (C) 2005 Raul Dario Durand Farfan  <raul.durand at gmail.com>           *
00005  *                                                                                   *
00006  * This file is part of MechSys.                                                     *
00007  *                                                                                   *
00008  * MechSys is free software; you can redistribute it and/or modify it under the      *
00009  * terms of the GNU General Public License as published by the Free Software         *
00010  * Foundation; either version 2 of the License, or (at your option) any later        *
00011  * version.                                                                          *
00012  *                                                                                   *
00013  * MechSys is distributed in the hope that it will be useful, but WITHOUT ANY        *
00014  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A   *
00015  * PARTICULAR PURPOSE. See the GNU General Public License for more details.          *
00016  *                                                                                   *
00017  * You should have received a copy of the GNU General Public License along with      *
00018  * MechSys; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, *
00019  * Fifth Floor, Boston, MA 02110-1301, USA                                           *
00020  *************************************************************************************/
00021 
00022 /* Numerical evaluation of eigenvalues and eigenvectors for NxN SYMMETRIC
00023  *  matrices using the Jacobi-rotation Method.
00024  *
00025  * 2005-09-27 (C): Dorival M. Pedroso - Completely rewritten (3x3 => NxN); based on C numerical recipes
00026  * 2005-05-10 (C): Dorival M. Pedroso - C++
00027  * 2004-08-15 (C): Dorival M. Pedroso - Fortran 95
00028  * 2002-04-15 (C): Dorival M. Pedroso - Fortran 77
00029  *
00030  */
00031 
00032 #ifndef MECHSYS_LINALG_JACOBIROT_H
00033 #define MECHSYS_LINALG_JACOBIROT_H
00034 
00035 #ifdef HAVE_CONFIG_H
00036   #include "config.h"
00037 #else
00038   #ifndef REAL
00039     #define REAL double
00040   #endif
00041   #ifndef ZERO
00042     #define ZERO 1.0e-10
00043   #endif
00044 #endif
00045 
00046 #include <cmath>
00047 
00048 #include "linalg/matrix.h"
00049 #include "linalg/vector.h"
00050 
00051 namespace LinAlg
00052 {
00053 
00054 namespace Sym
00055 {
00056 
00057 // {{{
00059  // }}}
00073 inline int JacobiRot(Matrix<REAL> & A, Matrix<REAL> & Q, Vector<REAL> & v) // {{{
00074 {
00075     int N = A.Rows();
00076     assert(N>1);         // at least 2x2 matrix
00077     assert(A.Cols()==N);
00078     assert(Q.Rows()==N);
00079     assert(Q.Cols()==N);
00080 
00081     const int  maxIt=30;       // Max number of iterations
00082     const REAL errTol=1.0e-15; // Tolerance
00083 
00084     int    j,p,q;
00085     REAL theta,tau,t,sm,s,h,g,c;
00086     REAL * b = new REAL [N];
00087     REAL * z = new REAL [N];
00088 
00089     for (p=0; p<N; p++) // Initialize Q to the identity matrix.
00090     {
00091         for (q=0; q<N; q++) Q(p,q)=0.0;
00092         Q(p,p)=1.0;
00093     }
00094     for (p=0; p<N; p++)
00095     {
00096         b[p]=v(p)=A(p,p); // Initialize b and v to the diagonal of A
00097         z[p]=0.0;         // This vector will accumulate terms of the form tapq as in equation (11.1.14).
00098     }
00099 
00100     for (int it=0; it<maxIt; it++)
00101     {
00102         sm=0.0;
00103         for (p=0; p<N-1; p++) // Sum off-diagonal elements.
00104         {
00105             for (q=p+1; q<N; q++)
00106             sm += fabs(A(p,q));
00107         }
00108         if (sm<errTol) // The normal return
00109         {
00110             delete [] b;
00111             delete [] z;
00112             return it+1;
00113         }
00114         for (p=0; p<N-1; p++)
00115         {
00116             for (q=p+1; q<N; q++)
00117             {
00118                 h=v(q)-v(p);
00119                 if (fabs(h)<=ZERO) t=1.0;
00120                 else
00121                 {
00122                     theta=0.5*h/(A(p,q));
00123                     t=1.0/(fabs(theta)+sqrt(1.0+theta*theta));
00124                     if (theta < 0.0) t=-t;
00125                 }
00126                 c=1.0/sqrt(1.0+t*t);
00127                 s=t*c;
00128                 tau=s/(1.0+c);
00129                 h=t*A(p,q);
00130                 z[p] -= h;
00131                 z[q] += h;
00132                 v(p) -= h;
00133                 v(q) += h;
00134                 A(p,q)=0.0;
00135                 for (j=0; j<p; j++)  // Case of rotations 0 <= j < p.
00136                 { 
00137                     g = A(j,p);
00138                     h = A(j,q);
00139                     A(j,p) = g - s*(h+g*tau);
00140                     A(j,q) = h + s*(g-h*tau);
00141                 }
00142                 for (j=p+1; j<q; j++) // Case of rotations p < j < q.
00143                 { 
00144                     g = A(p,j);
00145                     h = A(j,q);
00146                     A(p,j) = g - s*(h+g*tau);
00147                     A(j,q) = h + s*(g-h*tau);
00148                 }
00149                 for (j=q+1; j<N; j++) //Case of rotations q < j < N.
00150                 { 
00151                     g = A(p,j);
00152                     h = A(q,j);
00153                     A(p,j) = g - s*(h+g*tau);
00154                     A(q,j) = h + s*(g-h*tau);
00155                 }
00156                 for (j=0; j<N; j++) // Q matrix
00157                 {
00158                     g = Q(j,p);
00159                     h = Q(j,q);
00160                     Q(j,p) = g - s*(h+g*tau);
00161                     Q(j,q) = h + s*(g-h*tau);
00162                 }
00163             }
00164         }
00165         for (p=0; p<N; p++)
00166         {
00167             b[p] += z[p];
00168             z[p]  = 0.0;   // reinitialize z.
00169             v(p)  = b[p];  // update v with the sum of tapq,
00170         }
00171     }
00172 
00173     delete [] b;
00174     delete [] z;
00175     std::cout << "ERROR: Too many iterations in routine jacobi\n";
00176     return maxIt+1;
00177 
00178 } // }}}
00179 
00180 }; // namespace Sym
00181 
00182 }; // namespace LinAlg
00183 
00184 #endif // MECHSYS_LINALG_JACOBIROT_H
00185 
00186 // vim:fdm=marker

Generated on Wed Jan 24 15:56:26 2007 for MechSys by  doxygen 1.4.7