MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/linalg/sparse_matrix.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_MATRIX_H
00021 #define MECHSYS_SPARSE_MATRIX_H
00022 
00023 // STL
00024 #include <iostream>
00025 #include <sstream>  // for istringstream, ostringstream
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 
00040 namespace Sparse
00041 {
00042 
00083 template<typename Value_T, typename Index_T>
00084 class Matrix
00085 {
00086 public:
00088      Matrix();
00089 
00091     ~Matrix();
00092 
00096     Matrix(Triplet<Value_T,Index_T> const & T);
00097 
00098     // Methods
00099     void    Set  (Triplet<Value_T,Index_T> const & T);                                                                         
00100     void    Set  (Index_T nRows, Index_T nCols, Index_T nZ, String const & strAx, String const & strAi, String const & strAp); 
00101     Index_T Rows () const { return _nrows; } 
00102     Index_T Cols () const { return _ncols; } 
00103     Index_T nZ   () const { return _nz;    } 
00104 
00105     // Access methods
00106     Value_T         Ax       (Index_T iNz ) const; 
00107     Index_T         Ai       (Index_T iNz ) const; 
00108     Index_T         Ap       (Index_T iCol) const; 
00109     Value_T       * GetAxPtr ();                   
00110     Index_T       * GetAiPtr ();                   
00111     Index_T       * GetApPtr ();                   
00112     Value_T const * GetAxPtr () const;             
00113     Index_T const * GetAiPtr () const;             
00114     Index_T const * GetApPtr () const;             
00115 
00116     // Auxiliar methods
00117     void                    GetDense  (Mat_t & D) const;                                
00118     void                    SetNS     (Util::NumStream & NS) { _ns = &NS; }             
00119     Util::NumStream const & NS        () const           { return (*_ns); }             
00120     void                    WriteSMAT (char const * FileKey, double Tol=1.0e-14) const; 
00121 
00122 private:
00123     // Data
00124     Index_T           _nrows; 
00125     Index_T           _ncols; 
00126     Index_T           _nz;    
00127     Value_T         * _Ax;    
00128     Index_T         * _Ai;    
00129     Index_T         * _Ap;    
00130     Util::NumStream * _ns;    
00131 
00132 }; // class Matrix
00133 
00134 
00136 
00137 
00138 // Constructor & Destructor
00139 
00140 template<typename Value_T, typename Index_T>
00141 inline Matrix<Value_T,Index_T>::Matrix()
00142     : _nrows (0),
00143       _ncols (0),
00144       _nz    (0),
00145       _Ax    (NULL),
00146       _Ai    (NULL),
00147       _Ap    (NULL),
00148       _ns    (&Util::_8s)
00149 {}
00150 
00151 template<typename Value_T, typename Index_T>
00152 inline Matrix<Value_T,Index_T>::~Matrix()
00153 {
00154     if (_Ax!=NULL) delete [] _Ax;
00155     if (_Ai!=NULL) delete [] _Ai;
00156     if (_Ap!=NULL) delete [] _Ap;
00157 }
00158 
00159 // Alternative constructor
00160 
00161 template<typename Value_T, typename Index_T>
00162 inline Matrix<Value_T,Index_T>::Matrix(Triplet<Value_T,Index_T> const & T)
00163     : _Ax (NULL),
00164       _Ai (NULL),
00165       _Ap (NULL),
00166       _ns (&Util::_8s)
00167 {
00168     Set(T);
00169 }
00170 
00171 // Methods
00172 
00173 template<typename Value_T, typename Index_T>
00174 inline void Matrix<Value_T,Index_T>::Set(Triplet<Value_T,Index_T> const & T)
00175 {
00176     /* Based on Prof. Tim Davis' UMFPACK::UMF_triplet_map_x  inside umf_triplet.c */
00177 
00178     // Clean
00179     if (_Ax!=NULL) delete [] _Ax;
00180     if (_Ai!=NULL) delete [] _Ai;
00181     if (_Ap!=NULL) delete [] _Ap;
00182 
00183     // Allocate this matrix (with duplicates)
00184     _nrows = T.Rows();
00185     _ncols = T.Cols();
00186     _nz    = T.Top();
00187     _Ax    = new Value_T [_nz];
00188     _Ai    = new Index_T [_nz];
00189     _Ap    = new Index_T [_ncols+1];
00190 
00191     // Temporary variables
00192     Index_T p, p1, p2, pdest, cp; // pointers (indexes)
00193     Index_T nn = _nrows;  if (_ncols>nn) nn = _ncols;
00194 
00195     // Allocate workspaces
00196     Index_T * rp = new Index_T [_nrows+1];  // temporary row form
00197     Index_T * rj = new Index_T [_nz];       // temporary row form
00198     Value_T * rx = new Value_T [_nz];       // temporary row form
00199     Index_T * rc = new Index_T [_nrows];    // row count
00200     Index_T * w  = new Index_T [nn];        // workspace
00201     if (!rp || !rj || !rx || !rc || !w) throw new Fatal("Sparse::Matrix::Matrix(n,T): Out of memory.");
00202 
00203     // Count the entries in each row (also counting duplicates)
00204     for (Index_T i=0; i<_nrows; i++) w[i]=0; // use w as workspace for row counts (including duplicates)
00205     for (Index_T k=0; k<_nz; k++)
00206     {
00207         Index_T i = T.Ai(k);
00208         Index_T j = T.Aj(k);
00209         if (i<0 || i>=_nrows || j<0 || j>=_ncols) throw new Fatal("Sparse::Matrix::Matrix(n,T): (i<0 || i>=nRows || j<0 || j>=nCols) failed => triplet corresponds to an invalid matrix.");
00210         w[i]++;
00211     }
00212 
00213     // Compute the row pointers
00214     rp[0] = 0;
00215     for (Index_T i=0; i<_nrows; i++)
00216     {
00217         rp[i+1] = rp[i] + w[i];
00218         w [i]   = rp[i];       // w is now equal to the row pointers
00219     }
00220 
00221     // Construct the row form
00222     for (Index_T k=0 ; k<_nz; k++)
00223     {
00224         p     = w[T.Ai(k)]++; // rp stays the same, but w[i] is advanced to the start of row i+1
00225         rj[p] = T.Aj(k);
00226         rx[p] = T.Ax(k);
00227     }
00228 
00229     // Sum up duplicates
00230     for (Index_T j=0; j<_ncols; j++) w[j]=-1; // use w[j] to hold position in rj and rx of a_ij, for row i [
00231     for (Index_T i=0; i<_nrows; i++)
00232     {
00233         p1    = rp[i];
00234         p2    = rp[i+1];
00235         pdest = p1;
00236         for (p=p1; p<p2; p++) // At this point, w[j]<p1 holds true for all columns j, because rj and rx are stored in row oriented order
00237         {
00238             Index_T j  = rj[p];
00239             Index_T pj = w [j];
00240             if (pj>=p1) // this column index, j, is already in row i, at position pj
00241                 rx[pj] += rx[p]; // sum the entry
00242             else // keep the entry
00243             {
00244                 w[j] = pdest; // also keep track in w[j] of position of a_ij for case above
00245                 if (pdest!=p) // no need to move the entry if pdest is equal to p
00246                 {
00247                     rj[pdest] = j;
00248                     rx[pdest] = rx[p];
00249                 }
00250                 pdest++;
00251             }
00252         }
00253         rc[i] = pdest - p1 ;
00254     } // done using W for position of a_ij ]
00255 
00256     // Count the entries in each column
00257     for (Index_T j=0; j<_ncols; j++) w[j]=0; // [ use W as work space for column counts of A
00258     for (Index_T i=0; i<_nrows; i++)
00259         for (p=rp[i]; p<rp[i]+rc[i]; p++)
00260             w[rj[p]]++;
00261 
00262     // Create the column pointers
00263     _Ap[0] = 0;
00264     for (Index_T j=0; j<_ncols; j++) _Ap[j+1] = _Ap[j] + w[j]; // done using W as workspace for column counts of A ]
00265     for (Index_T j=0; j<_ncols; j++)   w[j]   = _Ap[j];
00266 
00267     // Construct the column form
00268     _nz = 0;
00269     for (Index_T i=0; i<_nrows; i++)
00270     {
00271         for (p=rp[i]; p<rp[i] + rc[i]; p++)
00272         {
00273             cp      = w[rj[p]]++;
00274             _Ai[cp] = i;
00275             _Ax[cp] = rx[p];
00276             _nz++;
00277         }
00278     }
00279 
00280     // Cleanup
00281     delete [] rp;
00282     delete [] rj;
00283     delete [] rx;
00284     delete [] rc;
00285     delete [] w;
00286 
00287 }
00288 
00289 template<typename Value_T, typename Index_T>
00290 inline void Matrix<Value_T,Index_T>::Set(Index_T nRows, Index_T nCols, Index_T nZ, String const & strAx, String const & strAi, String const & strAp)
00291 {
00292     Array<Value_T> ax;
00293     Array<Index_T> ai;
00294     Array<Index_T> ap;
00295 
00296     // Values => ax
00297     std::istringstream iss_x(strAx);
00298     Value_T value;
00299     while (iss_x>>value) { ax.Push(value); }
00300 
00301     // Row indexes => ai
00302     std::istringstream iss_i(strAi);
00303     Index_T index;
00304     while (iss_i>>index) { ai.Push(index); }
00305 
00306     // Pointers to row indexes => ap
00307     std::istringstream iss_p(strAp);
00308     Index_T pointer;
00309     while (iss_p>>pointer) { ap.Push(pointer); }
00310 
00311 #ifdef DO_DEBUG
00312     cout << "ax = " << strAx << " = "; for (size_t i=0; i<ax.Size(); i++) { cout << ax[i] << " "; } cout<<endl;
00313     cout << "ai = " << strAi << " = "; for (size_t i=0; i<ai.Size(); i++) { cout << ai[i] << " "; } cout<<endl;
00314     cout << "ap = " << strAp << " = "; for (size_t i=0; i<ap.Size(); i++) { cout << ap[i] << " "; } cout<<endl;
00315 #endif
00316 
00317     if (static_cast<Index_T>(ax.Size())      !=nZ     ) throw new Fatal("Sparse::Matrix::Set: The size (%d) of strAx (values) must be equal to nz(=%d), where nz is the number of non-zero values.",ax.Size(),nZ);
00318     if (static_cast<Index_T>(ai.Size())      !=nZ     ) throw new Fatal("Sparse::Matrix::Set: The size (%d) of strAi (row indexes) must be equal to nz(=%d), where nz is the number of non-zero values.",ai.Size(),nZ);
00319     if (static_cast<Index_T>(ap.Size())      !=nCols+1) throw new Fatal("Sparse::Matrix::Set: The size (%d) of strAp (pointers to the row indexes) must be equal to ncols+1(=%d), where ncols is the number of columns.",ap.Size(),nCols+1);
00320     if (static_cast<Index_T>(ap[ap.Size()-1])!=nZ     ) throw new Fatal("Sparse::Matrix::Set: The last value of Ap(=%d) in strAp (pointers to the row indexes) must be equal to nz(=%d), where nz is the number of non-zero values.",ap[ap.Size()-1],nZ);
00321 
00322     _nrows = nRows;
00323     _ncols = nCols;
00324     _nz    = nZ;
00325 
00326     _Ax = new Value_T [nZ];
00327     _Ai = new Index_T [nZ];
00328     _Ap = new Index_T [nCols+1];
00329 
00330     for (Index_T k=0; k<nZ;      ++k) _Ax[k] = ax[k];
00331     for (Index_T k=0; k<nZ;      ++k) _Ai[k] = ai[k];
00332     for (Index_T k=0; k<nCols+1; ++k) _Ap[k] = ap[k];
00333     
00334 }
00335 
00336 // Access methods
00337 
00338 template<typename Value_T, typename Index_T>
00339 inline Value_T Matrix<Value_T,Index_T>::Ax(Index_T iNz) const
00340 {
00341 #ifndef DNDEBUG
00342     if ((iNz<0) || (iNz>=_nz)) throw new Fatal("Sparse::Matrix::Ax: Index for a non-zero value, iNz(=%d), must be greater than/or equal to zero and smaller than nz(=%d)",iNz,_nz);
00343 #endif
00344     return _Ax[iNz];
00345 }
00346 
00347 template<typename Value_T, typename Index_T>
00348 inline Index_T Matrix<Value_T,Index_T>::Ai(Index_T iNz) const
00349 {
00350 #ifndef DNDEBUG
00351     if ((iNz<0) || (iNz>=_nz)) throw new Fatal("Sparse::Matrix::Ai: Index for a row index to a non-zero value, iNz(=%d), must be greater than/or equal to zero and smaller than nz(=%d)",iNz,_nz);
00352 #endif
00353     return _Ai[iNz];
00354 }
00355 
00356 template<typename Value_T, typename Index_T>
00357 inline Index_T Matrix<Value_T,Index_T>::Ap(Index_T iCol) const
00358 {
00359 #ifndef DNDEBUG
00360     if ((iCol<0) || (iCol>_ncols)) throw new Fatal("Sparse::Matrix::Ap: Index for a column, iCol(=%d), must be greater than/or equal to zero and smaller than nCols+1(=%d)",iCol,_ncols+1);
00361 #endif
00362     return _Ap[iCol];
00363 }
00364 
00365 template<typename Value_T, typename Index_T>
00366 inline Value_T * Matrix<Value_T,Index_T>::GetAxPtr() 
00367 {
00368 #ifndef DNDEBUG
00369     if (_Ax==NULL) throw new Fatal("Sparse::Matrix::GetAxPtr: The matrix must be set prior to get the pointer to Ax (non-zero values).");
00370 #endif
00371     return _Ax;
00372 }
00373 
00374 template<typename Value_T, typename Index_T>
00375 inline Index_T * Matrix<Value_T,Index_T>::GetAiPtr()
00376 {
00377 #ifndef DNDEBUG
00378     if (_Ai==NULL) throw new Fatal("Sparse::Matrix::GetAiPtr: The matrix must be set prior to get the pointer to Ai (row indexes of non-zero values).");
00379 #endif
00380     return _Ai;
00381 }
00382 
00383 template<typename Value_T, typename Index_T>
00384 inline Index_T * Matrix<Value_T,Index_T>::GetApPtr()
00385 {
00386 #ifndef DNDEBUG
00387     if (_Ap==NULL) throw new Fatal("Sparse::Matrix::GetApPtr: The matrix must be set prior to get the pointer to Ap (pointers to the row indexes of non-zero values).");
00388 #endif
00389     return _Ap;
00390 }
00391 
00392 template<typename Value_T, typename Index_T>
00393 inline Value_T const * Matrix<Value_T,Index_T>::GetAxPtr() const
00394 {
00395 #ifndef DNDEBUG
00396     if (_Ax==NULL) throw new Fatal("Sparse::Matrix::GetAxPtr: The matrix must be set prior to get the pointer to Ax (non-zero values).");
00397 #endif
00398     return _Ax;
00399 }
00400 
00401 template<typename Value_T, typename Index_T>
00402 inline Index_T const * Matrix<Value_T,Index_T>::GetAiPtr() const
00403 {
00404 #ifndef DNDEBUG
00405     if (_Ai==NULL) throw new Fatal("Sparse::Matrix::GetAiPtr: The matrix must be set prior to get the pointer to Ai (row indexes of non-zero values).");
00406 #endif
00407     return _Ai;
00408 }
00409 
00410 template<typename Value_T, typename Index_T>
00411 inline Index_T const * Matrix<Value_T,Index_T>::GetApPtr() const
00412 {
00413 #ifndef DNDEBUG
00414     if (_Ap==NULL) throw new Fatal("Sparse::Matrix::GetApPtr: The matrix must be set prior to get the pointer to Ap (pointers to the row indexes of non-zero values).");
00415 #endif
00416     return _Ap;
00417 }
00418 
00419 // Auxiliar methods
00420 
00421 template<typename Value_T, typename Index_T>
00422 inline void Matrix<Value_T,Index_T>::GetDense(Mat_t & D) const
00423 {
00424     D.change_dim(_nrows,_ncols);
00425     set_to_zero(D);
00426     for (Index_T j=0; j<_ncols; ++j)
00427     {
00428         Index_T start = _Ap[j];
00429         Index_T endpo = _Ap[j+1]; // == end+1
00430         for (Index_T p=start; p<endpo; ++p)
00431             D(_Ai[p],j) = _Ax[p];
00432     }
00433 }
00434 
00435 template<typename Value_T, typename Index_T>
00436 inline void Matrix<Value_T,Index_T>::WriteSMAT (char const * FileKey, double Tol) const
00437 {
00438     // find the number of really non-zero values
00439     size_t nz = 0;
00440     for (Index_T j=0; j<_ncols; ++j)
00441     {
00442         Index_T start = _Ap[j];
00443         Index_T endpo = _Ap[j+1]; // == end+1
00444         for (Index_T p=start; p<endpo; ++p)
00445             if (fabs(_Ax[p])>Tol) nz++;
00446     }
00447 
00448     // output
00449     std::ostringstream oss;
00450     char buf[256];
00451     sprintf(buf, "%d  %d  %zd\n", _nrows, _ncols, nz);
00452     oss << buf;
00453     for (Index_T j=0; j<_ncols; ++j)
00454     {
00455         Index_T start = _Ap[j];
00456         Index_T endpo = _Ap[j+1]; // == end+1
00457         for (Index_T p=start; p<endpo; ++p)
00458         {
00459             if (fabs(_Ax[p])>Tol)
00460             {
00461                 sprintf(buf, "  %d  %d  %g\n", _Ai[p], j, _Ax[p]);
00462             }
00463         }
00464     }
00465 
00466     // write to file
00467     String fn(FileKey);  fn.append(".smat");
00468     std::ofstream of(fn.CStr(), std::ios::out);
00469     of << oss.str();
00470     of.close();
00471 }
00472 
00474 template<typename Value_T, typename Index_T>
00475 std::ostream & operator<< (std::ostream & os, const Sparse::Matrix<Value_T,Index_T> & M)
00476 {
00477     os << "Ax =\n"; for (Index_T k=0; k<M.nZ();     ++k) os << M.NS()  <<M.Ax(k) << " "; os<<std::endl;
00478     os << "Ai =\n"; for (Index_T k=0; k<M.nZ();     ++k) os << Util::_3<<M.Ai(k) << " "; os<<std::endl;
00479     os << "Ap =\n"; for (Index_T j=0; j<M.Cols()+1; ++j) os << Util::_3<<M.Ap(j) << " "; os<<std::endl;
00480     os << std::endl;
00481 #ifdef DO_DEBUG
00482     /*
00483     os << "Rows=" << M.Rows() << ", Cols=" << M.Cols() << ", nZ=" << M.nZ() << std::endl;
00484     for (Index_T j=0; j<M.Cols(); ++j)
00485     {
00486         os << "Column # " << j << std::endl;
00487         Index_T start = M.Ap(j);
00488         Index_T endpo = M.Ap(j+1); // end+1
00489         for (Index_T p=start; p<endpo; ++p)
00490         {
00491             Index_T i = M.Ai(p);
00492             os << "i=" << i << ", value=" << M.Ax(p) << std::endl;
00493         }
00494         os << std::endl;
00495     }
00496     */
00497 #endif
00498     return os;
00499 }
00500 
00501 
00502 }; // namespace Sparse
00503 
00504 #endif // MECHSYS_SPARSE_MATRIX_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines