Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

matrix.h

Go to the documentation of this file.
00001 // -*-c++-*-
00002 #ifndef IG_MATRIX_H
00003 #define IG_MATRIX_H
00004 
00005 // $Id: matrix.h,v 1.40 2005/05/30 09:13:02 hkuiper Exp $
00006 
00007 // CwMtx matrix and vector math library
00008 // Copyright (C) 1999-2001  Harry Kuiper
00009 // Copyright (C) 2000  Will DeVore (template conversion)
00010 
00011 // This library is free software; you can redistribute it and/or
00012 // modify it under the terms of the GNU Lesser General Public
00013 // License as published by the Free Software Foundation; either
00014 // version 2 of the License, or (at your option) any later version.
00015 
00016 // This library is distributed in the hope that it will be useful,
00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019 // Lesser General Public License for more details.
00020 
00021 // You should have received a copy of the GNU Lesser General Public
00022 // License along with this library; if not, write to the Free Software
00023 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00024 // USA
00025 
00026 #include <iostream>
00027 #include <iomanip>
00028 
00029 // CWMatrix class
00030 
00031 // This library was designed to mirror as closely as possible the
00032 // notation used in mathematical writing. A matrix is indexed:
00033 // matMatrixName[row][col].
00034 
00035 // CAUTION!!!
00036 
00037 // This matrix library was implemented with emphasis on
00038 // speed. Consequently no attempts were made to trap and report
00039 // errors. It is left entirely to the user to write code that does not
00040 // cause errors within the matrix routines.
00041 
00042 namespace CwMtx
00043 {
00044   using std::ostream;
00045 
00046   // matrix status values
00047   enum { N_NOTALLOCATED, N_ALLOCATED, N_MAPPED };
00048 
00049   // Classes that create unity and zero "objects".  The ones directly
00050   // below work only for template arguments that are basic (numerical)
00051   // types that can be initialised by a literal 0 or 1.
00052   template <class T> class CWTUnity
00053   {
00054   public:
00055     operator T() { return 1; }
00056   };
00057 
00058   template <class T> class CWTZero
00059   {
00060   public:
00061     operator T() { return 0; }
00062   };
00063 
00064   // This template defaults to double. Most of the time this template
00065   // will be working with math functions that only work with
00066   // doubles. For example, the transcendental function sin(x) takes
00067   // and returns a double which would force the compiler to convert
00068   // back and forth from some other data type to a double.
00069 
00070   // prefix mat
00071   template < class T = double >
00072   class CWTMatrix
00073   {
00074   public:
00075     typedef T element;
00076 
00077     // creates a matrix, does NOT allocate rows and columns
00078     CWTMatrix();
00079     // creates a matrix, allocates rows and columns
00080     CWTMatrix(unsigned, unsigned);
00081     CWTMatrix(const CWTMatrix &);
00082     // sub-matrix mapped into another
00083     CWTMatrix(const CWTMatrix &, unsigned, unsigned, unsigned, unsigned);
00084         
00085     // removes matrix elements from free store
00086     ~CWTMatrix() { deallocate(); };
00087 
00088     // allocates rows and colums
00089     void dimension(unsigned, unsigned);
00090     // maps matrix into another
00091     void mapInto(const CWTMatrix&, unsigned, unsigned, unsigned, unsigned);
00092     // reverses the effect of dimension() and mapInto()
00093     void deallocate();
00094 
00095     int getStatus() const { return m_nMatStatus; };
00096     unsigned getRows() const { return m_crow; };
00097     unsigned getCols() const { return m_ccol; };
00098 
00099     // basic matrix operations
00100 
00101     // returns a row of modifyable elements
00102     T* operator [](unsigned irow) { return m_rgrow[irow]; };
00103     // returns a row of non-modifyable elements
00104     const T* operator [](unsigned irow) const { return m_rgrow[irow]; };
00105 
00106     CWTMatrix operator +(const CWTMatrix &) const;
00107     CWTMatrix operator -(const CWTMatrix &) const;
00108     CWTMatrix operator -() const;
00109     CWTMatrix operator *(const T &) const;
00110     CWTMatrix operator *(const CWTMatrix &) const;
00111 
00112     // Interesting note here. Because we are defining the "/" operator
00113     // we can't expect to use it inside the definition unless we
00114     // safely restrict it to operating on constants. Without the
00115     // parens the operator does the "* 1" first then does the
00116     // "/value" which then leads to calling the "/" etc...  With the
00117     // parens, the intended scalar operation, "1/value", occurs
00118     // first then the Matrix/Scalar operations occur.  If the parens
00119     // are missing in the operator below, an ifinite loop
00120     // occurs. -----------------------------------------------V----------V
00121     CWTMatrix operator /(const T &value) const
00122     {
00123       // NOTE: This used to work with g++ <= 3.2.
00124       // return (*this)*static_cast<const T &>(CWTUnity<T>()/value);
00125 
00126       T tTmp = CWTUnity<T>();
00127       tTmp /= value;
00128       return (*this)*tTmp;
00129     }
00130 
00131     // not inherited
00132     CWTMatrix & operator =(const CWTMatrix &);
00133     CWTMatrix & operator +=(const CWTMatrix &);
00134     CWTMatrix & operator -=(const CWTMatrix &);
00135     CWTMatrix & operator *=(const T &);
00136     CWTMatrix & operator /=(const T &value)
00137     {
00138       // NOTE: This used to work with g++ <= 3.2.
00139       // return (*this) *= static_cast<const T &>(CWTUnity<T>()/value);
00140 
00141       T tTmp = CWTUnity<T>();
00142       tTmp /= value;
00143       return (*this) *= tTmp;
00144     }
00145 
00146     int operator ==(const CWTMatrix &) const;
00147     int operator !=(const CWTMatrix &mat) const { return !( (*this) == mat ); }
00148 
00149     // stores CWMatrix + CWMatrix in this
00150     void storeSum(const CWTMatrix &, const CWTMatrix &);
00151     // stores CWMatrix*CWMatrix in this
00152     void storeProduct(const CWTMatrix &, const CWTMatrix &);
00153     // stores transpose of CWMatrix in this
00154     void storeTranspose(const CWTMatrix &);
00155     // stores CWMatrix at indicated position in this
00156     void storeAtPosition(unsigned, unsigned, const CWTMatrix &);
00157     // fills the whole array with a value.
00158     void fill(const T &);
00159 
00160     void interchangeRows(unsigned, unsigned);
00161     void addRowToRow(unsigned, unsigned, const T & = CWTUnity<T>());
00162     void multiplyRow(unsigned, const T &);
00163 
00164   private:
00165     // initializes data members
00166     void initialize();
00167 
00168     // we keep the data structures used for CWMatrix implementation
00169     // private
00170 
00171     // row count
00172     unsigned m_crow;
00173     // column count
00174     unsigned m_ccol;
00175     // an array of rows (stored on free store)
00176     T **m_rgrow;
00177     // matrix status
00178     int m_nMatStatus;
00179   };
00180 
00181   // Templates to create self-dimensioning CWTMatrix classes - or one
00182   // of its derived classes - using the syntax of a default
00183   // constructor.  This facility is required for using matrices as
00184   // elements of matrices since these will always be created by a call
00185   // to the default constructor.
00186 
00187   template <class T, unsigned crow, unsigned ccol>
00188   class CWTMat: public T
00189   {
00190   public:
00191     CWTMat(): T(crow, ccol) {}
00192 
00193     T & operator =(const T &mtx) { return T::operator=(mtx); }
00194   };
00195 
00196   // NOTE: There exists no unity matrix for a non-square matrix!
00197 
00198   // Zero matrix.  NOTE: A zero matrix can only be constructed for a
00199   // matrix of known dimensions.  Hence the use of CWTMat<T,n,m>.
00200   template <class T, unsigned crow, unsigned ccol>
00201   class CWTZero< CWTMat<CWTMatrix<T>, crow, ccol> >:
00202     public CWTMat<CWTMatrix<T>, crow, ccol>
00203   {
00204   public:
00205     CWTZero() { fill(CWTZero<T>()); }
00206   };
00207 
00208   //
00209   // Constructors
00210   //
00211 
00212   template < class T >
00213   inline CWTMatrix<T>::CWTMatrix()
00214   {
00215     initialize();
00216   };
00217 
00218   // creates a matrix, allocates rows and columns
00219   template < class T >
00220   inline CWTMatrix<T>::CWTMatrix(unsigned crow, unsigned ccol)
00221   {
00222     initialize();
00223     dimension(crow, ccol);
00224   }
00225 
00226   template < class T >
00227   inline CWTMatrix<T>::CWTMatrix(const CWTMatrix<T> &mat)
00228   {
00229     initialize();
00230 
00231     if (mat.m_nMatStatus == N_NOTALLOCATED)
00232       {
00233         // input matrix not allocated, so there's nothing to copy
00234         return;
00235       }
00236     else
00237       {
00238         // copy contents of input matrix
00239         (*this) = mat;
00240       }
00241   }
00242 
00243   // Mapped matrix constructor
00244   template < class T >
00245   inline CWTMatrix<T>::CWTMatrix(const CWTMatrix<T> &mat,
00246                                  unsigned irowStart,
00247                                  unsigned icolStart,
00248                                  unsigned irowEnd,
00249                                  unsigned icolEnd)
00250   {
00251     initialize();
00252     mapInto(mat, irowStart, icolStart, irowEnd, icolEnd);
00253   }
00254 
00255   //
00256   // Private Methods
00257   //
00258 
00259   // initial values for matrix attributes
00260   template < class T >
00261   inline void CWTMatrix<T>::initialize()
00262   {
00263     m_crow       = 0;
00264     m_ccol       = 0;
00265     m_rgrow      = NULL;
00266     m_nMatStatus = N_NOTALLOCATED;
00267   }
00268 
00269   //
00270   // User Methods
00271   //
00272 
00273   template < class T >
00274   void CWTMatrix<T>::dimension(unsigned crowInit, unsigned ccolInit)
00275   {
00276     if (m_nMatStatus != N_NOTALLOCATED)
00277       {
00278         deallocate();
00279       }
00280 
00281     m_crow = crowInit;
00282     m_ccol = ccolInit;
00283 
00284 #ifdef CC_CWTMTX_ASSUME_BASIC_TYPES
00285     // NOTE: CWTMatrix normally uses the standard C++ new() operator
00286     // to allocate memory for matrix elements.  Using malloc(3) can
00287     // save time because it can allocate all required memory in a
00288     // single call.  However, malloc(3) only works for template
00289     // arguments that are C++ basic types because basic types are no
00290     // classes and thus need not be initialised by a constructor.  To
00291     // use malloc(3) #define CC_CWTMTX_ASSUME_BASIC_TYPES in all
00292     // source files that use CWTMatrix templates before you #include
00293     // them.
00294 
00295     // Allocate space for row pointers and the rows themselves using
00296     // ANSI C malloc(3) function.
00297     m_rgrow = reinterpret_cast<T **>(malloc(m_crow*sizeof(T *)
00298                                             + m_crow*m_ccol*sizeof(T)));
00299     T *ptTmp = reinterpret_cast<T *>(&(m_rgrow[m_crow]));
00300 #else
00301     // Allocate space for row pointers and the rows themselves using
00302     // ANSI C++ new() operator.
00303     m_rgrow = new T*[m_crow];
00304     T *ptTmp = new T[m_crow*m_ccol];
00305 #endif
00306 
00307     // make row pointers point to start of each row
00308     for (unsigned irow = 0; irow < m_crow; ++irow)
00309       {
00310         m_rgrow[irow] = &(ptTmp[irow*m_ccol]);
00311       }
00312 
00313     m_nMatStatus = N_ALLOCATED;
00314   }
00315 
00316   // maps a matrix into another matrix, deallocates first if neccesary
00317   // allocates space on the free store for a matrix, deallocates first
00318   // if neccesary
00319   template < class T >
00320   void CWTMatrix<T>::mapInto(const CWTMatrix<T> &mat,
00321                              unsigned irowStart,
00322                              unsigned icolStart,
00323                              unsigned irowEnd,
00324                              unsigned icolEnd )
00325   {
00326     if (m_nMatStatus != N_NOTALLOCATED)
00327       {
00328         deallocate();
00329       }
00330 
00331     // calculate columns
00332     m_crow = irowEnd - irowStart + 1;
00333 
00334     // calculate rows
00335     m_ccol = icolEnd - icolStart + 1;
00336 
00337     // allocate space for row pointers
00338 #ifdef CC_CWTMTX_ASSUME_BASIC_TYPES
00339     m_rgrow = reinterpret_cast<T **>(malloc(m_crow*sizeof(T *)));
00340 #else
00341     m_rgrow = new T*[m_crow];
00342 #endif
00343 
00344     for (unsigned irow = 0; irow < m_crow; ++irow)
00345       {
00346         // get values for row pointers
00347         m_rgrow[irow] = &mat.m_rgrow[irow + irowStart][icolStart];
00348       }
00349 
00350     m_nMatStatus = N_MAPPED;
00351   }
00352 
00353   // deallocates a matrix' elements from the free store
00354   template < class T >
00355   void CWTMatrix<T>::deallocate()
00356   {
00357     // has to take account of the state the matrix is in
00358     switch (m_nMatStatus)
00359       {
00360       case N_NOTALLOCATED:
00361         // nothing needs to be deallocated
00362         break;
00363 
00364       case N_MAPPED:
00365         // delete the array of row pointers
00366 #ifdef CC_CWTMTX_ASSUME_BASIC_TYPES
00367         free(m_rgrow);
00368 #else
00369         delete [] m_rgrow;
00370 #endif
00371         break;
00372 
00373       case N_ALLOCATED:
00374         //   delete the contents of the matrix completely
00375 #ifdef CC_CWTMTX_ASSUME_BASIC_TYPES
00376         // Deallocate space for row pointers and the rows themselves
00377         // using ANSI C free(3) function.
00378         free(m_rgrow);
00379 #else
00380         // Deallocate space for row pointers and the rows themselves
00381         // using ANSI C++ delete() operator.
00382         delete [] *m_rgrow;
00383         delete [] m_rgrow;
00384 #endif
00385         break;
00386       };
00387 
00388     // bring this matrix in initialized state
00389     initialize();
00390   }
00391 
00392   template < class T >
00393   CWTMatrix<T> 
00394   CWTMatrix<T>::operator +(const CWTMatrix<T> &mat) const
00395   {
00396     // copy this and add argument
00397     return CWTMatrix( *this ) += mat;
00398   }
00399 
00400   template < class T >
00401   CWTMatrix<T> 
00402   CWTMatrix<T>::operator -(const CWTMatrix<T> &mat) const
00403   {
00404     // copy this and subtract argument
00405     return CWTMatrix( *this ) -= mat;
00406   }
00407 
00408   template < class T >
00409   CWTMatrix<T> CWTMatrix<T>::operator -() const
00410   {
00411     // NOTE: This used to work with g++ <= 3.2.
00412     // return (*this)*static_cast<const T &>(CWTZero<T>() - CWTUnity<T>());
00413 
00414     T tTmp  = CWTZero<T>();
00415     tTmp -= CWTUnity<T>();
00416     return (*this)*tTmp;
00417   }
00418 
00419   template < class T >
00420   CWTMatrix<T> CWTMatrix<T>::operator *(const T &value) const
00421   {
00422     // copy this and multiply by argument
00423     return CWTMatrix( *this ) *= value;
00424   }
00425 
00426   template < class T >
00427   CWTMatrix<T>
00428   CWTMatrix<T>::operator *(const CWTMatrix<T> &mat) const
00429   {
00430     // create result matrix
00431     CWTMatrix matResult( m_crow , mat.m_ccol );
00432     // store (*this)*mat in result matrix
00433     matResult.storeProduct( *this , mat );
00434     return matResult;
00435   }
00436 
00437   // assignment operator
00438   template < class T >
00439   CWTMatrix<T> & 
00440   CWTMatrix<T>::operator =(const CWTMatrix<T> &mat)
00441   {
00442     if (m_nMatStatus == N_NOTALLOCATED)
00443       {
00444         // if this is not allocated, we'll allocate it on the fly
00445         dimension(mat.m_crow, mat.m_ccol);
00446       }
00447 
00448     // Copy the values from mat to this, excess values in mat are
00449     // ignored. If mat has too few elements, garbage will be copied
00450     // into remaining elements of this
00451     for (unsigned irow = 0; irow < m_crow; ++irow)
00452       {
00453         for (unsigned icol = 0; icol < m_ccol; ++icol)
00454           {
00455             m_rgrow[irow][icol] = mat.m_rgrow[irow][icol];
00456           }
00457       }
00458 
00459     return *this;
00460   }
00461 
00462   template < class T >
00463   CWTMatrix<T> & 
00464   CWTMatrix<T>::operator +=(const CWTMatrix<T> &mat)
00465   {
00466     for (unsigned irow = 0; irow < m_crow; ++irow)
00467       {
00468         for (unsigned icol = 0; icol < m_ccol; ++icol)
00469           {
00470             m_rgrow[irow][icol] += mat.m_rgrow[irow][icol];
00471           }
00472       }
00473 
00474     return *this;
00475   }
00476 
00477   template < class T >
00478   CWTMatrix<T> & 
00479   CWTMatrix<T>::operator -=(const CWTMatrix<T> &mat)
00480   {
00481     for (unsigned irow = 0; irow < m_crow; ++irow)
00482       {
00483         for (unsigned icol = 0; icol < m_ccol; ++icol)
00484           {
00485             m_rgrow[irow][icol] -= mat.m_rgrow[irow][icol];
00486           }
00487       }
00488 
00489     return *this;
00490   }
00491 
00492   template < class T >
00493   CWTMatrix<T> & CWTMatrix<T>::operator *=(const T &value)
00494   {
00495     for (unsigned irow = 0; irow < m_crow; ++irow)
00496       {
00497         for (unsigned icol = 0; icol < m_ccol; ++icol)
00498           {
00499             m_rgrow[irow][icol] *= value;
00500           }
00501       }
00502 
00503     return *this;
00504   }
00505 
00506   template < class T >
00507   int CWTMatrix<T>::operator ==(const CWTMatrix<T> &mat) const
00508   {
00509     if ((m_crow == mat.m_crow) && (m_ccol == mat.m_ccol))
00510       {
00511         for (unsigned irow = 0; irow < m_crow; ++irow)
00512           {
00513             for (unsigned icol = 0; icol < m_ccol; ++icol)
00514               {
00515                 if (m_rgrow[irow][icol] != mat.m_rgrow[irow][icol])
00516                   {
00517                     return 0;
00518                   }
00519               }
00520           }
00521 
00522         return 1;
00523       }
00524     else
00525       {
00526         return 0;
00527       }
00528   }
00529 
00530   // stores mat1 + mat2 in this
00531   template < class T >
00532   void CWTMatrix<T>::storeSum(const CWTMatrix<T> &mat1,
00533                               const CWTMatrix<T> &mat2)
00534   {
00535     // NOTE: it is assumed that this has correct dimensions,
00536     // i.e. CWMatrix(mat1.m_crow, mat2.m_ccol)
00537 
00538     for (unsigned irow = 0; irow < m_crow; ++irow)
00539       {
00540         for (unsigned icol = 0; icol < m_ccol; ++icol)
00541           {
00542             m_rgrow[irow][icol] = 
00543               mat1.m_rgrow[irow][icol] + mat2.m_rgrow[irow][icol];
00544           }
00545       }
00546   }
00547 
00548   // stores mat1*mat2 in this
00549   template < class T >
00550   void CWTMatrix<T>::storeProduct(const CWTMatrix<T> &mat1,
00551                                   const CWTMatrix<T> &mat2)
00552   {
00553     // NOTE: it is assumed that this has correct dimensions,
00554     // i.e. CWMatrix(mat1.m_crow, mat2.m_ccol)
00555 
00556     for (unsigned irow = 0; irow < m_crow; ++irow)
00557       {
00558         for (unsigned icol = 0; icol < m_ccol; ++icol)
00559           {
00560             m_rgrow[irow][icol] = CWTZero<T>();
00561 
00562             for (unsigned icol2 = 0; icol2 < mat1.m_ccol; ++icol2)
00563               {
00564                 m_rgrow[irow][icol] += 
00565                   mat1.m_rgrow[irow][icol2]*mat2.m_rgrow[icol2][icol];
00566               }
00567           }
00568       }
00569   }
00570 
00571   // mat should fit in this
00572   template < class T >
00573   void CWTMatrix<T>::storeAtPosition(unsigned irowStart,
00574                                      unsigned icolStart,
00575                                      const CWTMatrix<T> &mat)
00576   {
00577     for (unsigned irow = 0; irow < mat.m_crow; ++irow)
00578       {
00579         for (unsigned icol = 0; icol < mat.m_ccol; ++icol)
00580           {
00581             m_rgrow[irow + irowStart][icol + icolStart] =
00582               mat.m_rgrow[irow][icol];
00583           }
00584       }
00585   }
00586 
00587   // stores transpose of mat in this
00588   template < class T >
00589   void CWTMatrix<T>::storeTranspose(const CWTMatrix<T> &mat)
00590   {
00591     // NOTE: it is assumed that this has correct dimensions,
00592     // i.e. CWMatrix(mat.m_ccol, mat.m_crow)
00593 
00594     for (unsigned irow = 0; irow < m_crow; ++irow)
00595       {
00596         for (unsigned icol = 0; icol < m_ccol; ++icol)
00597           {
00598             m_rgrow[irow][icol] = mat.m_rgrow[icol][irow];
00599           }
00600       }
00601   }
00602 
00603   template < class T >
00604   inline void CWTMatrix<T>::fill(const T &elemFill)
00605   {
00606     unsigned iEnd = m_crow*m_ccol;
00607 
00608     for (unsigned i = 0; i < iEnd; ++i)
00609       {
00610         (*m_rgrow)[i] = elemFill;
00611       }
00612   }
00613 
00614   template < class T >
00615   void CWTMatrix<T>::interchangeRows(unsigned irow1, unsigned irow2)
00616   {
00617     T* rowSav      = m_rgrow[irow1];
00618 
00619     // switch row pointers
00620     m_rgrow[irow1] = m_rgrow[irow2];
00621     m_rgrow[irow2] = rowSav;
00622   }
00623 
00624   template < class T >
00625   void CWTMatrix<T>::multiplyRow(unsigned irow, const T &value)
00626   {
00627     for (unsigned icol = 0; icol < m_ccol; ++icol)
00628       {
00629         m_rgrow[irow][icol] *= value;
00630       }
00631   }
00632 
00633   template < class T >
00634   void CWTMatrix<T>::addRowToRow(unsigned irowSrc,
00635                                  unsigned irowDest,
00636                                  const T &value)
00637   {
00638     for (unsigned icol = 0; icol < m_ccol; ++icol)
00639       {
00640         m_rgrow[irowDest][icol] += m_rgrow[irowSrc][icol]*value;
00641       }
00642   }
00643 
00644   //
00645   // template functions designed work with the base matrix class.
00646   //
00647 
00648   template < class T >
00649   inline CWTMatrix<T> operator *(const T &value,
00650                                  const CWTMatrix<T> &mat)
00651   {
00652     return mat*value;
00653   }
00654 
00655   template < class T >
00656   CWTMatrix<T> transpose(const CWTMatrix<T> &mat)
00657   {
00658     CWTMatrix<T> matTranspose( mat.getCols(), mat.getRows() );
00659     matTranspose.storeTranspose(mat);
00660     return matTranspose;
00661   }
00662 
00663   template < class T >
00664   ostream & operator <<(ostream &os, const CWTMatrix<T>& mtx)
00665   {
00666     os << "[" ;
00667 
00668     for (unsigned i = 0; i < mtx.getRows(); i++)
00669       {
00670         if (i > 0)
00671           {
00672             os << "; ";
00673           }
00674 
00675         os  << mtx[i][0];
00676 
00677         for (unsigned j = 1; j < mtx.getCols(); j++)
00678           {
00679             os  << ", " << mtx[i][j];
00680           }
00681       }
00682 
00683     os << "]";
00684 
00685     return os;
00686   }
00687 }
00688 
00689 #endif // IG_MATRIX_H
00690 

Generated on Sun Jul 3 12:18:14 2005 for Matrix and vector library by  doxygen 1.4.2