MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/linalg/matrix.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 #ifndef MECHSYS_LINALG_MATRIX_H
00020 #define MECHSYS_LINALG_MATRIX_H
00021 
00022 // STL
00023 #include <iostream>
00024 #include <cmath>
00025 
00026 // MechSys
00027 #include <mechsys/util/fatal.h>
00028 
00029 extern "C"
00030 {
00031     // BLAS
00032     void dscal_(int const *N, double const *alpha, double *X, int const *incX);
00033     void dcopy_(int const *N, double const *X, int const *incX, double *Y, int const *incY);
00034     void daxpy_(int const *N, double const *alpha, double const *X, int const *incX, double *Y, int const *incY);
00035 }
00036 
00037 namespace LinAlg
00038 {
00039 
00040 // Prototype for expression classes
00041 template <class t_exp, class t_res>
00042 class expression; // should not be called (directly) by the user
00043 
00056 template<typename Value_T>
00057 class Matrix
00058 {
00059 public:
00060     // Constructors
00061     Matrix () : _rows(0), _cols(0), _values(NULL), data(_values) {} 
00062     Matrix (int Rows, int Cols);                                    
00063     Matrix (Matrix<Value_T> const & Other);                         
00064 
00066     ~Matrix () { if (_values!=NULL) delete [] _values; }
00067 
00068     // Access methods
00069     int             Rows     () const; 
00070     int             Cols     () const; 
00071     size_t          num_rows () const { return (size_t)Rows(); }
00072     size_t          num_cols () const { return (size_t)Cols(); }
00073     Value_T const * GetPtr   () const; 
00074     Value_T       * GetPtr   ();       
00075 
00076     // Methods
00077     void Resize     (int Rows, int Cols); 
00078     void change_dim (int Rows, int Cols) { Resize(Rows,Cols); }
00079     void SetValues  (Value_T Value);      
00080 
00081     // Operators
00082     void            operator=  (Matrix<Value_T> const & R); 
00083     void            operator+= (Matrix<Value_T> const & R); 
00084     void            operator-= (Matrix<Value_T> const & R); 
00085     void            operator/= (Value_T const & Scalar);    
00086     void            operator*= (Value_T const & Scalar);    
00087     Value_T &       operator() (int i, int j);              
00088     const Value_T & operator() (int i, int j) const;        
00089     
00090     // Auxiliar structures
00091     // operator to assign values separated by commas \cond
00092     class CommaAssign
00093     {
00094     public:
00095         CommaAssign(Value_T * Values, int & Rows, int & Cols, Value_T const & FirstValue):_values(Values),_rows(Rows),_cols(Cols),_index(0) 
00096         { 
00097             if (_values==NULL) throw new Fatal("Matrix::CommaAssign::CommaAssign (_values==NULL). The matrix must be resized prior to use this method.");
00098             _values[0] = FirstValue;
00099             int _components = _rows*_cols;
00100             for (int i=1; i<_components; ++i)
00101                 _values[i] = static_cast<Value_T>(0);
00102         }
00103         CommaAssign & operator, (Value_T const & Num) 
00104         {
00105             _index++;
00106             if (_index>=_rows*_cols) throw new Fatal("Matrix::CommaAssign::operator, (_index>=_rows*_cols). There are too many values in the comma expression to be assigned to this matrix.");
00107             _values[_index/_cols + (_index % _cols) * _rows] = Num; // considering col major
00108             return *this;
00109         }
00110     private:
00111         Value_T * _values;
00112         int     & _rows;
00113         int     & _cols;
00114         int       _index;
00115     };
00116 
00117     CommaAssign operator= (Value_T const & Num) 
00118     {
00119         return CommaAssign(_values, _rows, _cols, Num);
00120     }
00121 
00122     // Methods required by the expressions evaluation
00123     template<typename t_exp>
00124     void operator= (const expression<t_exp, Matrix<Value_T> > & Exp) { Exp.Apply(*this); } 
00125 
00126     template<typename t_exp>
00127     void operator+= (const expression<t_exp, Matrix<Value_T> > & Exp) { Exp.Apply_pe(*this); } 
00128 
00129     template<typename t_exp>
00130     void operator-= (const expression<t_exp, Matrix<Value_T> > & Exp) { Exp.Apply_me(*this); }
00131     // \endcond
00132 
00133 private:
00134     // Data
00135     int       _rows;   
00136     int       _cols;   
00137     Value_T * _values; 
00138 
00139 public:
00140     Value_T * data;
00141 
00142 }; // class Matrix
00143 
00144 
00146 
00147 
00148 // Constructors
00149 
00150 template<typename Value_T>
00151 inline Matrix<Value_T>::Matrix(int Rows, int Cols)
00152     : _rows(0), _cols(0), _values(NULL), data(_values)
00153 {
00154     if (Rows>0 && Cols>0)
00155     {
00156         _rows = Rows;
00157         _cols = Cols;
00158         _values = new Value_T [_rows*_cols];
00159         for (int i=0; i<_rows*_cols; ++i)
00160             _values[i] = static_cast<Value_T>(0);
00161         data = _values;
00162     }
00163 }
00164 
00165 template<typename Value_T>
00166 inline Matrix<Value_T>::Matrix(Matrix<Value_T> const & R)
00167     : _rows(R.Rows()), _cols(R.Cols()), _values(NULL), data(_values)
00168 {
00169     if (_rows>0 && _cols>0)
00170     {
00171         // allocate memory
00172         _values = new Value_T [_rows*_cols];
00173         data    = _values;
00174 
00175         // copy
00176         int n = _rows*_cols;
00177         int i = 1;
00178         int j = 1;
00179         dcopy_ (&n, R.GetPtr(), &i, _values, &j);
00180     }
00181 }
00182 
00183 // Access methods
00184 
00185 template<typename Value_T>
00186 inline int Matrix<Value_T>::Rows() const
00187 {
00188     return _rows;
00189 }
00190 
00191 template<typename Value_T>
00192 inline int Matrix<Value_T>::Cols() const
00193 {
00194     return _cols;
00195 }
00196 
00197 template<typename Value_T>
00198 inline Value_T * Matrix<Value_T>::GetPtr()
00199 {
00200 #ifndef DNDEBUG
00201     //if (_values==NULL) throw new Fatal("Matrix::GetPtr: (_values==NULL). The matrix must be resized prior to get a pointer to its values.");
00202 #endif
00203     return _values;
00204 }
00205 
00206 template<typename Value_T>
00207 inline const Value_T * Matrix<Value_T>::GetPtr() const
00208 {
00209 #ifndef DNDEBUG
00210     //if (_values==NULL) throw new Fatal("Matrix::GetPtr: (_values==NULL). The matrix must be resized prior to get a pointer to its values.");
00211 #endif
00212     return _values;
00213 }
00214 
00215 // Methods
00216 
00217 template<typename Value_T>
00218 inline void Matrix<Value_T>::Resize(int Rows, int Cols)
00219 {
00220     if (Rows>0 && Cols>0)
00221     {
00222         if (Rows==_rows && Cols==_cols && _values!=NULL) return;    
00223         if (_values!=NULL) delete [] _values;
00224         _rows   = Rows;
00225         _cols   = Cols;
00226         _values = new Value_T [_rows*_cols];
00227         data    = _values;
00228         for (int i=0; i<_rows*_cols; ++i) _values[i] = static_cast<Value_T>(0);
00229     }
00230     else
00231     {
00232         if (_values!=NULL) delete [] _values;
00233         _rows   = 0;
00234         _cols   = 0;
00235         _values = NULL;
00236         data    = _values;
00237     }
00238 }
00239 
00240 template<typename Value_T>
00241 inline void Matrix<Value_T>::SetValues(Value_T Value)
00242 {
00243 #ifndef DNDEBUG
00244     if (_values==NULL) throw new Fatal("Matrix::SetValues: (_values==NULL). The matrix must be resized prior to set its values.");
00245 #endif
00246     for (int i=0; i<_rows*_cols; ++i)
00247         _values[i] = Value; 
00248 }
00249 
00250 // Operators
00251 
00252 template<typename Value_T>
00253 inline void Matrix<Value_T>::operator= (Matrix<Value_T> const & R)
00254 {
00255 #ifndef DNDEBUG
00256     if (&R==this) throw new Fatal("Matrix::operator= The right-hand-size of this operation (LHS = RHS) must not be equal to the LHS.");
00257 #endif
00258 
00259     // reallocate if they are different (LHS != RHS)
00260     if (_values==NULL || R.Rows()!=_rows || R.Cols()!=_cols)
00261     {
00262         _rows = R.Rows();
00263         _cols = R.Cols();
00264         if (_values!=NULL) delete [] _values;
00265         _values = new Value_T [_rows*_cols];
00266         data    = _values;
00267     }
00268 
00269     // copy
00270     int n = _rows*_cols;
00271     int i = 1;
00272     int j = 1;
00273     dcopy_ (&n, R.GetPtr(), &i, _values, &j);
00274 }
00275 
00276 template<typename Value_T>
00277 inline void Matrix<Value_T>::operator+= (Matrix<Value_T> const & R)
00278 {
00279 #ifndef DNDEBUG
00280     if (_values==NULL  ) return;//throw new Fatal("Matrix::operator+= (_values==NULL). The matrix must be resized prior to use this method.");
00281     if (R.Rows()!=_rows) throw new Fatal("Matrix::operator+= (R.Rows()!=_rows). The number of Rows of the LHS (%d) must be equal to the number of rows of the RHS (%d).",R.Rows(),_rows);
00282     if (R.Cols()!=_cols) throw new Fatal("Matrix::operator+= (R.Rows()!=_cols). The number of Cols of the LHS (%d) must be equal to the number of cols of the RHS (%d).",R.Cols(),_cols);
00283 #endif
00284     int     n = _rows*_cols;
00285     Value_T a = 1.0;
00286     int     i = 1;
00287     int     j = 1;
00288     daxpy_ (&n, &a, R.GetPtr(), &i, _values, &j);
00289 }
00290 
00291 template<typename Value_T>
00292 inline void Matrix<Value_T>::operator-= (Matrix<Value_T> const & R)
00293 {
00294 #ifndef DNDEBUG
00295     if (_values==NULL  ) return;//throw new Fatal("Matrix::operator-= (_values==NULL). The matrix must be resized prior to use this method.");
00296     if (R.Rows()!=_rows) throw new Fatal("Matrix::operator-= (R.Rows()!=_rows). The number of Rows of the LHS (%d) must be equal to the number of rows of the RHS (%d).",R.Rows(),_rows);
00297     if (R.Cols()!=_cols) throw new Fatal("Matrix::operator-= (R.Rows()!=_cols). The number of Cols of the LHS (%d) must be equal to the number of cols of the RHS (%d).",R.Cols(),_cols);
00298 #endif
00299     int     n = _rows*_cols;
00300     Value_T a = -1.0;
00301     int     i = 1;
00302     int     j = 1;
00303     daxpy_ (&n, &a, R.GetPtr(), &i, _values, &j);
00304 }
00305 
00306 template<typename Value_T>
00307 inline void Matrix<Value_T>::operator/= (Value_T const & Scalar)
00308 {
00309 #ifndef DNDEBUG
00310     if (_values==NULL) return;//throw new Fatal("Matrix::operator/= (_values==NULL). The matrix must be resized before calling this method.");
00311 #endif
00312     int     n = _rows*_cols;
00313     Value_T a = 1.0/Scalar;
00314     int     d = 1;
00315     dscal_ (&n, &a, _values, &d);
00316 }
00317 
00318 template<typename Value_T>
00319 inline void Matrix<Value_T>::operator*= (Value_T const & Scalar)
00320 {
00321 #ifndef DNDEBUG
00322     if (_values==NULL) return;//throw new Fatal("Matrix::operator*= (_values==NULL). The matrix must be resized before calling this method.");
00323 #endif
00324     int     n = _rows*_cols;
00325     Value_T a = Scalar;
00326     int     d = 1;
00327     dscal_ (&n, &a, _values, &d);
00328 }
00329 
00330 template<typename Value_T>
00331 inline Value_T & Matrix<Value_T>::operator() (int i, int j)
00332 {
00333 #ifndef DNDEBUG
00334     if (_values==NULL  ) throw new Fatal("Matrix::operator() (_values==NULL). The matrix must be resized prior to use this method.");
00335     if (i<0 || i>=_rows) throw new Fatal("Matrix::operator() (i<0 || i>=_rows). The index (i=%d) for a row must be greater than/or equal to zero and smaller than the number of rows (nrow=%d).",i,_rows);
00336     if (j<0 || j>=_cols) throw new Fatal("Matrix::operator() (j<0 || j>=_cols). The index (j=%d) for a column must be greater than/or equal to zero and smaller than the number of columns (ncol=%d).",j,_cols);
00337 #endif
00338     return _values[j*_rows+i]; // Col major
00339 }
00340 
00341 template<typename Value_T>
00342 inline const Value_T & Matrix<Value_T>::operator() (int i, int j) const
00343 {
00344 #ifndef DNDEBUG
00345     if (_values==NULL  ) throw new Fatal("Matrix::(const)operator() (_values==NULL). The matrix must be resized prior to use this method.");
00346     if (i<0 || i>=_rows) throw new Fatal("Matrix::(const)operator() (i<0 || i>=_rows). The index (i=%d) for a row must be greater than/or equal to zero and smaller than the number of rows (nrow=%d).",i,_rows);
00347     if (j<0 || j>=_cols) throw new Fatal("Matrix::(const)operator() (j<0 || j>=_cols). The index (j=%d) for a column must be greater than/or equal to zero and smaller than the number of columns (ncol=%d).",j,_cols);
00348 #endif
00349     return _values[j*_rows+i]; // Col major
00350 }
00351 
00353 template<typename Value_T>
00354 std::ostream & operator<< (std::ostream & os, const Matrix<Value_T> & M)
00355 {
00356     for (int i=0; i<M.Rows(); ++i)
00357     {
00358         for (int j=0; j<M.Cols(); ++j) os << M(i,j) << " ";
00359         os << std::endl;
00360     }
00361     return os;
00362 }
00363 
00364 
00365 }; // namespace LinAlg
00366 
00367 #endif // MECHSYS_LINALG_MATRIX_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines