![]() |
MechSys
1.0
Computing library for simulations in continuum and discrete mechanics
|
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