![]() |
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_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