MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/linalg/sparse_crmatrix.h
Go to the documentation of this file.
00001 /************************************************************************
00002  * MechSys - Open Library for Mechanical Systems                        *
00003  * Copyright (C) 2005 Dorival M. Pedroso, Raul Durand                   *
00004  * Copyright (C) 2009 Sergio Galindo                                    *
00005  *                                                                      *
00006  * This program is free software: you can redistribute it and/or modify *
00007  * it under the terms of the GNU General Public License as published by *
00008  * the Free Software Foundation, either version 3 of the License, or    *
00009  * any later version.                                                   *
00010  *                                                                      *
00011  * This program is distributed in the hope that it will be useful,      *
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         *
00014  * GNU General Public License for more details.                         *
00015  *                                                                      *
00016  * You should have received a copy of the GNU General Public License    *
00017  * along with this program. If not, see <http://www.gnu.org/licenses/>  *
00018  ************************************************************************/
00019 
00020 #ifndef MECHSYS_SPARSE_CRMATRIX_H
00021 #define MECHSYS_SPARSE_CRMATRIX_H
00022 
00023 // STL
00024 #include <iostream>
00025 #include <sstream>
00026 
00027 // MechSys
00028 #include <mechsys/linalg/matvec.h>
00029 #include <mechsys/linalg/sparse_triplet.h>
00030 #include <mechsys/util/array.h>
00031 #include <mechsys/util/numstreams.h>
00032 
00033 #ifdef DO_DEBUG
00034   using std::cout;
00035   using std::endl;
00036 #endif
00037 
00038 namespace Sparse
00039 {
00040 
00064 template<typename Value_T, typename Index_T>
00065 class CRMatrix
00066 {
00067 public:
00069      CRMatrix();
00070 
00072     ~CRMatrix();
00073 
00077     CRMatrix(Triplet<Value_T,Index_T> const & T);
00078 
00079     // Methods
00080     void    Set  (Triplet<Value_T,Index_T> const & T);                                                                         
00081     void    Set  (Index_T nRows, Index_T nCols, Index_T nZ, String const & strAy, String const & strAj, String const & strAq); 
00082     Index_T Rows () const { return _nrows; } 
00083     Index_T Cols () const { return _ncols; } 
00084     Index_T nZ   () const { return _nz;    } 
00085 
00086     // Access methods
00087     Value_T         Ay       (Index_T iNz ) const; 
00088     Index_T         Aj       (Index_T iNz ) const; 
00089     Index_T         Aq       (Index_T iRow) const; 
00090     Value_T       * GetAyPtr ();                   
00091     Index_T       * GetAjPtr ();                   
00092     Index_T       * GetAqPtr ();                   
00093     Value_T const * GetAyPtr () const;             
00094     Index_T const * GetAjPtr () const;             
00095     Index_T const * GetAqPtr () const;             
00096 
00097     // Auxiliar methods
00098     void                    GetDense (Mat_t & D) const;                    
00099     void                    SetNS    (Util::NumStream & NS) { _ns = &NS; } 
00100     Util::NumStream const & NS       () const           { return (*_ns); } 
00101 
00102 private:
00103     // Data
00104     Index_T           _nrows; 
00105     Index_T           _ncols; 
00106     Index_T           _nz;    
00107     Value_T         * _Ay;    
00108     Index_T         * _Aj;    
00109     Index_T         * _Aq;    
00110     Util::NumStream * _ns;    
00111 
00112 }; // class CRMatrix
00113 
00114 
00116 
00117 
00118 // Constructor & Destructor
00119 
00120 template<typename Value_T, typename Index_T>
00121 inline CRMatrix<Value_T,Index_T>::CRMatrix()
00122     : _nrows (0),
00123       _ncols (0),
00124       _nz    (0),
00125       _Ay    (NULL),
00126       _Aj    (NULL),
00127       _Aq    (NULL),
00128       _ns    (&Util::_8s)
00129 {}
00130 
00131 template<typename Value_T, typename Index_T>
00132 inline CRMatrix<Value_T,Index_T>::~CRMatrix()
00133 {
00134     if (_Ay!=NULL) delete [] _Ay;
00135     if (_Aj!=NULL) delete [] _Aj;
00136     if (_Aq!=NULL) delete [] _Aq;
00137 }
00138 
00139 // Alternative constructor
00140 
00141 template<typename Value_T, typename Index_T>
00142 inline CRMatrix<Value_T,Index_T>::CRMatrix(Triplet<Value_T,Index_T> const & T)
00143     : _Ay (NULL),
00144       _Aj (NULL),
00145       _Aq (NULL),
00146       _ns (&Util::_8s)
00147 {
00148     Set(T);
00149 }
00150 
00151 // Methods
00152 
00153 template<typename Value_T, typename Index_T>
00154 inline void CRMatrix<Value_T,Index_T>::Set(Triplet<Value_T,Index_T> const & T)
00155 {
00156     // Clean
00157     if (_Ay!=NULL) delete [] _Ay;
00158     if (_Aj!=NULL) delete [] _Aj;
00159     if (_Aq!=NULL) delete [] _Aq;
00160 
00161     // Allocate this matrix (With room for the duplicates. This space will be unused by the resulting CRMatrix)
00162     _nrows = T.Rows();
00163     _ncols = T.Cols();
00164     _nz    = T.Top();
00165     _Ay    = new Value_T [_nz];
00166     _Aj    = new Index_T [_nz];
00167     _Aq    = new Index_T [_nrows+1];
00168 
00169     // Temporary variables
00170     Index_T p, p1, p2, pdest; // pointers (indexes)
00171     Index_T nn = _nrows;  if (_ncols>nn) nn = _ncols;
00172 
00173     // Allocate workspaces
00174     Index_T * rq = new Index_T [_nrows+1]; // temporary row format
00175     Index_T * rj = new Index_T [_nz];      // temporary row format
00176     Value_T * ry = new Value_T [_nz];      // temporary row format
00177     Index_T * rc = new Index_T [_nrows];   // row count
00178     Index_T * w  = new Index_T [nn];       // workspace
00179     if (!rq || !rj || !ry || !w) throw new Fatal(_("Sparse::CRMatrix::CRMatrix(nRows,nCols,T): Out of memory."));
00180 
00181     // Count the entries in each row (also counting duplicates)
00182     for (Index_T i=0; i<_nrows; i++) w[i]=0; // use w as workspace for row counts (including duplicates)
00183     for (Index_T k=0; k<_nz; k++)
00184     {
00185         Index_T i = T.Ai(k);
00186         Index_T j = T.Aj(k);
00187         if (i<0 || i>=_nrows || j<0 || j>=_ncols) throw new Fatal(_("Sparse::CRMatrix::CRMatrix(nRows,nCols,T): (i<0 || i>=nRows || j<0 || j>=nCols) failed => triplet corresponds to an invalid matrix."));
00188         w[i]++;
00189     }
00190 
00191     // Compute the row pointers (with duplicates)
00192     rq[0] = 0;
00193     for (Index_T i=0; i<_nrows; i++)
00194     {
00195         rq[i+1] = rq[i] + w[i];
00196         w [i]   = rq[i];       // w is now equal to the row pointers
00197     }
00198 
00199     // Construct the row form (with duplicates)
00200     for (Index_T k=0 ; k<_nz; k++)
00201     {
00202         p     = w[T.Ai(k)]++; // rq stays the same, but w[i] is advanced to the start of row i+1
00203         rj[p] = T.Aj(k);
00204         ry[p] = T.Ax(k);
00205     }
00206 
00207     // Sum up duplicates (but do not change the size)
00208     for (Index_T j=0; j<_ncols; j++) w[j]=-1; // use w[j] to hold position in Aj and Ay of a_ij, for row i [
00209     for (Index_T i=0; i<_nrows; i++)
00210     {
00211         p1    = rq[i];
00212         p2    = rq[i+1];
00213         pdest = p1;
00214         for (p=p1; p<p2; p++) // At this point, w[j]<p1 holds true for all columns j, because Aj and Ay are stored in row oriented order
00215         {
00216             Index_T j  = rj[p];
00217             Index_T pj = w[j];
00218             if (pj>=p1) // this column index, j, is already in row i, at position pj
00219                 ry[pj] += ry[p]; // sum the entry
00220             else // keep the entry
00221             {
00222                 w[j] = pdest; // also keep track in w[j] of position of a_ij for case above
00223                 if (pdest!=p) // no need to move the entry if pdest is equal to p
00224                 {
00225                     rj[pdest] = j;
00226                     ry[pdest] = ry[p];
00227                 }
00228                 pdest++;
00229             }
00230         }
00231         rc[i] = pdest - p1; // will have the number of elemens without duplicates in each row (row count)
00232     } // done using w for position of a_ij ]
00233 
00234     // Construct the row form (without duplicates)
00235     _nz    = 0;
00236     _Aq[0] = 0;
00237     for (Index_T i=0; i<_nrows; i++)
00238     {
00239         _Aq[i+1] = _Aq[i] + rc[i];
00240         for (p=rq[i]; p<rq[i]+rc[i]; p++)
00241         {
00242             _Aj[_nz] = rj[p];
00243             _Ay[_nz] = ry[p];
00244             _nz++;
00245         }
00246     }
00247 
00248     // Cleanup
00249     delete [] rq;
00250     delete [] rj;
00251     delete [] ry;
00252     delete [] rc;
00253     delete [] w;
00254 
00255 }
00256 
00257 template<typename Value_T, typename Index_T>
00258 inline void CRMatrix<Value_T,Index_T>::Set(Index_T nRows, Index_T nCols, Index_T nZ, String const & strAy, String const & strAj, String const & strAq)
00259 {
00260     Array<Value_T> ay;
00261     Array<Index_T> aj;
00262     Array<Index_T> aq;
00263 
00264     // Values => ay
00265     std::istringstream iss_y(strAy);
00266     Value_T value;
00267     while (iss_y>>value) { ay.Push(value); }
00268 
00269     // Column indexes => aj
00270     std::istringstream iss_j(strAj);
00271     Index_T index;
00272     while (iss_j>>index) { aj.Push(index); }
00273 
00274     // Pointers to column indexes => aq
00275     std::istringstream iss_q(strAq);
00276     Index_T pointer;
00277     while (iss_q>>pointer) { aq.Push(pointer); }
00278 
00279 #ifdef DO_DEBUG
00280     cout << "ay = " << strAy << " = "; for (size_t i=0; i<ay.Size(); i++) { cout << ay[i] << " "; } cout<<endl;
00281     cout << "aj = " << strAj << " = "; for (size_t i=0; i<aj.Size(); i++) { cout << aj[i] << " "; } cout<<endl;
00282     cout << "aq = " << strAq << " = "; for (size_t i=0; i<aq.Size(); i++) { cout << aq[i] << " "; } cout<<endl;
00283 #endif
00284 
00285     if (static_cast<Index_T>(ay.Size())      !=nZ     ) throw new Fatal(_("Sparse::CRMatrix::Set: The size (%d) of strAy (values) must be equal to nz(=%d), where nz is the number of non-zero values."),ay.Size(),nZ);
00286     if (static_cast<Index_T>(aj.Size())      !=nZ     ) throw new Fatal(_("Sparse::CRMatrix::Set: The size (%d) of strAj (column indexes) must be equal to nz(=%d), where nz is the number of non-zero values."),aj.Size(),nZ);
00287     if (static_cast<Index_T>(aq.Size())      !=nRows+1) throw new Fatal(_("Sparse::CRMatrix::Set: The size (%d) of strAq (pointers to the column indexes) must be equal to nrows+1(=%d), where nrows is the number of rows."),aq.Size(),nRows+1);
00288     if (static_cast<Index_T>(aq[aq.Size()-1])!=nZ     ) throw new Fatal(_("Sparse::CRMatrix::Set: The last value of Aq(=%d) in strAq (pointers to the row indexes) must be equal to nz(=%d), where nz is the number of non-zero values."),aq[aq.Size()-1],nZ);
00289 
00290     _nrows = nRows;
00291     _ncols = nCols;
00292     _nz    = nZ;
00293 
00294     _Ay = new Value_T [nZ];
00295     _Aj = new Index_T [nZ];
00296     _Aq = new Index_T [nRows+1];
00297 
00298     for (Index_T k=0; k<nZ;      ++k) _Ay[k] = ay[k];
00299     for (Index_T k=0; k<nZ;      ++k) _Aj[k] = aj[k];
00300     for (Index_T k=0; k<nRows+1; ++k) _Aq[k] = aq[k];
00301     
00302 }
00303 
00304 // Access methods
00305 
00306 template<typename Value_T, typename Index_T>
00307 inline Value_T CRMatrix<Value_T,Index_T>::Ay(Index_T iNz) const
00308 {
00309 #ifndef DNDEBUG
00310     if ((iNz<0) || (iNz>=_nz)) throw new Fatal(_("Sparse::CRMatrix::Ay: Index for a non-zero value, iNz(=%d), must be greater than/or equal to zero and smaller than nz(=%d)"),iNz,_nz);
00311 #endif
00312     return _Ay[iNz];
00313 }
00314 
00315 template<typename Value_T, typename Index_T>
00316 inline Index_T CRMatrix<Value_T,Index_T>::Aj(Index_T iNz) const
00317 {
00318 #ifndef DNDEBUG
00319     if ((iNz<0) || (iNz>=_nz)) throw new Fatal(_("Sparse::CRMatrix::Aj: Index for an index to a non-zero value, iNz(=%d), must be greater than/or equal to zero and smaller than nz(=%d)"),iNz,_nz);
00320 #endif
00321     return _Aj[iNz];
00322 }
00323 
00324 template<typename Value_T, typename Index_T>
00325 inline Index_T CRMatrix<Value_T,Index_T>::Aq(Index_T iRow) const
00326 {
00327 #ifndef DNDEBUG
00328     if ((iRow<0) || (iRow>_nrows)) throw new Fatal(_("Sparse::CRMatrix::Aq: Index for a row, iRow(=%d), must be greater than/or equal to zero and smaller than nRows+1(=%d)"),iRow,_nrows+1);
00329 #endif
00330     return _Aq[iRow];
00331 }
00332 
00333 template<typename Value_T, typename Index_T>
00334 inline Value_T * CRMatrix<Value_T,Index_T>::GetAyPtr() 
00335 {
00336 #ifndef DNDEBUG
00337     if (_Ay==NULL) throw new Fatal(_("Sparse::CRMatrix::GetAyPtr: The matrix must be set prior to get the pointer to Ay (non-zero values)."));
00338 #endif
00339     return _Ay;
00340 }
00341 
00342 template<typename Value_T, typename Index_T>
00343 inline Index_T * CRMatrix<Value_T,Index_T>::GetAjPtr()
00344 {
00345 #ifndef DNDEBUG
00346     if (_Aj==NULL) throw new Fatal(_("Sparse::CRMatrix::GetAjPtr: The matrix must be set prior to get the pointer to Aj (column indexes of non-zero values)."));
00347 #endif
00348     return _Aj;
00349 }
00350 
00351 template<typename Value_T, typename Index_T>
00352 inline Index_T * CRMatrix<Value_T,Index_T>::GetAqPtr()
00353 {
00354 #ifndef DNDEBUG
00355     if (_Aq==NULL) throw new Fatal(_("Sparse::CRMatrix::GetAqPtr: The matrix must be set prior to get the pointer to Aq (pointers to the column indexes of non-zero values)."));
00356 #endif
00357     return _Aq;
00358 }
00359 
00360 template<typename Value_T, typename Index_T>
00361 inline Value_T const * CRMatrix<Value_T,Index_T>::GetAyPtr() const
00362 {
00363 #ifndef DNDEBUG
00364     if (_Ay==NULL) throw new Fatal(_("Sparse::CRMatrix::GetAyPtr: The matrix must be set prior to get the pointer to Ay (non-zero values)."));
00365 #endif
00366     return _Ay;
00367 }
00368 
00369 template<typename Value_T, typename Index_T>
00370 inline Index_T const * CRMatrix<Value_T,Index_T>::GetAjPtr() const
00371 {
00372 #ifndef DNDEBUG
00373     if (_Aj==NULL) throw new Fatal(_("Sparse::CRMatrix::GetAjPtr: The matrix must be set prior to get the pointer to Aj (column indexes of non-zero values)."));
00374 #endif
00375     return _Aj;
00376 }
00377 
00378 template<typename Value_T, typename Index_T>
00379 inline Index_T const * CRMatrix<Value_T,Index_T>::GetAqPtr() const
00380 {
00381 #ifndef DNDEBUG
00382     if (_Aq==NULL) throw new Fatal(_("Sparse::CRMatrix::GetAqPtr: The matrix must be set prior to get the pointer to Aq (pointers to the column indexes of non-zero values)."));
00383 #endif
00384     return _Aq;
00385 }
00386 
00387 // Auxiliar methods
00388 
00389 template<typename Value_T, typename Index_T>
00390 inline void CRMatrix<Value_T,Index_T>::GetDense(Mat_t & D) const
00391 {
00392     D.Resize(_nrows,_ncols);
00393     for (Index_T i=0; i<_nrows; ++i)
00394     {
00395         Index_T start = _Aq[i];
00396         Index_T endpo = _Aq[i+1]; // == end+1 (po: plus one)
00397         for (Index_T q=start; q<endpo; ++q)
00398             D(i,_Aj[q]) = _Ay[q];
00399     }
00400 }
00401 
00402 
00404 template<typename Value_T, typename Index_T>
00405 std::ostream & operator<< (std::ostream & os, const Sparse::CRMatrix<Value_T,Index_T> & M)
00406 {
00407     os << "Ay =\n"; for (Index_T k=0; k<M.nZ();     ++k) os << M.NS()  <<M.Ay(k) << " "; os<<std::endl;
00408     os << "Aj =\n"; for (Index_T k=0; k<M.nZ();     ++k) os << Util::_3<<M.Aj(k) << " "; os<<std::endl;
00409     os << "Aq =\n"; for (Index_T i=0; i<M.Rows()+1; ++i) os << Util::_3<<M.Aq(i) << " "; os<<std::endl;
00410     os << std::endl;
00411 #ifdef DO_DEBUG
00412     /*
00413     os << "Rows=" << M.Rows() << ", Cols=" << M.Cols() << ", nZ=" << M.nZ() << std::endl;
00414     for (Index_T i=0; i<M.Rows(); ++i)
00415     {
00416         os << "Row # " << i << std::endl;
00417         Index_T start = M.Aq(i);
00418         Index_T endpo = M.Aq(i+1); // end+1 (po: plus one)
00419         for (Index_T q=start; q<endpo; ++q)
00420         {
00421             Index_T j = M.Aj(q);
00422             os << "j=" << j << ", value=" << M.Ay(q) << std::endl;
00423         }
00424         os << std::endl;
00425     }
00426     */
00427 #endif
00428     return os;
00429 }
00430 
00431 
00432 }; // namespace Sparse
00433 
00434 #endif // MECHSYS_SPARSE_CRMATRIX_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines