matrix.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 // -- IMPORTANT --
00023 // OBS.:
00024 //   Internally, the values are stored as Col-Major, thus a pointer
00025 //   can be passed to FORTRAN routines very easily.
00026 
00027 #ifndef MECHSYS_LINALG_MATRIX_H
00028 #define MECHSYS_LINALG_MATRIX_H
00029 
00030 #ifndef ZERO
00031   #define ZERO 1.0e-10
00032 #endif
00033 
00034 #include <sstream>
00035 #include <cassert>
00036 #include <cmath>
00037 
00038 #include "util/numstreams.h"
00039 
00040 using Util::_8s;
00041 
00042 namespace LinAlg
00043 {
00044 
00045 // Prototype for expression classes
00046 template <class t_exp, class t_res>
00047 class expression;
00048 
00049 template<typename Type>
00050 class Matrix
00051 {
00052 public:
00053     // Default constructor
00054     Matrix() : _rows(0), _cols(0), _values(NULL) {}
00055     // Alternative Constructor
00056     Matrix(int Rows, int Cols)                              : _values(NULL) { _set(Rows,Cols); }
00057     Matrix(int Rows, int Cols, std::string const & strVals) : _values(NULL) { _set(Rows,Cols,strVals); }
00058     Matrix(int N, std::string const & strDiagonal, std::string const & strUpperTriang) : _values(NULL) { _set_sym(N,strDiagonal,strUpperTriang); }
00059     // Destructor
00060     ~Matrix()
00061     {
00062         if (_values!=NULL) delete [] _values;
00063     }
00064     // Copy constructor
00065     Matrix(Matrix<Type> const & Other)
00066     {
00067           _rows = Other.Rows();
00068           _cols = Other.Cols();
00069         _values = new Type [_rows*_cols];
00070         for (int i=0; i<_rows*_cols; ++i)
00071             _values[i] = Other._values[i];
00072     }
00073     // Get
00074            int   Rows()   const { assert(_values!=NULL); return _rows;   }
00075            int   Cols()   const { assert(_values!=NULL); return _cols;   }
00076           Type * GetPtr()       { assert(_values!=NULL); return _values; }
00077     const Type * GetPtr() const { assert(_values!=NULL); return _values; }
00078     Type         Det()    const;
00079     void         Inv(Matrix<Type> & inv) const;
00080     void         Trn(Matrix<Type> & trn) const;
00081     // Set
00082     void Set(int Rows, int Cols)                              { _set(Rows,Cols); }
00083     void Set(int Rows, int Cols, std::string const & strVals) { _set(Rows,Cols,strVals); }
00084     void Set(int N, std::string const & strDiagonal, std::string const & strUpperTriang) { _set_sym(N,strDiagonal,strUpperTriang); }
00085     void SetValues(Type Value) // {{{
00086     {
00087         assert(_values!=NULL);
00088         for (int i=0; i<_rows*_cols; ++i)
00089             _values[i] = Value; 
00090     } // }}}
00091     void Reset(std::string const & strVals) // {{{
00092     {
00093         std::istringstream iss(strVals);
00094         for (int i=0; i<_rows; ++i)
00095         for (int j=0; j<_cols; ++j)
00096             iss >> _values[j*_rows+i]; // Col major
00097     } // }}}
00098     void Resize(int Rows, int Cols) { _resize(Rows,Cols); }
00099     // operators
00100     void operator= (const Matrix<Type> & R) // {{{
00101     {
00102         assert(&R!=this);
00103         if (R.Rows() != _rows || R.Cols() != _cols)
00104         {
00105             _rows = R.Rows();
00106             _cols = R.Cols();
00107             if (_values != NULL) delete [] _values;
00108             _values = new Type [_rows*_cols];
00109         }
00110         
00111         int _components=_rows*_cols;
00112         for (int i=0; i<_components; ++i)
00113             _values[i] = R._values[i];
00114     } // }}}
00115 
00116     // operator to assign values separated by commas {{{
00117     class CommaAssign
00118     {
00119     public:
00120         CommaAssign(Type * Values, int & Rows, int & Cols, Type const & FirstValue):_values(Values),_rows(Rows),_cols(Cols),_index(0) 
00121         { 
00122             assert(_values!=NULL);
00123             _values[0] = FirstValue;
00124             int _components = _rows*_cols;
00125             for (int i=1; i<_components; ++i)
00126                 _values[i] = static_cast<Type>(0);
00127         }
00128         CommaAssign & operator, (Type const & Num) 
00129         {
00130             _index++;
00131             assert(_index < _rows*_cols);
00132             _values[_index/_cols + (_index % _cols) * _rows] = Num; // considering col major
00133             return *this;
00134         }
00135     private:
00136         Type * _values;
00137         int  & _rows;
00138         int  & _cols;
00139         int    _index;
00140     };
00141 
00142     CommaAssign operator= (Type const & Num) 
00143     {
00144         return CommaAssign(_values, _rows, _cols, Num);
00145     } // }}}
00146 
00147     void operator+= (const Matrix<Type> & R) // {{{
00148     {
00149         assert(_values!=NULL);
00150         assert(R.Rows()==_rows);
00151         assert(R.Cols()==_cols);
00152         int _components=_rows*_cols;
00153         for (int i=0; i<_components; ++i)
00154             _values[i] += R._values[i];
00155     } // }}}
00156 
00157     void operator-= (const Matrix<Type> & R) // {{{
00158     {
00159         assert(_values!=NULL);
00160         assert(R.Rows()==_rows);
00161         assert(R.Cols()==_cols);
00162         int _components=_rows*_cols;
00163         for (int i=0; i<_components; ++i)
00164             _values[i] -= R._values[i];
00165     } // }}}
00166     
00167     // Suport for expression evaluation {{{
00168     template<typename t_exp>
00169     void operator  = (const expression<t_exp, Matrix<Type> > & Exp) { Exp.Apply(*this); } 
00170 
00171     template<typename t_exp>
00172     void operator += (const expression<t_exp, Matrix<Type> > & Exp) { Exp.Apply_pe(*this); } 
00173 
00174     template<typename t_exp>
00175     void operator -= (const expression<t_exp, Matrix<Type> > & Exp) { Exp.Apply_me(*this); } // }}}
00176 
00177     Type & operator() (int i, int j) // {{{
00178     {
00179         assert(_values!=NULL);
00180         assert(i>=0 & i<_rows);
00181         assert(j>=0 & j<_cols);
00182         return _values[j*_rows+i]; // Col major
00183     } // }}}
00184     const Type & operator() (int i, int j) const // {{{
00185     {
00186         assert(_values!=NULL);
00187         assert(i>=0 & i<_rows);
00188         assert(j>=0 & j<_cols);
00189         return _values[j*_rows+i]; // Col major
00190     } // }}}
00191 private:
00192     int    _rows;
00193     int    _cols;
00194     Type * _values;
00195     void _set(int Rows, int Cols) // {{{
00196     {
00197         assert(_values==NULL);
00198         assert(Rows>0);
00199         assert(Cols>0);
00200           _rows = Rows;
00201           _cols = Cols;
00202         _values = new Type [_rows*_cols];
00203         for (int i=0; i<_rows*_cols; ++i)
00204             _values[i] = static_cast<Type>(0);
00205     } // }}}
00206     void _set(int Rows, int Cols, std::string const & strVals) // {{{
00207     {
00208         assert(_values==NULL);
00209         assert(Rows>0);
00210         assert(Cols>0);
00211           _rows = Rows;
00212           _cols = Cols;
00213         _values = new Type [_rows*_cols];
00214         std::istringstream iss(strVals);
00215         for (int i=0; i<_rows; ++i)
00216         for (int j=0; j<_cols; ++j)
00217             iss >> _values[j*_rows+i]; // Col major
00218     } // }}}
00219     void _resize(int Rows, int Cols) // {{{
00220     {
00221         assert(Rows>0);
00222         assert(Cols>0);
00223         if (Rows==_rows && Cols==_cols && _values!=NULL) return;    
00224         if (_values!=NULL) delete [] _values;
00225         _rows = Rows;
00226         _cols = Cols;
00227         _values = new Type [_rows*_cols];
00228     } // }}}
00229     void _set_sym(int N, std::string const & strDiagonal, std::string const & strUpperTriang) // {{{
00230     {
00231         assert(N>0);
00232           _rows = N;
00233           _cols = N;
00234         _values = new Type [_rows*_cols];
00235         std::stringstream iss_D  (strDiagonal);
00236         std::stringstream iss_UT (strUpperTriang);
00237         // diagonal
00238         for (int i=0; i<N; ++i)
00239             iss_D >> _values[i*_rows+i]; // Col major
00240         // upper triangle (and lower triangle)
00241         for (int i=0; i<N-1; ++i)
00242         for (int j=i+1; j<N; ++j)
00243         {
00244             iss_UT >> _values[j*_rows+i]; // Col major
00245             _values[i*_rows+j] = _values[j*_rows+i];
00246         } // }}}
00247     }
00248 
00249 }; // class Matrix<Type>
00250 
00251 template<typename Type>
00252 std::ostream & operator<< (std::ostream & os, const Matrix<Type> & M) // {{{
00253 {
00254     os << std:: endl;
00255     for (int i=0; i<M.Rows(); ++i)
00256     {
00257         for (int j=0; j<M.Cols(); ++j)
00258             os << _8s()<< M(i,j);
00259         os << std::endl;
00260     }
00261     return os;
00262 } // }}}
00263 
00264 // determinant of a matrix
00265 template<typename Type>
00266 inline Type Matrix<Type>::Det() const // {{{
00267 {
00268     Matrix<Type> const & M = (*this);
00269     Type _det;
00270     if (_rows==1)
00271     {
00272         _det = 0;
00273         for (int i=0; i<_cols; i++) _det += pow(M(0,i),2);
00274         _det = pow(_det, 0.5);
00275     } 
00276     else if (_rows==3 && _cols==3)
00277     {
00278         _det =   M(0,0)*(M(1,1)*M(2,2) - M(1,2)*M(2,1)) \
00279                - M(0,1)*(M(1,0)*M(2,2) - M(1,2)*M(2,0)) \
00280                + M(0,2)*(M(1,0)*M(2,1) - M(1,1)*M(2,0));
00281     }
00282     else if (_rows==2 && _cols==3)
00283     {
00284         Type d1 = M(0,0)*M(1,1) - M(0,1)*M(1,0);
00285         Type d2 = M(0,1)*M(1,2) - M(0,2)*M(1,1);
00286         Type d3 = M(0,2)*M(1,0) - M(0,0)*M(1,2);
00287         _det = sqrt(d1*d1 + d2*d2 + d3*d3);
00288     }
00289     else
00290     {
00291         std::ostringstream oss;
00292         oss << "Matrix::Det: Determinant for a (" << _rows << " x " << _cols << ") matrix is not available\n"; // TODO: ??? << check error
00293         throw oss.str().c_str();
00294     }
00295     return _det;
00296 } // }}}
00297 
00298 template<typename Type>
00299 inline void Matrix<Type>::Inv(Matrix<Type> & inv) const // {{{
00300 {
00301     inv.Resize(_rows, _cols);
00302     Matrix<Type> const & M = (*this);
00303     if (_rows==3 && _cols==3) // && _rows()==3 && Inv.Cols()==3)
00304     {
00305         inv.Resize(3,3);
00306         Type det = Det();
00307         if (fabs(det)<ZERO)
00308             throw "Matrix::Inv: Could not calculate inverse because determinant is equal to zero\n";
00309         
00310         inv(0,0) = (M(1,1)*M(2,2) - M(1,2)*M(2,1)) / det;
00311         inv(0,1) = (M(0,2)*M(2,1) - M(0,1)*M(2,2)) / det;
00312         inv(0,2) = (M(0,1)*M(1,2) - M(0,2)*M(1,1)) / det;
00313         
00314         inv(1,0) = (M(1,2)*M(2,0) - M(1,0)*M(2,2)) / det;
00315         inv(1,1) = (M(0,0)*M(2,2) - M(0,2)*M(2,0)) / det;
00316         inv(1,2) = (M(0,2)*M(1,0) - M(0,0)*M(1,2)) / det;
00317         
00318         inv(2,0) = (M(1,0)*M(2,1) - M(1,1)*M(2,0)) / det;
00319         inv(2,1) = (M(0,1)*M(2,0) - M(0,0)*M(2,1)) / det;
00320         inv(2,2) = (M(0,0)*M(1,1) - M(0,1)*M(1,0)) / det;
00321     }
00322     else
00323     {
00324         inv.Resize(_rows,_cols);
00325         Matrix<Type> extended(_rows, _cols*2);
00326 
00327         //extending Matrix
00328         for (int r = 0; r < _rows; r++) 
00329             for (int c = 0; c < _cols; c++) 
00330             {
00331                 extended(r,c) = this->operator()(r,c);
00332                 if (r == c) extended(r,c+_rows) = 1;
00333                 else extended(r,c+_rows) = 0;
00334             }
00335 
00336         for (int p = 0; p < _cols; p++) //triangulation
00337         { 
00338             for (int r = p + 1; r < _rows; r++)
00339             {
00340                 //pivoting
00341                 if (fabs(extended(p,p))<1.e-10)
00342                 { 
00343                     //lookin for a line with non zero value in pivot column
00344                     int rr;
00345                     for (rr = p; rr < _rows; rr++) if (fabs(extended(rr,p)) >= 1.e-10) break; 
00346                     if (rr==_rows) throw "Matrix::Inv: Error calculating inverse matrix): singular matrix";
00347                     for (int c = p; c < _cols*2; c++){
00348                         Type temp = extended(p,c);
00349                         extended(p,c) = extended(rr,c); 
00350                         extended(rr,c) = temp;
00351                     }
00352                 }
00353                 Type coef = extended(r,p) / extended(p,p);
00354                 for (int c = p; c < _cols*2; c++)
00355                     extended(r,c) -= coef * extended(p,c);
00356             }
00357         }
00358 
00359         //Retro-Triangulation
00360         for (int p = _rows-1; p > 0; p--)
00361         { 
00362             for (int r = p-1; r >= 0; r--)
00363             {
00364                 Type coef = extended(r,p) / extended(p,p);
00365                 for (int c = _cols*2-1; c >= p; c--)  
00366                     extended(r,c) -= coef * extended(p,c);
00367             }
00368         }
00369         
00370         //copying inverse Matrix and dividing by diagonal value
00371         for (int r = 0; r < _rows; r++)
00372             for (int c = 0; c < _cols; c++)
00373                 inv(r,c) = extended(r,c+_rows) / extended(r,r); 
00374         
00375     }
00376 } // }}}
00377 
00378 template<typename Type>
00379 inline void Matrix<Type>::Trn(Matrix<Type> & trn) const // {{{
00380 {
00381     trn.Resize(_cols, _rows);
00382     Matrix<Type> const & M = (*this);
00383     for (int r = 0; r < _rows; r++) 
00384         for (int c = 0; c < _cols; c++) 
00385             trn(c,r) = M(r,c);
00386     
00387 } // }}}
00388 
00389 }; // namespace LinAlg
00390 
00391 #endif // MECHSYS_LINALG_MATRIX_H
00392 
00393 // vim:fdm=marker

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