From 3c1a9263cbb103c1f6ff4bf7fd50cf449db0f8e0 Mon Sep 17 00:00:00 2001 From: Thomas Fischer <thomas.fischer@ufz.de> Date: Tue, 8 Nov 2011 16:55:51 +0100 Subject: [PATCH] implementation of method eraseEntries() in class template CRSMatrix - backup of work --- MathLib/LinAlg/Sparse/CRSMatrix.h | 206 +++++++++++++++++- MathLib/LinAlg/Sparse/CRSTranspose.h | 8 +- MathLib/sparse.h | 71 +++--- SimpleTests/MatrixTests/CMakeLists.txt | 16 ++ .../MatrixTests/MatTestRemoveRowsCols.cpp | 71 ++++++ 5 files changed, 322 insertions(+), 50 deletions(-) create mode 100644 SimpleTests/MatrixTests/MatTestRemoveRowsCols.cpp diff --git a/MathLib/LinAlg/Sparse/CRSMatrix.h b/MathLib/LinAlg/Sparse/CRSMatrix.h index ba7042f5122..49737ebe79e 100644 --- a/MathLib/LinAlg/Sparse/CRSMatrix.h +++ b/MathLib/LinAlg/Sparse/CRSMatrix.h @@ -12,6 +12,11 @@ #include <fstream> #include <iostream> #include <cassert> + +// Base +#include "swap.h" + +// MathLib #include "SparseMatrixBase.h" #include "sparse.h" #include "amuxCRS.h" @@ -113,23 +118,206 @@ public: } } - void eraseEntries (IDX_TYPE n_entries, IDX_TYPE* rows, IDX_TYPE *cols) + /** + * get const access to the row pointer array of CRS matrix + * @return the index array _row_ptr + */ + IDX_TYPE const* getRowPtrArray() const { return _row_ptr; } + + /** + * get const access to the column index array of CRS matrix + * @return the index array _col_idx + */ + IDX_TYPE const* getColIdxArray ()const { return _col_idx; } + + /** + * get the matrix entries within an array of CRS matrix + * @return + */ + FP_TYPE const* getEntryArray() const { return _data; } + + /** + * erase rows and columns from sparse matrix + * @param n_rows_cols number of rows / columns to remove + * @param rows sorted list of rows that should be removed + * @param cols sorted list of columns that should be removed + */ + void eraseEntries (IDX_TYPE n_rows_cols, + IDX_TYPE const*const rows, IDX_TYPE const*const cols) { - // ToDo - //*** determine the number of new entries - unsigned cnt_new_entries(_row_ptr[MatrixBase::_n_rows]); + IDX_TYPE n_cols(MatrixBase::_n_rows); + //*** remove the rows + removeRows(n_rows_cols, rows); + //*** transpose + transpose(n_cols); + //*** remove columns in original means removing rows in the transposed + removeRows(n_rows_cols, cols); + //*** transpose again + transpose(MatrixBase::_n_rows); + //*** apply changes to the column indices + correctColumnIndices(n_rows_cols, cols); + } + + /** + * get the j-th column of the sparse matrix + * @param j the column number that should be returned + * @param column_entries the column entries (have to be allocated + */ + void getColumn(IDX_TYPE j, FP_TYPE* column_entries) const + { + for (IDX_TYPE k(0); k<MatrixBase::_n_rows; k++) { + const IDX_TYPE end_row(_row_ptr[k+1]); + IDX_TYPE i(_row_ptr[k+1]); + while (i<end_row && _col_idx[i] != j) { + i++; + } + if (i==end_row) { + column_entries[k] = 0.0; + } else { + column_entries[k] = _data[i]; + } + } + } + +protected: + void removeRows (IDX_TYPE n_rows_cols, IDX_TYPE const*const rows) + { + //*** determine the number of new rows and the number of entries without the rows + const IDX_TYPE n_new_rows(MatrixBase::_n_rows - n_rows_cols); + IDX_TYPE *row_ptr_new(new IDX_TYPE[n_new_rows+1]); + row_ptr_new[0] = 0; + IDX_TYPE row_cnt (1), erase_row_cnt(0); + for (unsigned k(0); k<MatrixBase::_n_rows; k++) { + if (k != rows[erase_row_cnt]) { + row_ptr_new[row_cnt] = _row_ptr[k+1] - _row_ptr[k]; + row_cnt++; + } else { + erase_row_cnt++; + } + } + + //*** sum up the entries + for (IDX_TYPE k(0); k<n_new_rows; k++) { + row_ptr_new[k+1] = row_ptr_new[k+1] + row_ptr_new[k]; + } + + //*** create new memory for col_idx and data + IDX_TYPE nnz_new(row_ptr_new[n_new_rows]); + IDX_TYPE *col_idx_new (new IDX_TYPE[nnz_new]); + FP_TYPE *data_new (new FP_TYPE[nnz_new]); - //*** create new memory //*** copy the entries - //*** apply changes to attributes + // initialization + IDX_TYPE *row_ptr_new_tmp(new IDX_TYPE[n_new_rows+1]); + for (unsigned k(0); k<=n_new_rows; k++) { + row_ptr_new_tmp[k] = row_ptr_new[k]; + } + erase_row_cnt = 0; + row_cnt = 0; + // copy column index and data entries + for (IDX_TYPE k(0); k<MatrixBase::_n_rows; k++) { + if (k != rows[erase_row_cnt]) { + const IDX_TYPE end (_row_ptr[k+1]); + // walk through row + for (IDX_TYPE j(_row_ptr[k]); j<end; j++) { + col_idx_new[row_ptr_new_tmp[row_cnt]] = _col_idx[j]; + data_new[row_ptr_new_tmp[row_cnt]] = _data[j]; + row_ptr_new_tmp[row_cnt]++; + } + row_cnt++; + } else { + erase_row_cnt++; + } + } + + MatrixBase::_n_rows -= n_rows_cols; + BASELIB::swap (row_ptr_new, _row_ptr); + BASELIB::swap (col_idx_new, _col_idx); + BASELIB::swap (data_new, _data); + + delete [] row_ptr_new; + delete [] col_idx_new; + delete [] data_new; + } + + void transpose (IDX_TYPE n_cols) + { + // create a helper array row_ptr_nnz + IDX_TYPE *row_ptr_nnz(new IDX_TYPE[n_cols+1]); + for (IDX_TYPE k(0); k <= n_cols; k++) { + row_ptr_nnz[k] = 0; + } + + // count entries per row in the transposed matrix + IDX_TYPE nnz(_row_ptr[MatrixBase::_n_rows]); + for (IDX_TYPE k(0); k < nnz; k++) { + row_ptr_nnz[_col_idx[k]]++; + } + + // create row_ptr_trans + IDX_TYPE *row_ptr_trans(new IDX_TYPE[n_cols + 1]); + row_ptr_trans[0] = 0; + for (IDX_TYPE k(0); k < n_cols; k++) { + row_ptr_trans[k+1] = row_ptr_trans[k] + row_ptr_nnz[k]; + } + + // make a copy of row_ptr_trans + for (IDX_TYPE k(0); k <= n_cols; k++) { + row_ptr_nnz[k] = row_ptr_trans[k]; + } + + // create arrays col_idx_trans and data_trans + assert(nnz == row_ptr_trans[n_cols]); + IDX_TYPE *col_idx_trans(new IDX_TYPE[nnz]); + FP_TYPE *data_trans(new FP_TYPE[nnz]); + + // fill arrays col_idx_trans and data_trans + for (IDX_TYPE i(0); i < MatrixBase::_n_rows; i++) { + const IDX_TYPE row_end(_row_ptr[i + 1]); + for (IDX_TYPE j(_row_ptr[i]); j < row_end; j++) { + const IDX_TYPE k(_col_idx[j]); + col_idx_trans[row_ptr_nnz[k]] = i; + data_trans[row_ptr_nnz[k]] = _data[j]; + row_ptr_nnz[k]++; + } + } + + MatrixBase::_n_rows = n_cols; + BASELIB::swap(row_ptr_trans, _row_ptr); + BASELIB::swap(col_idx_trans, _col_idx); + BASELIB::swap(data_trans, _data); + + delete[] row_ptr_nnz; + delete[] row_ptr_trans; + delete[] col_idx_trans; + delete[] data_trans; } - void getColumn(IDX_TYPE col, FP_TYPE* column_entries) + void correctColumnIndices(IDX_TYPE n_rows_cols, IDX_TYPE const*const cols) { - // ToDo + // create the mapping + const IDX_TYPE size(MatrixBase::_n_rows + n_rows_cols); + IDX_TYPE *mapping(new IDX_TYPE[size]); + IDX_TYPE k(0); + for (IDX_TYPE i(0); i < n_rows_cols; i++) { + while (k < cols[i]) { + mapping[k] = k - i; + k++; + } + } + for (IDX_TYPE k(cols[n_rows_cols - 1]); k < size; k++) { + mapping[k] = k - n_rows_cols; + } + + // apply mapping to _col_idx + const IDX_TYPE nnz(_row_ptr[MatrixBase::_n_rows]); + for (IDX_TYPE k(0); k < nnz; k++) { + _col_idx[k] = mapping[_col_idx[k]]; + } + + delete[] mapping; } -protected: IDX_TYPE *_row_ptr; IDX_TYPE *_col_idx; FP_TYPE* _data; diff --git a/MathLib/LinAlg/Sparse/CRSTranspose.h b/MathLib/LinAlg/Sparse/CRSTranspose.h index 6b3eba98604..010a49e5a31 100644 --- a/MathLib/LinAlg/Sparse/CRSTranspose.h +++ b/MathLib/LinAlg/Sparse/CRSTranspose.h @@ -2,17 +2,17 @@ * CRSTranspose.h * * Created on: Sep 27, 2011 - * Author: fischeth + * Author: TF */ #ifndef CRSTRANSPOSE_H_ #define CRSTRANSPOSE_H_ -void CS_transp(unsigned n, double* A, unsigned* jA, unsigned *iA, - double* B, unsigned *jB, unsigned *iB) +void CS_transp(unsigned n, unsigned *iA, unsigned* jA, double* A, + unsigned *iB, unsigned *jB, double* B) { unsigned nnz = iA[n]; - unsigned *inz = new unsigned[n]; + unsigned *inz(new unsigned[n]); for (unsigned i=0; i<n; ++i) inz[i] = 0; diff --git a/MathLib/sparse.h b/MathLib/sparse.h index fa3f6623659..3278ea93c69 100644 --- a/MathLib/sparse.h +++ b/MathLib/sparse.h @@ -4,51 +4,48 @@ #include <iostream> #include <cassert> -extern void CS_write(char*, unsigned, unsigned*, unsigned*, double*); +extern void CS_write(char*, unsigned, unsigned const*, unsigned const*, double const*); extern void CS_read(char*, unsigned&, unsigned*&, unsigned*&, double*&); -template<class T> void -CS_write(std::ostream &os, unsigned n, unsigned* iA, unsigned* jA, T* A) +template<class T> void CS_write(std::ostream &os, unsigned n, unsigned const* iA, unsigned const* jA, T const* A) { - os.write((char*) &n, sizeof(unsigned)); - os.write((char*) iA, (n+1)*sizeof(unsigned)); - os.write((char*) jA, iA[n]*sizeof(unsigned)); - os.write((char*) A, iA[n]*sizeof(T)); + os.write((char*) &n, sizeof(unsigned)); + os.write((char*) iA, (n + 1) * sizeof(unsigned)); + os.write((char*) jA, iA[n] * sizeof(unsigned)); + os.write((char*) A, iA[n] * sizeof(T)); } -template<class T> void -CS_read(std::istream &is, unsigned &n, unsigned* &iA, unsigned* &jA, T* &A) +template<class T> void CS_read(std::istream &is, unsigned &n, unsigned* &iA, unsigned* &jA, T* &A) { - is.read((char*) &n, sizeof(unsigned)); - if (iA != NULL) { - delete [] iA; - delete [] jA; - delete [] A; - } - iA = new unsigned[n+1]; - assert(iA!=NULL); - is.read((char*) iA, (n+1)*sizeof(unsigned)); - - jA = new unsigned[iA[n]]; - assert(jA!=NULL); - is.read((char*) jA, iA[n]*sizeof(unsigned)); - - A = new T[iA[n]]; - assert(A!=NULL); - is.read((char*) A, iA[n]*sizeof(T)); + is.read((char*) &n, sizeof(unsigned)); + if (iA != NULL) { + delete[] iA; + delete[] jA; + delete[] A; + } + iA = new unsigned[n + 1]; + assert(iA != NULL); + is.read((char*) iA, (n + 1) * sizeof(unsigned)); + + jA = new unsigned[iA[n]]; + assert(jA != NULL); + is.read((char*) jA, iA[n] * sizeof(unsigned)); + + A = new T[iA[n]]; + assert(A != NULL); + is.read((char*) A, iA[n] * sizeof(T)); #ifndef NDEBUG - // do simple checks - if (iA[0]!=0) - std::cerr << std::endl - << "CRS matrix: array iA doesn't start with 0" << std::endl; - - unsigned i = 0; - while (i<iA[n] && jA[i]<n) ++i; - if (i<iA[n]) - std::cerr << std::endl - << "CRS matrix: the " << i << "th entry of jA has the value " - << jA[i] << ", which is out of bounds." << std::endl; + // do simple checks + if (iA[0] != 0) std::cerr << std::endl << "CRS matrix: array iA doesn't start with 0" + << std::endl; + + unsigned i = 0; + while (i < iA[n] && jA[i] < n) + ++i; + if (i < iA[n]) std::cerr << std::endl << "CRS matrix: the " << i + << "th entry of jA has the value " << jA[i] << ", which is out of bounds." + << std::endl; #endif } diff --git a/SimpleTests/MatrixTests/CMakeLists.txt b/SimpleTests/MatrixTests/CMakeLists.txt index bda3c0ca41a..50238c4a25c 100644 --- a/SimpleTests/MatrixTests/CMakeLists.txt +++ b/SimpleTests/MatrixTests/CMakeLists.txt @@ -19,6 +19,13 @@ ADD_EXECUTABLE( MatMult ${HEADERS} ) +# Create the executable +ADD_EXECUTABLE( MatTestRemoveRowsCols + MatTestRemoveRowsCols.cpp + ${SOURCES} + ${HEADERS} +) + IF (WIN32) TARGET_LINK_LIBRARIES(MatMult Winmm.lib) ENDIF (WIN32) @@ -28,3 +35,12 @@ TARGET_LINK_LIBRARIES ( MatMult MathLib ) +IF (WIN32) + TARGET_LINK_LIBRARIES(MatTestRemoveRowsCols Winmm.lib) +ENDIF (WIN32) + +TARGET_LINK_LIBRARIES ( MatTestRemoveRowsCols + Base + MathLib +) + diff --git a/SimpleTests/MatrixTests/MatTestRemoveRowsCols.cpp b/SimpleTests/MatrixTests/MatTestRemoveRowsCols.cpp new file mode 100644 index 00000000000..905f1498bf3 --- /dev/null +++ b/SimpleTests/MatrixTests/MatTestRemoveRowsCols.cpp @@ -0,0 +1,71 @@ +/* + * MatTestRemoveRowsCols.cpp + * + * Created on: Nov 8, 2011 + * Author: TF + */ + +#include <fstream> +#include <iostream> + +// Base +#include "RunTimeTimer.h" +#include "CPUTimeTimer.h" + +// MathLib +#include "LinAlg/Sparse/CRSMatrix.h" + +int main(int argc, char *argv[]) +{ + if (argc < 3) { + std::cout << "Usage: " << argv[0] << " input-matrix output-matrix" << std::endl; + return 1; + } + + std::string fname_mat (argv[1]); + bool verbose (true); + + // *** reading matrix in crs format from file + std::ifstream in(fname_mat.c_str(), std::ios::in | std::ios::binary); + double *A(NULL); + unsigned *iA(NULL), *jA(NULL), n; + if (in) { + if (verbose) { + std::cout << "reading matrix from " << fname_mat << " ... " << std::flush; + } + RunTimeTimer timer; + timer.start(); + CS_read(in, n, iA, jA, A); + in.close(); + timer.stop(); + if (verbose) { + std::cout << "ok, " << timer.elapsed() << " s)" << std::endl; + } + } else { + std::cout << "error reading matrix from " << fname_mat << std::endl; + } + unsigned nnz(iA[n]); + if (verbose) { + std::cout << "Parameters read: n=" << n << ", nnz=" << nnz << std::endl; + } + + MathLib::CRSMatrix<double, unsigned> mat (n, iA, jA, A); + + const unsigned n_rows_cols_to_erase(10); + unsigned *rows_to_erase(new unsigned[n_rows_cols_to_erase]); + unsigned *cols_to_erase(new unsigned[n_rows_cols_to_erase]); + + for (unsigned k(0); k<n_rows_cols_to_erase; k++) { + rows_to_erase[k] = k*5; + cols_to_erase[k] = k*5; + } + + mat.eraseEntries(n_rows_cols_to_erase, rows_to_erase, cols_to_erase); + delete[] rows_to_erase; + delete[] cols_to_erase; + + fname_mat = argv[2]; + std::ofstream out (fname_mat.c_str(), std::ios::binary); + CS_write (out, mat.getNRows(), mat.getRowPtrArray(), mat.getColIdxArray(), mat.getEntryArray()); + out.close(); +} -- GitLab