spm.h

00001 #ifndef gridripper_math_spm_h
00002 #define gridripper_math_spm_h
00003 
00004 #include <cstring>
00005 
00006 namespace gridripper { namespace math {
00007 
00015 template <class TD>
00016 class SpM
00017 {
00018 private:
00019     int numRows;
00020     int numColumns;
00021 
00022 protected:
00028     SpM(int nrows, int ncols): numRows(nrows), numColumns(ncols) {
00029     }
00030 
00031     void resize(int nrows, int ncols) {
00032         numRows = nrows;
00033         numColumns = ncols;
00034     }
00035 
00036 public:
00041     int getNumRows() const {
00042         return numRows;
00043     }
00044 
00049     int getNumColumns() const {
00050         return numColumns;
00051     }
00052 
00058     virtual int countNonzerosInRow(int row) const =0;
00059 
00069     virtual void gmv(TD* y, TD alpha, const TD* x, TD beta, const TD* b)
00070         const =0;
00071 
00076     virtual void toDenseMatrix(TD* mat) const =0;
00077 };
00078 
00090 template <class TD, class TI>
00091 class DiaSpM: public SpM<TD>
00092 {
00093 private:
00094     TD* data;
00095     TI* offsets;
00096     int numDiagonals;
00097 
00098 public:
00106     DiaSpM(int nrows, int ncols, int ndia): SpM<TD>(nrows, ncols), numDiagonals(ndia) {
00107         int n = nrows*ndia;
00108         data = new TD[n];
00109         offsets = new TI[ndia];
00110         for(int i = 0; i < n; ++i) {
00111             data[i] = 0;
00112         }
00113         for(int i = 0; i < ndia; ++i) {
00114             offsets[i] = 0;
00115         }
00116     }
00117 
00118     ~DiaSpM() {
00119         delete [] data;
00120         delete [] offsets;
00121     }
00122 
00129     void realloc(int nrows, int ncols, int ndia) {
00130         if(nrows == SpM<TD>::getNumRows()
00131                 && ncols == SpM<TD>::getNumColumns()
00132                 && numDiagonals == ndia) {
00133             return;
00134         }
00135         delete [] data;
00136         delete [] offsets;
00137         SpM<TD>::resize(nrows, ncols);
00138         numDiagonals = ndia;
00139         int n = nrows*ndia;
00140         data = new TD[n];
00141         offsets = new TI[ndia];
00142     }
00143 
00149     void setOffset(int dia, TI offset) {
00150         offsets[dia] = offset;
00151     }
00152 
00159     void set(int row, int dia, TD v) {
00160         data[row*numDiagonals + dia] = v;
00161     }
00162 
00167     const TD* internalArray() const {
00168         return data;
00169     }
00170 
00175     TD* internalArray() {
00176         return data;
00177     }
00178 
00183     int arrayLength() const {
00184         return SpM<TD>::getNumRows()*numDiagonals;
00185     }
00186 
00192     const TI* internalOffsetArray() const {
00193         return offsets;
00194     }
00195 
00201     TI* internalOffsetArray() {
00202         return offsets;
00203     }
00204 
00209     int getNumDiagonals() const {
00210         return numDiagonals;
00211     }
00212 
00218     int countNonzerosInRow(int row) const {
00219         int nrows = SpM<TD>::getNumRows();
00220         int ncols = SpM<TD>::getNumColumns();
00221         int n = 0;
00222         for(int dia = 0; dia < numDiagonals; ++dia) {
00223             int offset = offsets[dia];
00224             int start = offset < 0? -offset : 0;
00225             int end = ncols - offset;
00226             if(end > nrows) {
00227                 end = nrows;
00228             }
00229             if(row >= start && row < end) {
00230                 ++n;
00231             }
00232         }
00233         return n;
00234     }
00235 
00245     void gmv(TD* y, TD alpha, const TD* x, TD beta, const TD* b) const {
00246         int nrows = SpM<TD>::getNumRows();
00247         int ncols = SpM<TD>::getNumColumns();
00248         for(int row = 0; row < nrows; ++row) {
00249             TD v = 0;
00250             for(int dia = 0; dia < numDiagonals; ++dia) {
00251                 int offset = offsets[dia];
00252                 int start = offset < 0? -offset : 0;
00253                 int end = ncols - offset;
00254                 if(end > nrows) {
00255                     end = nrows;
00256                 }
00257                 if(row >= start && row < end) {
00258                     v += data[row*numDiagonals + dia]*x[row + offset];
00259                 }
00260             }
00261             if(b != NULL) {
00262                 y[row] = alpha*v + beta*b[row];
00263             } else {
00264                 y[row] = alpha*v;
00265             }
00266         }
00267     }
00268 
00273     void toDenseMatrix(TD* mat) const {
00274         int nrows = SpM<TD>::getNumRows();
00275         int ncols = SpM<TD>::getNumColumns();
00276         memset(mat, 0, nrows*ncols*sizeof(mat[0]));
00277         for(int dia = 0; dia < numDiagonals; ++dia) {
00278             int offset = offsets[dia];
00279             int row = offset < 0? -offset : 0;
00280             int end = ncols - offset;
00281             if(end > nrows) {
00282                 end = nrows;
00283             }
00284             while(row < end) {
00285                 mat[row*ncols + row + offset] = data[row*numDiagonals + dia];
00286                 ++row;
00287             }
00288         }
00289     }
00290 };
00291 
00303 template <class TD, class TI>
00304 class EllSpM: public SpM<TD>
00305 {
00306 private:
00307     TD* data;
00308     TI* columnIndices;
00309     int maxNonzerosPerRow;
00310 
00311 public:
00319     EllSpM(int nrows, int ncols, int nonzero): SpM<TD>(nrows, ncols),
00320             maxNonzerosPerRow(nonzero) {
00321         int n = nrows*nonzero;
00322         data = new TD[n];
00323         columnIndices = new TI[n];
00324         for(int i = 0; i < n; ++i) {
00325             data[i] = 0;
00326             columnIndices[i] = -1;
00327         }
00328     }
00329 
00330     ~EllSpM() {
00331         delete [] data;
00332         delete [] columnIndices;
00333     }
00334 
00341     void realloc(int nrows, int ncols, int nonzero) {
00342         if(nrows == SpM<TD>::getNumRows()
00343                 && ncols == SpM<TD>::getNumColumns()
00344                 && maxNonzerosPerRow == nonzero) {
00345             return;
00346         }
00347         delete [] data;
00348         delete [] columnIndices;
00349         SpM<TD>::resize(nrows, ncols);
00350         maxNonzerosPerRow = nonzero;
00351         int n = nrows*nonzero;
00352         data = new TD[n];
00353         columnIndices = new TI[n];
00354         for(int i = 0; i < n; ++i) {
00355             columnIndices[i] = -1;
00356         }
00357     }
00358 
00366     void set(int row, int col, TD v, int i) {
00367         int k = row*maxNonzerosPerRow + i;
00368         columnIndices[k] = col;
00369         data[k] = v;
00370     }
00371 
00376     const TD* internalArray() const {
00377         return data;
00378     }
00379 
00384     TD* internalArray() {
00385         return data;
00386     }
00387 
00392     const TI* internalColumnIndexArray() const {
00393         return columnIndices;
00394     }
00395 
00400     TI* internalColumnIndexArray() {
00401         return columnIndices;
00402     }
00403 
00408     int arrayLength() const {
00409         return SpM<TD>::getNumRows()*maxNonzerosPerRow;
00410     }
00411 
00417     int countNonzerosInRow(int row) const {
00418         int n = 0;
00419         int offset = row*maxNonzerosPerRow;
00420         for(int i = 0; i < maxNonzerosPerRow; ++i) {
00421             int icol = columnIndices[offset + i];
00422             if(icol < 0) {
00423                 break;
00424             }
00425             ++n;
00426         }
00427         return n;
00428     }
00429 
00439     void gmv(TD* y, TD alpha, const TD* x, TD beta, const TD* b) const {
00440         int nrows = SpM<TD>::getNumRows();
00441         for(int irow = 0; irow < nrows; ++irow) {
00442             TD v = 0;
00443             int offset = irow*maxNonzerosPerRow;
00444             for(int i = 0; i < maxNonzerosPerRow; ++i) {
00445                 int icol = columnIndices[offset + i];
00446                 if(icol < 0) {
00447                     break;
00448                 }
00449                 v += data[offset + i]*x[icol];
00450             }
00451             if(b != NULL) {
00452                 y[irow] = alpha*v + beta*b[irow];
00453             } else {
00454                 y[irow] = alpha*v;
00455             }
00456         }
00457     }
00458 
00463     int getMaxNonzerosPerRow() const {
00464         return maxNonzerosPerRow;
00465     }
00466 
00471     void toDenseMatrix(TD* mat) const {
00472         int nrows = SpM<TD>::getNumRows();
00473         int ncols = SpM<TD>::getNumColumns();
00474         memset(mat, 0, nrows*ncols*sizeof(mat[0]));
00475         int offset = 0;
00476         for(int irow = 0; irow < nrows; ++irow) {
00477             for(int i = 0; i < maxNonzerosPerRow; ++i) {
00478                 int icol = columnIndices[offset + i];
00479                 if(icol < 0) {
00480                     break;
00481                 }
00482                 mat[irow*ncols + icol] = data[offset + i];
00483             }
00484             offset += maxNonzerosPerRow;
00485         }
00486     }
00487 };
00488 
00500 template <class TD, class TI>
00501 class CooSpM: public SpM<TD>
00502 {
00503 private:
00504     TD* data;
00505     TI* rowIndices;
00506     TI* columnIndices;
00507     int nonzeroCount;
00508 
00509 public:
00517     CooSpM(int nrows, int ncols, int maxnonzero): SpM<TD>(nrows, ncols),
00518             nonzeroCount(maxnonzero) {
00519         data = new TD[maxnonzero];
00520         rowIndices = new TI[maxnonzero];
00521         columnIndices = new TI[maxnonzero];
00522         for(int i = 0; i < maxnonzero; ++i) {
00523             data[i] = 0;
00524             rowIndices[i] = 0;
00525             columnIndices[i] = 0;
00526         }
00527     }
00528 
00529     ~CooSpM() {
00530         delete [] data;
00531         delete [] rowIndices;
00532         delete [] columnIndices;
00533     }
00534 
00541     void realloc(int nrows, int ncols, int nonzero) {
00542         if(nrows == SpM<TD>::getNumRows()
00543                 && ncols == SpM<TD>::getNumColumns()
00544                 && nonzero == nonzeroCount) {
00545             return;
00546         }
00547         delete [] data;
00548         delete [] rowIndices;
00549         delete [] columnIndices;
00550         SpM<TD>::resize(nrows, ncols);
00551         nonzeroCount = nonzero;
00552         data = new TD[nonzero];
00553         rowIndices = new TI[nonzero];
00554         columnIndices = new TI[nonzero];
00555     }
00556 
00564     void set(int row, int col, TD v, int i) {
00565         data[i] = v;
00566         rowIndices[i] = row;
00567         columnIndices[i] = col;
00568     }
00569 
00574     const TD* internalArray() const {
00575         return data;
00576     }
00577 
00582     TD* internalArray() {
00583         return data;
00584     }
00585 
00590     int arrayLength() const {
00591         return nonzeroCount;
00592     }
00593 
00598     const TI* internalRowIndexArray() const {
00599         return rowIndices;
00600     }
00601 
00606     TI* internalRowIndexArray() {
00607         return rowIndices;
00608     }
00609 
00614     const TI* internalColumnIndexArray() const {
00615         return columnIndices;
00616     }
00617 
00622     TI* internalColumnIndexArray() {
00623         return columnIndices;
00624     }
00625 
00631     int countNonzerosInRow(int row) const {
00632         int n = 0;
00633         for(int i = 0; i < nonzeroCount; ++i) {
00634             if(rowIndices[i] == row) {
00635                 ++n;
00636             }
00637         }
00638         return n;
00639     }
00640 
00650     void gmv(TD* y, TD alpha, const TD* x, TD beta, const TD* b) const {
00651         int nrows = SpM<TD>::getNumRows();
00652         if(b != NULL) {
00653             for(int row = 0; row < nrows; ++row) {
00654                 y[row] = beta*b[row];
00655             }
00656         } else {
00657             for(int row = 0; row < nrows; ++row) {
00658                 y[row] = 0;
00659             }
00660         }
00661         for(int i = 0; i < nonzeroCount; ++i) {
00662             int irow = rowIndices[i];
00663             int icol = columnIndices[i];
00664             y[irow] += alpha*data[i]*x[icol];
00665         }
00666     }
00667 
00672     int getNonzeroCount() const {
00673         return nonzeroCount;
00674     }
00675 
00680     void toDenseMatrix(TD* mat) const {
00681         int nrows = SpM<TD>::getNumRows();
00682         int ncols = SpM<TD>::getNumColumns();
00683         memset(mat, 0, nrows*ncols*sizeof(mat[0]));
00684         for(int i = 0; i < nonzeroCount; ++i) {
00685             int irow = rowIndices[i];
00686             int icol = columnIndices[i];
00687             mat[irow*ncols + icol] = data[i];
00688         }
00689     }
00690 };
00691 
00703 template <class TD, class TI>
00704 class CsrSpM: public SpM<TD>
00705 {
00706 private:
00707     TD* data;
00708     TI* columnIndices;
00709     TI* rowPtr;
00710     int nonzeroCount;
00711 
00712 public:
00720     CsrSpM(int nrows, int ncols, int nonzero): SpM<TD>(nrows, ncols),
00721             nonzeroCount(nonzero) {
00722         data = new TD[nonzero];
00723         columnIndices = new TI[nonzero];
00724         rowPtr = new TI[nrows + 1];
00725         for(int i = 0; i < nonzero; ++i) {
00726             data[i] = 0;
00727             columnIndices[i] = 0;
00728         }
00729         for(int i = 0; i <= nrows; ++i) {
00730             rowPtr[i] = 0;
00731         }
00732     }
00733 
00734     ~CsrSpM() {
00735         delete [] data;
00736         delete [] columnIndices;
00737         delete [] rowPtr;
00738     }
00739 
00746     void realloc(int nrows, int ncols, int nonzero) {
00747         if(nrows == SpM<TD>::getNumRows()
00748                 && ncols == SpM<TD>::getNumColumns()
00749                 && nonzero == nonzeroCount) {
00750             return;
00751         }
00752         delete [] data;
00753         delete [] columnIndices;
00754         delete [] rowPtr;
00755         SpM<TD>::resize(nrows, ncols);
00756         nonzeroCount = nonzero;
00757         data = new TD[nonzero];
00758         columnIndices = new TI[nonzero];
00759         rowPtr = new TI[nrows + 1];
00760     }
00761 
00767     void setRowPtr(int row, TI p) {
00768         rowPtr[row] = p;
00769     }
00770 
00778     void set(int row, int col, TD v, int i) {
00779         data[i] = v;
00780         columnIndices[i] = col;
00781     }
00782 
00787     const TD* internalArray() const {
00788         return data;
00789     }
00790 
00795     TD* internalArray() {
00796         return data;
00797     }
00798 
00803     int arrayLength() const {
00804         return nonzeroCount;
00805     }
00806 
00811     const TI* internalRowPtrArray() const {
00812         return rowPtr;
00813     }
00814 
00819     TI* internalRowPtrArray() {
00820         return rowPtr;
00821     }
00822 
00827     const TI* internalColumnIndexArray() const {
00828         return columnIndices;
00829     }
00830 
00835     TI* internalColumnIndexArray() {
00836         return columnIndices;
00837     }
00838 
00844     int countNonzerosInRow(int row) const {
00845         return rowPtr[row + 1] - rowPtr[row];
00846     }
00847 
00857     void gmv(TD* y, TD alpha, const TD* x, TD beta, const TD* b) const {
00858         int nrows = SpM<TD>::getNumRows();
00859         if(b != NULL) {
00860             for(int row = 0; row < nrows; ++row) {
00861                 y[row] = beta*b[row];
00862             }
00863         } else {
00864             for(int row = 0; row < nrows; ++row) {
00865                 y[row] = 0;
00866             }
00867         }
00868         for(int irow = 0; irow < nrows; ++irow) {
00869             int start = rowPtr[irow];
00870             int end = rowPtr[irow + 1];
00871             for(int i = start; i < end; ++i) {
00872                 y[irow] += alpha*data[i]*x[columnIndices[i]];
00873             }
00874         }
00875     }
00876 
00881     int getNonzeroCount() const {
00882         return nonzeroCount;
00883     }
00884 
00889     void toDenseMatrix(TD* mat) const {
00890         int nrows = SpM<TD>::getNumRows();
00891         int ncols = SpM<TD>::getNumColumns();
00892         memset(mat, 0, nrows*ncols*sizeof(mat[0]));
00893         for(int irow = 0; irow < nrows; ++irow) {
00894             int p = rowPtr[irow];
00895             int end = rowPtr[irow + 1];
00896             while(p < end) {
00897                 mat[irow*ncols + columnIndices[p]] = data[p];
00898                 ++p;
00899             }
00900         }
00901     }
00902 };
00903 
00904 } } // namespace gridripper::math
00905 
00906 #endif /* gridripper_math_spm_h */