SparseMatrix.h

00001 /*  _________________________________________________________________________
00002  *
00003  *  UTILIB: A utility library for developing portable C++ codes.
00004  *  Copyright (c) 2001, Sandia National Laboratories.
00005  *  This software is distributed under the GNU Lesser General Public License.
00006  *  For more information, see the README file in the top UTILIB directory.
00007  *  _________________________________________________________________________
00008  */
00009 
00010 //
00011 // SparseMatrix.h
00012 //
00039 #ifndef __SparseMatrix_h
00040 #define __SparseMatrix_h
00041 
00042 //--- INCLUDES ---//
00043 
00044 #include "_math.h"
00045 #include "BitArray.h"
00046 #include "CharString.h"
00047 #include "DoubleVector.h"
00048 #include "IntVector.h"
00049 #include "Ereal.h"
00050  
00051 //--- CONSTANTS ---//
00052 
00053 //--- TYPES ---//
00054 
00055 template <class T>
00056 class UTILIB_API CMSparseMatrix; // Forward decl
00057 
00058 template <class T>
00059 class UTILIB_API RMSparseMatrix; // Forward decl
00060 
00061 //
00062 // Note:  is this numerically stable?
00063 //
00064 template <class T>
00065 inline void product(NumArray<T>& res, const RMSparseMatrix<T>& mat, 
00066                                                 const NumArray<T>& vec)
00067 {
00068 res.resize(mat.get_nrows());
00069 
00070 int nrows=mat.get_nrows();
00071 for (int i=0; i<nrows; i++) {
00072   res[i] = 0.0;
00073   const T* val = &(mat.matval[mat.matbeg[i]]);
00074   const int*    col = &(mat.matind[mat.matbeg[i]]);
00075   for (int k=0; k<mat.matcnt[i]; k++, val++, col++) {
00076     res[i] += vec[*col] * (*val);
00077     }
00078   }
00079 }
00080 
00081 
00082 //---------------------------------------------------------------------------
00083 
00084 template <class T>
00085 class UTILIB_API SparseMatrix
00086 {
00087 public:
00088 
00090   int get_ncols( void ) const { return ncols; }
00092   int get_nrows( void ) const { return nrows; }
00094   int get_nnzero( void ) const {return nnzeros;}
00096   IntVector& get_matbeg( void ) { return matbeg; }
00098   IntVector& get_matcnt( void ) { return matcnt; }
00100   IntVector& get_matind( void ) { return matind; }
00102   NumArray<T>& get_matval( void ) { return matval; }
00103 
00105   virtual T& operator()(const int row, const int col) = 0;
00107   virtual const T& operator()(const int row, const int col) const = 0;
00108 
00110   virtual int pretty_print(ostream& ostr) const;
00112   virtual int write(ostream& ostr) const = 0;
00114   virtual int read(istream& istr) = 0;
00116   int write(PackBuffer& ostr) const;
00118   int read(UnPackBuffer& istr);
00119 
00121   virtual void delete_row(const int i) = 0;
00123   virtual void delete_col(const int i) = 0;
00125   virtual void delete_element(const int row, const int col) = 0;
00126 
00127 protected:
00128 
00130   SparseMatrix( void ) :
00131         ncols(0), nrows(0), nnzeros(0) {}
00133   virtual ~SparseMatrix() {}
00134 
00136   virtual void initialize(int nrow, int ncol, int nnzero) = 0;
00138   void setup(int ncol, int nrow, int nnzero, int flag);
00140   int          ncols;
00142   int          nrows;
00144   int          nnzeros;
00146   IntVector    matbeg;
00148   IntVector    matcnt;
00150   IntVector    matind;
00152   NumArray<T> matval;
00153 
00154 };
00155 
00156 
00157 template <class T>
00158 inline ostream& operator<<(ostream& output, const SparseMatrix<T>& array)
00159 { array.write(output); return(output); }
00160 
00161 template <class T>
00162 inline istream& operator>>(istream& input, SparseMatrix<T>& array)
00163 { array.read(input); return(input); }
00164 
00165 
00167 template <class T>
00168 inline UTILIB_API PackBuffer& operator<<(PackBuffer& output, const SparseMatrix<T
00169 >& array)
00170 { array.write(output); return(output); }
00171 
00173 template <class T>
00174 inline UTILIB_API UnPackBuffer& operator>>(UnPackBuffer& input, SparseMatrix<T>&
00175 array)
00176 { array.read(input); return(input); }
00177 
00178 //---------------------------------------------------------------------------
00179 
00180 template <class T>
00181 class UTILIB_API CMSparseMatrix : public SparseMatrix<T>
00182 {
00183 public:
00184 
00185   friend RMSparseMatrix<T>;
00186 
00188   CMSparseMatrix( void ) {}
00190   CMSparseMatrix( int nrow, int ncol, int nnzero )
00191                 {setup(nrow,ncol,nnzero,1);}
00193   CMSparseMatrix( CMSparseMatrix<Ereal<T> >& mat);
00195   ~CMSparseMatrix() {}
00196 
00198   void initialize(int nrow, int ncol, int nnzero)
00199                 {
00200                 setup(nrow,ncol,nnzero,1);
00201                 ncols=ncol;
00202                 nrows=nrow;
00203                 nnzeros=nnzero;
00204                 }
00205   
00207   T& operator()(const int row, const int col);
00209   const T& operator()(const int row, const int col) const;
00210 
00212   int adjoinColumn(int count, int* rowPosition, T* value);
00213 
00215   int write(ostream& ostr) const;
00217   int read(istream& istr);
00219   void convert(const RMSparseMatrix<T>& rowmajor);
00220 
00222   void delete_row(const int i);
00224   void delete_col(const int i);
00226   void delete_element(const int row, const int col);
00227 };
00228 
00229 
00230 //---------------------------------------------------------------------------
00231 
00232 template <class T>
00233 class UTILIB_API RMSparseMatrix : public SparseMatrix<T>
00234 {
00235 public:
00236 
00237   friend CMSparseMatrix<T>;
00238 
00239   friend UTILIB_API void product<T>(NumArray<T>& res, 
00240                                 const RMSparseMatrix<T>& mat, 
00241                                 const NumArray<T>& vec);
00242 
00244   RMSparseMatrix( void ) {}
00246   RMSparseMatrix( int nrow, int ncol, int nnzero )
00247                 {setup(nrow,ncol,nnzero,0);}
00249   virtual ~RMSparseMatrix() {}
00250 
00252   void initialize(int nrow, int ncol, int nnzero)
00253                 {
00254                 setup(nrow,ncol,nnzero,0);
00255                 ncols=ncol;
00256                 nrows=nrow;
00257                 nnzeros=nnzero;
00258                 }
00260   void resize(const int rowndx, const int rowlen);
00261 
00263   T& operator()(const int row, const int col);
00265   const T& operator()(const int row, const int col) const;
00266 
00268   int adjoinRow(int count, int* colPosition, T* value);
00269 
00271   int write(ostream& ostr) const;
00273   int read(istream& istr);
00275   void convert(const CMSparseMatrix<T>& colmajor);
00276 
00278   void delete_row(const int i);
00280   void delete_col(const int i);
00282   void delete_element(const int row, const int col);
00283 };
00284 
00285 
00286 
00287 
00288 //
00289 // This just sets up the memory, but does not modify the ncols, nrows or
00290 // nnzeros values
00291 //
00292 template <class T>
00293 void SparseMatrix<T>::setup(int nrow, int ncol, int nnzero, int flag)
00294 {
00295 matind.resize(nnzero);
00296 matval.resize(nnzero);
00297 if (flag) {
00298    matbeg.resize(ncol);
00299    matcnt.resize(ncol);
00300    }
00301 else {
00302    matbeg.resize(nrow);
00303    matcnt.resize(nrow);
00304    }
00305 }
00306 
00307 
00308 template <class T>
00309 CMSparseMatrix<T>::CMSparseMatrix( CMSparseMatrix<Ereal<T> >& mat)
00310 {
00311 initialize(mat.get_nrows(), mat.get_ncols(), mat.get_nnzero());
00312 matind << mat.get_matind();
00313 matval << mat.get_matval();
00314 matbeg << mat.get_matbeg();
00315 matcnt << mat.get_matcnt();
00316 }
00317 
00318 
00319 template <class T>
00320 T& CMSparseMatrix<T>::operator()(const int row, const int col)
00321 {
00322 if ((row < 0) || (row >= nrows) || (col < 0) || (col >= ncols))
00323    ErrAbort(errmsg("CMSparseMatrix<T>::operator : iterator out of range. %dx%d not in %dx%d",row,col,nrows,ncols));
00324 
00325 int pt = matbeg[col];
00326 for (int i=0; i<matcnt[col]; i++)
00327   if (matind[pt+i] == row)
00328      return matval[pt+i];
00329 
00330 return matval[0];
00331 }
00332 
00333 
00334 template <class T>
00335 const T& CMSparseMatrix<T>::operator()(const int row, const int col) const
00336 {
00337 if ((row < 0) || (row >= nrows) || (col < 0) || (col >= ncols))
00338    ErrAbort(errmsg("CMSparseMatrix<T>::operator : iterator out of range. %dx%d not in %dx%d",row,col,nrows,ncols));
00339 
00340 int pt = matbeg[col];
00341 for (int i=0; i<matcnt[col]; i++)
00342   if (matind[pt+i] == row)
00343      return matval[pt+i];
00344 
00345 return matval[0];
00346 }
00347 
00348 
00349 template <class T>
00350 T& RMSparseMatrix<T>::operator()(const int row, const int col)
00351 {
00352 if ((row < 0) || (row >= nrows) || (col < 0) || (col >= ncols))
00353    ErrAbort(errmsg("RMSparseMatrix<T>::operator : iterator out of range. %dx%d not in %dx%d",row,col,nrows,ncols));
00354 
00355 int pt = matbeg[row];
00356 for (int i=0; i<matcnt[row]; i++)
00357   if (matind[pt+i] == col)
00358      return matval[pt+i];
00359 
00360 return matval[0];
00361 }
00362 
00363 
00364 template <class T>
00365 const T& RMSparseMatrix<T>::operator()(const int row, const int col) const
00366 {
00367 if ((row < 0) || (row >= nrows) || (col < 0) || (col >= ncols))
00368    ErrAbort(errmsg("RMSparseMatrix<T>::operator : iterator out of range. %dx%d not in %dx%d",row,col,nrows,ncols));
00369 
00370 int pt = matbeg[row];
00371 for (int i=0; i<matcnt[row]; i++)
00372   if (matind[pt+i] == col)
00373      return matval[pt+i];
00374 
00375 return matval[0];
00376 }
00377 
00378 
00379 template <class T>
00380 int SparseMatrix<T>::pretty_print(ostream& ostr) const
00381 {
00382 for (int i=0; i<nrows; i++) {
00383   for (int j=0; j<ncols; j++)
00384     ostr << operator()(i,j) << " ";
00385   ostr << endl;
00386   }
00387 return OK;
00388 }
00389 
00390 
00391 template <class T>
00392 int CMSparseMatrix<T>::write(ostream& ostr) const 
00393 {
00394 ostr << nrows << " " << ncols << " " << nnzeros << ":" << endl;
00395 int ndx=0;
00396 for (int i=0; i<ncols; i++)
00397   for (int j=0; j<matcnt[i]; j++) {
00398     ostr << " (" << matind[ndx] << "," << i << ") " << matval[ndx] << endl;
00399     ndx++;
00400     }
00401 
00402 return OK;
00403 }
00404 
00405 
00406 template <class T>
00407 int CMSparseMatrix<T>::read(istream& istr)
00408 {
00409 ErrAbort("CMSparseMatrix<T>::read - not implemented!");
00410 return ERR;
00411 }
00412 
00413 
00414 template <class T>
00415 int SparseMatrix<T>::write(PackBuffer& ostr) const 
00416 {
00417 ostr << nrows << ncols << nnzeros;
00418 ostr << matbeg << matcnt << matind << matval;
00419 
00420 return OK;
00421 }
00422 
00423 
00424 template <class T>
00425 int SparseMatrix<T>::read(UnPackBuffer& istr)
00426 {
00427 int ntmp, ctmp, ztmp;
00428 istr >> ntmp >> ctmp >> ztmp;
00429 initialize(ntmp,ctmp,ztmp);
00430 istr >> matbeg >> matcnt >> matind >> matval;
00431 return OK;
00432 }
00433 
00434 
00435 template <class T>
00436 int RMSparseMatrix<T>::write(ostream& ostr) const 
00437 {
00438 ostr << nrows << " " << ncols << " " << nnzeros << ":" << endl;
00439 int ndx=0;
00440 for (int i=0; i<nrows; i++)
00441   for (int j=0; j<matcnt[i]; j++) {
00442     ostr << " (" << i << "," << matind[ndx] << ") " << matval[ndx] << endl;
00443     ndx++;
00444     }
00445 
00446 return OK;
00447 }
00448 
00449 
00450 template <class T>
00451 int RMSparseMatrix<T>::read(istream& istr)
00452 {
00453 ErrAbort("RMSparseMatrix<T>::read - not implemented!");
00454 return ERR;
00455 }
00456 
00457 
00458 
00459 template <class T>
00460 void RMSparseMatrix<T>::delete_row(const int i)
00461 {
00462 //
00463 // Delete all of the elements in the row
00464 //
00465 while (matcnt[i] > 0)
00466   delete_element(i,matind[matbeg[i]]);
00467 //
00468 // Delete the row itself
00469 //
00470 for (int j=i; j<(nrows-1); j++) {
00471   matbeg[j] = matbeg[j+1];
00472   matcnt[j] = matcnt[j+1];
00473   }
00474 nrows--;
00475 }
00476 
00477 
00478 template <class T>
00479 void RMSparseMatrix<T>::delete_col(const int i)
00480 {
00481 //
00482 // Delete all of the elements in the column
00483 //
00484 for (int j=0; j<nrows; j++) {
00485   //
00486   // Look for column i in row j
00487   //
00488   int k=0;
00489   while (k < matcnt[j]) {
00490     if (matind[matbeg[j]+k] == i)
00491        delete_element(j,i);
00492     else {
00493        if (matind[matbeg[j]+k] > i)
00494           matind[matbeg[j]+k]--;
00495        k++;
00496        }
00497     }
00498   }
00499 //
00500 // Delete the column itself (the column indeces are decremented above!)
00501 //
00502 ncols--;
00503 }
00504 
00505 
00506 template <class T>
00507 void RMSparseMatrix<T>::delete_element(const int rowndx, const int colndx)
00508 {
00509 int k=0;
00510 for (; k<matcnt[rowndx]; k++)
00511   if (matind[matbeg[rowndx]+k] == colndx) {
00512      break;
00513      }
00514 if (k == matcnt[rowndx]) return;
00515 
00516 for (int i=matbeg[rowndx]+k; i<(nnzeros-1); i++) {
00517   matind[i] = matind[i+1];
00518   matval[i] = matval[i+i];
00519   }
00520 matcnt[rowndx]--;
00521 for (int j=rowndx+1; j<nrows; j++)
00522   matbeg[j]--;
00523 nnzeros--;
00524 }
00525 
00526 
00527 template <class T>
00528 void RMSparseMatrix<T>::resize(const int rowndx, const int rowlen)
00529 {
00530 if (rowlen == matcnt[rowndx])
00531    return;
00532 else if (rowlen > matcnt[rowndx]) {
00533    // TODO - resize the array up!
00534    }
00535 else {
00536    int diff = rowlen-matcnt[rowndx];
00537 
00538    if (diff < 0) {
00539       for (int i=matbeg[rowndx]+rowlen; i<(nnzeros+diff); i++) {
00540         matind[i] = matind[i-diff];
00541         matval[i] = matval[i-diff];
00542         }
00543       }
00544    matcnt[rowndx] += diff;
00545    for (int j=rowndx+1; j<nrows; j++)
00546      matbeg[j] += diff;
00547    nnzeros += diff;
00548    }
00549 }
00550 
00551 
00552 template <class T>
00553 void CMSparseMatrix<T>::convert(const RMSparseMatrix<T>& rowmajor)
00554 {
00555 matval.resize(rowmajor.nnzeros);
00556 matind.resize(rowmajor.nnzeros);
00557 
00558 ncols = rowmajor.ncols;
00559 nrows = rowmajor.nrows;
00560 nnzeros = rowmajor.nnzeros;
00561 matcnt.resize(ncols);
00562 matcnt=0;
00563 matbeg.resize(ncols);
00564 
00565 IntVector rowndx(nrows);
00566 rowndx=0;
00567 int prev_cndx=0;
00568 
00569 for (int i=0; i<nnzeros; i++) {
00570   //
00571   // Set dummy values for cndx and rndx
00572   //
00573   int cndx=ncols;
00574   int rndx=-1;
00575   //
00576   // Find the point in the matrix with the next highest column index
00577   //
00578   for (int j=0; j<nrows; j++) {
00579     if ((rowmajor.matcnt[j] > 0) && (rowmajor.matcnt[j] > rowndx[j])) {
00580        if (rowmajor.matind[rowmajor.matbeg[j]+rowndx[j]] < cndx) {
00581           cndx = rowmajor.matind[rowmajor.matbeg[j]+rowndx[j]];
00582           rndx = j;
00583           }
00584        }
00585     if (cndx == prev_cndx)      // Can stop early because we're in the same col
00586        break;
00587     }
00588   //
00589   // Add this new point to the CM matrix
00590   //
00591   if (matcnt[cndx] == 0)
00592      matbeg[cndx] = i;
00593   matcnt[cndx]++;
00594   matind[i] = rndx;
00595   matval[i] = rowmajor.matval[rowmajor.matbeg[rndx]+rowndx[rndx]];
00596 
00597   rowndx[rndx]++;
00598   prev_cndx=cndx;
00599   }
00600 }
00601 
00602 
00603 template <class T>
00604 void RMSparseMatrix<T>::convert(const CMSparseMatrix<T>& colmajor)
00605 {
00606 matval.resize(colmajor.nnzeros);
00607 matind.resize(colmajor.nnzeros);
00608 
00609 ncols = colmajor.ncols;
00610 nrows = colmajor.nrows;
00611 nnzeros = colmajor.nnzeros;
00612 matcnt.resize(nrows);
00613 matcnt=0;
00614 matbeg.resize(nrows);
00615 
00616 IntVector colndx(ncols);
00617 colndx=0;
00618 int prev_rndx=0;
00619 
00620 for (int i=0; i<nnzeros; i++) {
00621   //
00622   // Find the point in the matrix with the next highest row index
00623   //
00624   int cndx=-1;
00625   int rndx=nrows;
00626   for (int j=0; j<ncols; j++) {
00627     if ((colmajor.matcnt[j] > 0) && (colmajor.matcnt[j] > colndx[j])) {
00628        if (colmajor.matind[colmajor.matbeg[j]+colndx[j]] < rndx) {
00629           cndx = j;
00630           rndx = colmajor.matind[colmajor.matbeg[j]+colndx[j]];
00631           }
00632        }
00633     if (prev_rndx == rndx)      // Can stop because we are on the same row
00634        break;
00635     }
00636   
00637   //
00638   // Add this new point to the RM matrix
00639   //
00640   if (matcnt[rndx] == 0)
00641      matbeg[rndx] = i;
00642   matcnt[rndx]++;
00643   matind[i] = cndx;
00644   matval[i] = colmajor.matval[colmajor.matbeg[cndx]+colndx[cndx]];
00645 
00646   colndx[cndx]++;
00647   prev_rndx=rndx;
00648   }
00649 }
00650 
00651 
00652 
00653 template <class T>
00654 int CMSparseMatrix<T>::adjoinColumn(int count, int* rowPosition, T* value)
00655 {
00656 if (ncols == (int) matcnt.size()) {
00657    matcnt.resize(ncols+32);
00658    matbeg.resize(ncols+32);
00659    }
00660 
00661 if (nnzeros + count > (int) matval.size()) {
00662    matval.resize(nnzeros+max(count,64));
00663    matind.resize(nnzeros+max(count,64));
00664    }
00665 
00666 matbeg[ncols] = nnzeros;
00667 matcnt[ncols++] = count;
00668 for (int i=0; i<count; i++) {
00669   matind[nnzeros]   = rowPosition[i];
00670   // If we're building from scratch, number of rows is the highest row
00671   // number seen so far (+1 since 0 based)
00672   if (rowPosition[i] >= nrows)
00673     nrows = rowPosition[i] + 1;
00674   matval[nnzeros++] = value[i];
00675   }
00676 
00677 return nnzeros;
00678 }
00679 
00680 
00681 template <class T>
00682 void CMSparseMatrix<T>::delete_col(const int i)
00683 {
00684 //
00685 // Delete all of the elements in the col 
00686 //
00687 while (matcnt[i])
00688   delete_element(matind[matbeg[i]],i);
00689 //
00690 // Delete the col itself
00691 //
00692 for (int j=i; j<(ncols-1); j++) {
00693   matbeg[j] = matbeg[j+1];
00694   matcnt[j] = matcnt[j+1];
00695   }
00696 ncols--;
00697 }
00698 
00699 
00700 template <class T>
00701 void CMSparseMatrix<T>::delete_row(const int i)
00702 {
00703 //
00704 // Delete all of the elements in the column
00705 //
00706 for (int j=0; j<ncols; j++) {
00707   //
00708   // Look for row i in row j
00709   //
00710   int k=0;
00711   while (k < matcnt[j]) {
00712     if (matind[matbeg[j]+k] == i)
00713        delete_element(i,j);
00714     else {
00715        if (matind[matbeg[j]+k] > i)
00716           matind[matbeg[j]+k]--;
00717        k++;
00718        }
00719     }
00720   }
00721 //
00722 // Delete the row itself (the row indeces are decremented above!)
00723 //
00724 nrows--;
00725 }
00726 
00727 
00728 template <class T>
00729 void CMSparseMatrix<T>::delete_element(const int rowndx, const int colndx)
00730 {
00731 int k=0;
00732 for (; k<matcnt[colndx]; k++)
00733   if (matind[matbeg[colndx]+k] == rowndx) {
00734      break;
00735      }
00736 if (k == matcnt[colndx]) return;
00737 
00738 for (int i=matbeg[colndx]+k; i<(nnzeros-1); i++) {
00739   matind[i] = matind[i+1];
00740   matval[i] = matval[i+1];
00741   }
00742 matcnt[colndx]--;
00743 for (int j=colndx+1; j<ncols; j++)
00744   matbeg[j]--;
00745 nnzeros--;
00746 }
00747 
00748 
00749 
00750 template <class T>
00751 int RMSparseMatrix<T>::adjoinRow(int count, int* colPosition, T* value)
00752 {
00753 if (nrows == (int) matcnt.size()) {
00754    matcnt.resize(nrows+32);
00755    matbeg.resize(nrows+32);
00756    }
00757 
00758 if (nnzeros + count > (int) matval.size()) {
00759    matval.resize(nnzeros+max(count,64));
00760    matind.resize(nnzeros+max(count,64));
00761    }
00762 
00763 matbeg[nrows] = nnzeros;
00764 matcnt[nrows++] = count;
00765 for (int i=0; i<count; i++) {
00766   matind[nnzeros]   = colPosition[i];
00767   matval[nnzeros++] = value[i];
00768   }
00769 
00770 return nnzeros;
00771 }
00772 
00773 
00774 
00775 #endif