MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/linalg/jacobirot.h
Go to the documentation of this file.
00001 /************************************************************************
00002  * MechSys - Open Library for Mechanical Systems                        *
00003  * Copyright (C) 2005 Dorival M. Pedroso, Raúl D. D. Farfan             *
00004  *                                                                      *
00005  * This program is free software: you can redistribute it and/or modify *
00006  * it under the terms of the GNU General Public License as published by *
00007  * the Free Software Foundation, either version 3 of the License, or    *
00008  * any later version.                                                   *
00009  *                                                                      *
00010  * This program is distributed in the hope that it will be useful,      *
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         *
00013  * GNU General Public License for more details.                         *
00014  *                                                                      *
00015  * You should have received a copy of the GNU General Public License    *
00016  * along with this program. If not, see <http://www.gnu.org/licenses/>  *
00017  ************************************************************************/
00018 
00019 /* Numerical evaluation of eigenvalues and eigenvectors for NxN SYMMETRIC
00020  *  matrices using the Jacobi-rotation Method.
00021  *
00022  * 2005-09-27 (C): Dorival M. Pedroso - Completely rewritten (3x3 => NxN); based on C numerical recipes
00023  * 2005-05-10 (C): Dorival M. Pedroso - C++
00024  * 2004-08-15 (C): Dorival M. Pedroso - Fortran 95
00025  * 2002-04-15 (C): Dorival M. Pedroso - Fortran 77
00026  */
00027 
00028 #ifndef MECHSYS_LINALG_JACOBIROT_H
00029 #define MECHSYS_LINALG_JACOBIROT_H
00030 
00031 // STL
00032 #include <cmath>
00033 
00034 // MechSys
00035 #include "mechsys/linalg/matvec.h"
00036 
00053 template<typename MatrixType, typename VectorType>
00054 inline int _jacobi_rot (int N, MatrixType & A, MatrixType & Q, VectorType & v, double errTol=DBL_EPSILON)
00055 {
00056     const int    maxIt = 20;          // max number of iterations
00057     const double Zero  = DBL_EPSILON; // tolerance
00058 
00059     int    j,p,q;
00060     double theta,tau,t,sm,s,h,g,c;
00061     double * b = new double [N];
00062     double * z = new double [N];
00063 
00064     for (p=0; p<N; p++) // initialize Q to the identity matrix.
00065     {
00066         for (q=0; q<N; q++) Q(p,q) = 0.0;
00067         Q(p,p) = 1.0;
00068     }
00069     for (p=0; p<N; p++)
00070     {
00071         b[p] = v(p) = A(p,p); // initialize b and v to the diagonal of A
00072         z[p] = 0.0;           // this vector will accumulate terms of the form tapq as in equation (11.1.14).
00073     }
00074 
00075     for (int it=0; it<maxIt; it++)
00076     {
00077         sm = 0.0;
00078         for (p=0; p<N-1; p++) // sum off-diagonal elements.
00079         {
00080             for (q=p+1; q<N; q++)
00081             sm += fabs(A(p,q));
00082         }
00083         if (sm<errTol) // exit point
00084         {
00085             delete [] b;
00086             delete [] z;
00087             return it+1;
00088         }
00089         for (p=0; p<N-1; p++)
00090         {
00091             for (q=p+1; q<N; q++)
00092             {
00093                 h = v(q)-v(p);
00094                 if (fabs(h)<=Zero) t=1.0;
00095                 else
00096                 {
00097                     theta = 0.5*h/(A(p,q));
00098                     t     = 1.0/(fabs(theta)+sqrt(1.0+theta*theta));
00099                     if (theta < 0.0) t=-t;
00100                 }
00101                 c      = 1.0/sqrt(1.0+t*t);
00102                 s      = t*c;
00103                 tau    = s/(1.0+c);
00104                 h      = t*A(p,q);
00105                 z[p]  -= h;
00106                 z[q]  += h;
00107                 v(p)  -= h;
00108                 v(q)  += h;
00109                 A(p,q) = 0.0;
00110                 for (j=0; j<p; j++)  // case of rotations 0 <= j < p.
00111                 {
00112                     g      = A(j,p);
00113                     h      = A(j,q);
00114                     A(j,p) = g - s*(h+g*tau);
00115                     A(j,q) = h + s*(g-h*tau);
00116                 }
00117                 for (j=p+1; j<q; j++) // case of rotations p < j < q.
00118                 {
00119                     g      = A(p,j);
00120                     h      = A(j,q);
00121                     A(p,j) = g - s*(h+g*tau);
00122                     A(j,q) = h + s*(g-h*tau);
00123                 }
00124                 for (j=q+1; j<N; j++) //case of rotations q < j < N.
00125                 {
00126                     g      = A(p,j);
00127                     h      = A(q,j);
00128                     A(p,j) = g - s*(h+g*tau);
00129                     A(q,j) = h + s*(g-h*tau);
00130                 }
00131                 for (j=0; j<N; j++) // Q matrix
00132                 {
00133                     g      = Q(j,p);
00134                     h      = Q(j,q);
00135                     Q(j,p) = g - s*(h+g*tau);
00136                     Q(j,q) = h + s*(g-h*tau);
00137                 }
00138             }
00139         }
00140         for (p=0; p<N; p++)
00141         {
00142             b[p] += z[p];
00143             z[p]  = 0.0;   // reinitialize z.
00144             v(p)  = b[p];  // update v with the sum of tapq,
00145         }
00146     }
00147 
00148     delete [] b;
00149     delete [] z;
00150     throw new Fatal("JacobiRot: Jacobi rotation dit not converge after %d iterations",maxIt+1);
00151     return maxIt+1;
00152 }
00153 
00155 inline int JacobiRot (Mat_t & A, Mat_t & Q, Vec_t & v, double errTol=DBL_EPSILON)
00156 {
00157     int N = A.num_rows();
00158     if (N<2)                     throw new Fatal("JacobiRot: Matrix needs to be at least 2x2");
00159     if (A.num_cols()!=(size_t)N) throw new Fatal("JacobiRot: Matrix must be square");
00160     Q.change_dim (N,N);
00161     v.change_dim (N);
00162     return _jacobi_rot (N, A, Q, v, errTol);
00163 }
00164 
00166 inline int JacobiRot (Mat3_t & A, Mat3_t & Q, Vec3_t & v, double errTol=DBL_EPSILON)
00167 {
00168     return _jacobi_rot (/*N*/3, A, Q, v, errTol);
00169 }
00170 
00172 inline int JacobiRot (Vec_t const & TenA, Mat3_t & Q, Vec3_t & v, double errTol=DBL_EPSILON)
00173 {
00174     Mat3_t A;
00175     Ten2Mat (TenA, A);
00176     return _jacobi_rot (/*N*/3, A, Q, v, errTol);
00177 }
00178 
00179 #ifdef USE_BOOST_PYTHON
00180 inline int PyJacobiRot (BPy::list const & A, BPy::list & Q, BPy::list & V, double errTol=DBL_EPSILON)
00181 {
00182     Mat_t a, q;
00183     Vec_t v;
00184     List2Mat (A, a);
00185     int it = JacobiRot (a, q, v, errTol);
00186     Mat2List (q, Q);
00187     Vec2List (v, V);
00188     return it;
00189 }
00190 #endif
00191 
00192 #endif // MECHSYS_LINALG_JACOBIROT_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines