moab
Matrix3.hpp
Go to the documentation of this file.
00001 /*
00002  * MOAB, a Mesh-Oriented datABase, is a software component for creating,
00003  * storing and accessing finite element mesh data.
00004  * 
00005  * Copyright 2004 Sandia Corporation.  Under the terms of Contract
00006  * DE-AC04-94AL85000 with Sandia Coroporation, the U.S. Government
00007  * retains certain rights in this software.
00008  * 
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  */
00014 
00023 #ifndef MOAB_MATRIX3_HPP
00024 #define MOAB_MATRIX3_HPP
00025 
00026 #include "moab/Types.hpp"
00027 //#include "moab/EigenDecomp.hpp"
00028 #include <iostream>
00029 #include "moab/CartVect.hpp"
00030 
00031 #include <iosfwd>
00032 #include <limits>
00033 #include <float.h>
00034 #include <assert.h>
00035 #ifdef _MSC_VER
00036 # define finite _finite
00037 #endif
00038 
00039 namespace moab {
00040 
00041 namespace Matrix{
00042     template< typename Matrix>
00043     Matrix inverse( const Matrix & d, const double i){
00044         Matrix m( d);
00045          m( 0) = i * (d(4) * d(8) - d(5) * d(7));
00046              m( 1) = i * (d(2) * d(7) - d(8) * d(1));
00047              m( 2) = i * (d(1) * d(5) - d(4) * d(2));
00048              m( 3) = i * (d(5) * d(6) - d(8) * d(3));
00049              m( 4) = i * (d(0) * d(8) - d(6) * d(2));
00050              m( 5) = i * (d(2) * d(3) - d(5) * d(0));
00051              m( 6) = i * (d(3) * d(7) - d(6) * d(4));
00052              m( 7) = i * (d(1) * d(6) - d(7) * d(0));
00053              m( 8) = i * (d(0) * d(4) - d(3) * d(1));
00054         return m;
00055     }
00056 
00057     template< typename Matrix>
00058     inline bool positive_definite( const Matrix & d, 
00059                        double& det ){
00060             double subdet6 = d(1)*d(5)-d(2)*d(4);
00061             double subdet7 = d(2)*d(3)-d(0)*d(5);
00062             double subdet8 = d(0)*d(4)-d(1)*d(3);
00063             det = d(6)*subdet6 + d(7)*subdet7 + d(8)*subdet8;
00064             return d(0) > 0 && subdet8 > 0 && det > 0;
00065     }
00066     template< typename Matrix>
00067     inline Matrix transpose( const Matrix & d){
00068           return Matrix( d(0), d(3), d(6),
00069                          d(1), d(4), d(7),
00070                          d(2), d(5), d(8) );
00071     }
00072     template< typename Matrix>
00073     inline Matrix mmult3( const Matrix& a, const Matrix& b ) {
00074       return Matrix( a(0,0) * b(0,0) + a(0,1) * b(1,0) + a(0,2) * b(2,0),
00075                      a(0,0) * b(0,1) + a(0,1) * b(1,1) + a(0,2) * b(2,1),
00076                      a(0,0) * b(0,2) + a(0,1) * b(1,2) + a(0,2) * b(2,2),
00077                      a(1,0) * b(0,0) + a(1,1) * b(1,0) + a(1,2) * b(2,0),
00078                      a(1,0) * b(0,1) + a(1,1) * b(1,1) + a(1,2) * b(2,1),
00079                      a(1,0) * b(0,2) + a(1,1) * b(1,2) + a(1,2) * b(2,2),
00080                      a(2,0) * b(0,0) + a(2,1) * b(1,0) + a(2,2) * b(2,0),
00081                      a(2,0) * b(0,1) + a(2,1) * b(1,1) + a(2,2) * b(2,1),
00082                      a(2,0) * b(0,2) + a(2,1) * b(1,2) + a(2,2) * b(2,2) );
00083     }
00084 
00085     template< typename Vector, typename Matrix>
00086     inline Matrix outer_product( const Vector & u,
00087                                   const Vector & v,
00088                       Matrix & m ) {
00089         m = Matrix( u[0] * v[0], u[0] * v[1], u[0] * v[2],
00090                         u[1] * v[0], u[1] * v[1], u[1] * v[2],
00091                         u[2] * v[0], u[2] * v[1], u[2] * v[2] );
00092         return m;
00093     }
00094     template< typename Matrix>
00095     inline double determinant3( const Matrix & d){
00096         return (d(0) * d(4) * d(8) 
00097              + d(1) * d(5) * d(6)
00098              + d(2) * d(3) * d(7)
00099              - d(0) * d(5) * d(7)
00100              - d(1) * d(3) * d(8)
00101              - d(2) * d(4) * d(6)); 
00102     }
00103     
00104     template< typename Matrix>
00105     inline const Matrix inverse( const Matrix & d){
00106         const double det = 1.0/determinant3( d);
00107         return inverse( d, det);
00108     }
00109     
00110     template< typename Vector, typename Matrix>
00111     inline Vector vector_matrix( const Vector& v, const Matrix& m ) {
00112       return Vector( v[0] * m(0,0) + v[1] * m(1,0) + v[2] * m(2,0),
00113                      v[0] * m(0,1) + v[1] * m(1,1) + v[2] * m(2,1),
00114                      v[0] * m(0,2) + v[1] * m(1,2) + v[2] * m(2,2) );
00115     }
00116     
00117     template< typename Vector, typename Matrix>
00118     inline Vector matrix_vector( const Matrix& m, const Vector& v ){
00119        Vector res = v;
00120        res[ 0] = v[0] * m(0,0) + v[1] * m(0,1) + v[2] * m(0,2);
00121        res[ 1] = v[0] * m(1,0) + v[1] * m(1,1) + v[2] * m(1,2);
00122        res[ 2] = v[0] * m(2,0) + v[1] * m(2,1) + v[2] * m(2,2);
00123        return res;
00124     } 
00125 
00126     // moved from EigenDecomp.hpp
00127 
00128     // Jacobi iteration for the solution of eigenvectors/eigenvalues of a nxn
00129     // real symmetric matrix. Square nxn matrix a; size of matrix in n;
00130     // output eigenvalues in w; and output eigenvectors in v. Resulting
00131     // eigenvalues/vectors are sorted in decreasing order; eigenvectors are
00132     // normalized.
00133     // TODO: Remove this
00134     #define VTK_ROTATE(a,i,j,k,l) g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau);\
00135             a[k][l]=h+s*(g-h*tau)
00136 
00137     //TODO: Refactor this method into subroutines
00138     //use a namespace { }  with no name to
00139     //contain subroutines so that the compiler
00140     //automatically inlines them.
00141 
00142     template< typename Matrix, typename Vector>
00143     ErrorCode EigenDecomp( const Matrix & _a,
00144                            double w[3],
00145                            Vector v[3] ) {
00146       const int MAX_ROTATIONS = 20;
00147       const double one_ninth = 1./9;
00148       int i, j, k, iq, ip, numPos;
00149       double tresh, theta, tau, t, sm, s, h, g, c, tmp;
00150       double b[3], z[3];
00151       Matrix a( _a);
00152 
00153       // initialize
00154       for (ip=0; ip<3; ip++) {
00155         for (iq=0; iq<3; iq++){
00156           v[ip][iq] = 0.0;
00157         }
00158         v[ip][ip] = 1.0;
00159       }
00160       for (ip=0; ip<3; ip++) {
00161         b[ip] = w[ip] = a[ip][ip];
00162         z[ip] = 0.0;
00163       }
00164 
00165       // begin rotation sequence
00166       for (i=0; i<MAX_ROTATIONS; i++){
00167         sm = 0.0;
00168         for (ip=0; ip<2; ip++){
00169           for (iq=ip+1; iq<3; iq++){ sm += fabs(a[ip][iq]); }
00170         }
00171 
00172         if ( sm == 0.0 ){ break; }
00173         // first 3 sweeps
00174         tresh = (i < 3)? 0.2*sm*one_ninth : 0.0;
00175         for (ip=0; ip<2; ip++) {
00176           for (iq=ip+1; iq<3; iq++) {
00177             g = 100.0*fabs(a[ip][iq]);
00178 
00179             // after 4 sweeps
00180             if ( i > 3 && (fabs(w[ip])+g) == fabs(w[ip])
00181                  && (fabs(w[iq])+g) == fabs(w[iq])) {
00182               a[ip][iq] = 0.0;
00183       }
00184             else if ( fabs(a[ip][iq]) > tresh) {
00185               h = w[iq] - w[ip];
00186               if ( (fabs(h)+g) == fabs(h)){ t = (a[ip][iq]) / h; }
00187               else {
00188                 theta = 0.5*h / (a[ip][iq]);
00189                 t = 1.0 / (fabs(theta)+sqrt(1.0+theta*theta));
00190                 if (theta < 0.0) { t = -t;}
00191               }
00192               c = 1.0 / sqrt(1+t*t);
00193               s = t*c;
00194               tau = s/(1.0+c);
00195               h = t*a[ip][iq];
00196               z[ip] -= h;
00197               z[iq] += h;
00198               w[ip] -= h;
00199               w[iq] += h;
00200               a[ip][iq]=0.0;
00201               // ip already shifted left by 1 unit
00202               for (j = 0;j <= ip-1;j++) { VTK_ROTATE(a,j,ip,j,iq); }
00203               // ip and iq already shifted left by 1 unit
00204               for (j = ip+1;j <= iq-1;j++) { VTK_ROTATE(a,ip,j,j,iq); }
00205               // iq already shifted left by 1 unit
00206               for (j=iq+1; j<3; j++) { VTK_ROTATE(a,ip,j,iq,j); }
00207               for (j=0; j<3; j++) { VTK_ROTATE(v,j,ip,j,iq); }
00208               }
00209             }
00210           }
00211 
00212         for (ip=0; ip<3; ip++) {
00213           b[ip] += z[ip];
00214           w[ip] = b[ip];
00215           z[ip] = 0.0;
00216         }
00217       }
00218 
00220       if ( i >= MAX_ROTATIONS ) {
00221           std::cerr << "Matrix3D: Error extracting eigenfunctions" << std::endl;
00222           return MB_FAILURE;
00223       }
00224 
00225       // sort eigenfunctions                 these changes do not affect accuracy
00226       for (j=0; j<2; j++){                  // boundary incorrect
00227         k = j;
00228         tmp = w[k];
00229         for (i=j+1; i<3; i++){                // boundary incorrect, shifted already
00230           if (w[i] >= tmp){                  // why exchage if same?
00231             k = i;
00232             tmp = w[k];
00233             }
00234         }
00235         if (k != j){
00236           w[k] = w[j];
00237           w[j] = tmp;
00238           for (i=0; i<3; i++){
00239             tmp = v[i][j];
00240             v[i][j] = v[i][k];
00241             v[i][k] = tmp;
00242             }
00243         }
00244       }
00245       // insure eigenvector consistency (i.e., Jacobi can compute vectors that
00246       // are negative of one another (.707,.707,0) and (-.707,-.707,0). This can
00247       // reek havoc in hyperstreamline/other stuff. We will select the most
00248       // positive eigenvector.
00249       int ceil_half_n = (3 >> 1) + (3 & 1);
00250       for (j=0; j<3; j++) {
00251         for (numPos=0, i=0; i<3; i++) {
00252           if ( v[i][j] >= 0.0 ) { numPos++; }
00253         }
00254     //    if ( numPos < ceil(double(n)/double(2.0)) )
00255         if ( numPos < ceil_half_n) {
00256           for(i=0; i<3; i++) { v[i][j] *= -1.0; }
00257         }
00258       }
00259       return MB_SUCCESS;
00260     }
00261 } //namespace Matrix
00262 
00263 class Matrix3  {
00264   //TODO: std::array when we can use C++11
00265   double d[9];
00266 
00267 public:
00268   //Default Constructor
00269   inline Matrix3(){
00270     for(int i = 0; i < 9; ++i){ d[ i] = 0; }
00271   }
00272   //TODO: Deprecate this.
00273   //Then we can go from three Constructors to one. 
00274   inline Matrix3( double diagonal ){ 
00275       d[0] = d[4] = d[8] = diagonal;
00276       d[1] = d[2] = d[3] = 0.0;
00277       d[5] = d[6] = d[7] = 0.0;
00278   }
00279   inline Matrix3( const CartVect & diagonal ){ 
00280       d[0] = diagonal[0];
00281       d[4] = diagonal[1],
00282       d[8] = diagonal[2];
00283       d[1] = d[2] = d[3] = 0.0;
00284       d[5] = d[6] = d[7] = 0.0;
00285   }
00286   //TODO: not strictly correct as the Matrix3 object
00287   //is a double d[ 9] so the only valid model of T is
00288   //double, or any refinement (int, float) 
00289   //*but* it doesn't really matter anything else
00290   //will fail to compile.
00291   template< typename T> 
00292   inline Matrix3( const std::vector< T> & diagonal ){ 
00293       d[0] = diagonal[0];
00294       d[4] = diagonal[1],
00295       d[8] = diagonal[2];
00296       d[1] = d[2] = d[3] = 0.0;
00297       d[5] = d[6] = d[7] = 0.0;
00298   }
00299 
00300 inline Matrix3( double v00, double v01, double v02,
00301                 double v10, double v11, double v12,
00302                 double v20, double v21, double v22 ){
00303     d[0] = v00; d[1] = v01; d[2] = v02;
00304     d[3] = v10; d[4] = v11; d[5] = v12;
00305     d[6] = v20; d[7] = v21; d[8] = v22;
00306 }
00307 
00308   //Copy constructor 
00309   Matrix3 ( const Matrix3 & f){
00310     for(int i = 0; i < 9; ++i) { d[ i] = f.d[ i]; }
00311   }
00312   //Weird constructors 
00313   template< typename Vector> 
00314   inline Matrix3(   const Vector & row0,
00315                     const Vector & row1,
00316                     const Vector & row2 ) {
00317       for(std::size_t i = 0; i < 3; ++i){
00318     d[ i] = row0[ i];
00319     d[ i+3]= row1[ i];
00320     d[ i+6] = row2[ i];
00321       }
00322   }
00323   
00324   inline Matrix3( const double* v ){ 
00325       d[0] = v[0]; d[1] = v[1]; d[2] = v[2];
00326       d[3] = v[3]; d[4] = v[4]; d[5] = v[5]; 
00327       d[6] = v[6]; d[7] = v[7]; d[8] = v[8];
00328   }
00329   
00330   inline Matrix3& operator=( const Matrix3& m ){
00331       d[0] = m.d[0]; d[1] = m.d[1]; d[2] = m.d[2];
00332       d[3] = m.d[3]; d[4] = m.d[4]; d[5] = m.d[5];
00333       d[6] = m.d[6]; d[7] = m.d[7]; d[8] = m.d[8];
00334       return *this;
00335   }
00336   
00337   inline Matrix3& operator=( const double* v ){ 
00338       d[0] = v[0]; d[1] = v[1]; d[2] = v[2];
00339       d[3] = v[3]; d[4] = v[4]; d[5] = v[5]; 
00340       d[6] = v[6]; d[7] = v[7]; d[8] = v[8];
00341       return *this;
00342  }
00343 
00344   inline double* operator[]( unsigned i ){ return d + 3*i; }
00345   inline const double* operator[]( unsigned i ) const{ return d + 3*i; }
00346   inline double& operator()(unsigned r, unsigned c) { return d[3*r+c]; }
00347   inline double operator()(unsigned r, unsigned c) const { return d[3*r+c]; }
00348   inline double& operator()(unsigned i) { return d[i]; }
00349   inline double operator()(unsigned i) const { return d[i]; }
00350   
00351     // get pointer to array of nine doubles
00352   inline double* array()
00353       { return d; }
00354   inline const double* array() const
00355       { return d; }
00356 
00357   inline Matrix3& operator+=( const Matrix3& m ){
00358       d[0] += m.d[0]; d[1] += m.d[1]; d[2] += m.d[2];
00359       d[3] += m.d[3]; d[4] += m.d[4]; d[5] += m.d[5];
00360       d[6] += m.d[6]; d[7] += m.d[7]; d[8] += m.d[8];
00361       return *this;
00362   }
00363   
00364   inline Matrix3& operator-=( const Matrix3& m ){
00365       d[0] -= m.d[0]; d[1] -= m.d[1]; d[2] -= m.d[2];
00366       d[3] -= m.d[3]; d[4] -= m.d[4]; d[5] -= m.d[5];
00367       d[6] -= m.d[6]; d[7] -= m.d[7]; d[8] -= m.d[8];
00368       return *this;
00369   }
00370   
00371   inline Matrix3& operator*=( double s ){
00372       d[0] *= s; d[1] *= s; d[2] *= s;
00373       d[3] *= s; d[4] *= s; d[5] *= s;
00374       d[6] *= s; d[7] *= s; d[8] *= s;
00375       return *this;
00376  }
00377   
00378   inline Matrix3& operator/=( double s ){
00379       d[0] /= s; d[1] /= s; d[2] /= s;
00380       d[3] /= s; d[4] /= s; d[5] /= s;
00381       d[6] /= s; d[7] /= s; d[8] /= s;
00382       return *this;
00383   }
00384  
00385   inline Matrix3& operator*=( const Matrix3& m ){
00386     (*this) = moab::Matrix::mmult3((*this),m); 
00387     return *this;
00388   }
00389   
00390   inline double determinant() const{
00391     return moab::Matrix::determinant3( *this);
00392   }
00393  
00394   inline Matrix3 inverse() const { 
00395     const double i = 1.0/determinant();
00396     return moab::Matrix::inverse( *this, i); 
00397   }
00398   inline Matrix3 inverse( double i ) const {
00399     return moab::Matrix::inverse( *this, i); 
00400   }
00401   
00402   inline bool positive_definite() const{
00403     double tmp;
00404     return positive_definite( tmp);
00405   }
00406   
00407   inline bool positive_definite( double& det ) const{
00408       return moab::Matrix::positive_definite( *this, det);
00409   }
00410   
00411   inline Matrix3 transpose() const{ return moab::Matrix::transpose( *this); }
00412   
00413   inline bool invert() {
00414     double i = 1.0 / determinant();
00415     if (!finite(i) || fabs(i) < std::numeric_limits<double>::epsilon())
00416       return false;
00417     *this = inverse( i );
00418     return true;
00419   }
00420     // Calculate determinant of 2x2 submatrix composed of the
00421     // elements not in the passed row or column.
00422   inline double subdet( int r, int c ) const{
00423     const int r1 = (r+1)%3, r2 = (r+2)%3;
00424     const int c1 = (c+1)%3, c2 = (c+2)%3;
00425     assert(r >= 0 && c >= 0);
00426     if (r < 0 || c < 0) return DBL_MAX;
00427     return d[3*r1+c1]*d[3*r2+c2] - d[3*r1+c2]*d[3*r2+c1];
00428   }
00429 }; //class Matrix3
00430 
00431 inline Matrix3 operator+( const Matrix3& a, const Matrix3& b ){ 
00432     return Matrix3(a) += b; 
00433 }
00434 inline Matrix3 operator-( const Matrix3& a, const Matrix3& b ){ 
00435     return Matrix3(a) -= b; 
00436 }
00437 
00438 inline Matrix3 operator*( const Matrix3& a, const Matrix3& b ) {
00439     return moab::Matrix::mmult3( a, b);
00440 }
00441 
00442 template< typename Vector>
00443 inline Matrix3 outer_product( const Vector & u,
00444                               const Vector & v ) {
00445   return Matrix3( u[0] * v[0], u[0] * v[1], u[0] * v[2],
00446                   u[1] * v[0], u[1] * v[1], u[1] * v[2],
00447                   u[2] * v[0], u[2] * v[1], u[2] * v[2] );
00448 }
00449 
00450 template< typename T>
00451 inline std::vector< T> operator*( const Matrix3&m, const std::vector< T> & v){
00452         return moab::Matrix::matrix_vector( m, v);
00453 }
00454 
00455 template< typename T>
00456 inline std::vector< T> operator*( const std::vector< T>& v, const Matrix3&m){
00457         return moab::Matrix::vector_matrix( v, m);
00458 }
00459 
00460 inline CartVect operator*( const Matrix3&m,  const CartVect& v){
00461         return moab::Matrix::matrix_vector( m, v);
00462 }
00463 
00464 inline CartVect operator*( const CartVect& v, const Matrix3& m){
00465         return moab::Matrix::vector_matrix( v, m);
00466 }
00467 
00468 } // namespace moab
00469 
00470 #ifndef MOAB_MATRIX3_OPERATORLESS
00471 #define MOAB_MATRIX3_OPERATORLESS
00472 inline std::ostream& operator<<( std::ostream& s, const moab::Matrix3& m ){
00473   return s <<  "| " << m(0,0) << " " << m(0,1) << " " << m(0,2) 
00474            << " | " << m(1,0) << " " << m(1,1) << " " << m(1,2) 
00475            << " | " << m(2,0) << " " << m(2,1) << " " << m(2,2) 
00476            << " |" ;
00477 }
00478 #endif//MOAB_MATRIX3_OPERATORLESS
00479 #endif //MOAB_MATRIX3_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines