Browse Source

Added conversion routines from/to Eigen Sparse Matrix Format

Added tests for aforementioned conversion routines.
Changed call parameters for sparse/static_sparse_matrix.h
Minor ICL 13.x changes.
tempestpy_adaptions
PBerger 12 years ago
parent
commit
a4f5794419
  1. 6
      resources/3rdparty/eigen/Eigen/src/SparseCore/SparseMatrixBase.h
  2. 4
      resources/3rdparty/stlsoft-1.9.116/include/stlsoft/stlsoft.h
  3. 4
      src/parser/read_tra_file.cpp
  4. 362
      src/sparse/static_sparse_matrix.h
  5. 196
      test/sparse/static_sparse_matrix_test.cpp

6
resources/3rdparty/eigen/Eigen/src/SparseCore/SparseMatrixBase.h

@ -164,7 +164,11 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived>
/** \returns the size of the inner dimension according to the storage order, /** \returns the size of the inner dimension according to the storage order,
* i.e., the number of rows for a columns major matrix, and the number of cols otherwise */ * i.e., the number of rows for a columns major matrix, and the number of cols otherwise */
Index innerSize() const { return (int(Flags)&RowMajorBit) ? this->cols() : this->rows(); } Index innerSize() const { return (int(Flags)&RowMajorBit) ? this->cols() : this->rows(); }
bool isRowMajorMatrix() const {
return (int(Flags)&RowMajorBit);
}
bool isRValue() const { return m_isRValue; } bool isRValue() const { return m_isRValue; }
Derived& markAsRValue() { m_isRValue = true; return derived(); } Derived& markAsRValue() { m_isRValue = true; return derived(); }

4
resources/3rdparty/stlsoft-1.9.116/include/stlsoft/stlsoft.h

@ -554,8 +554,10 @@
# define STLSOFT_COMPILER_VERSION_STRING "Intel C/C++ 11.0" # define STLSOFT_COMPILER_VERSION_STRING "Intel C/C++ 11.0"
# elif (__INTEL_COMPILER >= 1200) && (__INTEL_COMPILER < 1300) # elif (__INTEL_COMPILER >= 1200) && (__INTEL_COMPILER < 1300)
# define STLSOFT_COMPILER_VERSION_STRING "Intel C/C++ 12.x" # define STLSOFT_COMPILER_VERSION_STRING "Intel C/C++ 12.x"
# elif (__INTEL_COMPILER >= 1300) && (__INTEL_COMPILER < 1400)
# define STLSOFT_COMPILER_VERSION_STRING "Intel C/C++ 13.x"
# else /* ? __INTEL_COMPILER */ # else /* ? __INTEL_COMPILER */
# error Only Intel C++ Compiler versions 6.0, 7.0(/7.1), 8.0, 9.0, 10.0, 11.0 and 12.x currently supported by the STLSoft libraries
# error Only Intel C++ Compiler versions 6.0, 7.0(/7.1), 8.0, 9.0, 10.0, 11.0, 12.x and 13.x currently supported by the STLSoft libraries
# endif /* __INTEL_COMPILER */ # endif /* __INTEL_COMPILER */
#elif defined(__MWERKS__) #elif defined(__MWERKS__)

4
src/parser/read_tra_file.cpp

@ -135,12 +135,12 @@ sparse::StaticSparseMatrix<double> * read_tra_file(const char * filename) {
* Memory for diagonal elements is automatically allocated, hence only the number of non-diagonal * Memory for diagonal elements is automatically allocated, hence only the number of non-diagonal
* non-zero elements has to be specified (which is non_zero, computed by make_first_pass) * non-zero elements has to be specified (which is non_zero, computed by make_first_pass)
*/ */
sp = new sparse::StaticSparseMatrix<double>(rows,non_zero);
sp = new sparse::StaticSparseMatrix<double>(rows);
if ( NULL == sp ) { if ( NULL == sp ) {
throw std::bad_alloc(); throw std::bad_alloc();
return NULL; return NULL;
} }
sp->initialize();
sp->initialize(non_zero);
//Reading transitions (one per line) and saving the results in the matrix //Reading transitions (one per line) and saving the results in the matrix
while (NULL != fgets(s, BUFFER_SIZE, p )) { while (NULL != fgets(s, BUFFER_SIZE, p )) {

362
src/sparse/static_sparse_matrix.h

@ -13,6 +13,7 @@
#include "src/exceptions/out_of_range.h" #include "src/exceptions/out_of_range.h"
#include "Eigen/Sparse" #include "Eigen/Sparse"
#include "src/sparse/eigen_sparse_additions.h"
namespace mrmc { namespace mrmc {
@ -46,13 +47,13 @@ class StaticSparseMatrix {
//! Constructor //! Constructor
/*! /*!
\param rows Row-Count and therefore column-count of the symmetric matrix
\param non_zero_entries The exact count of entries that will be submitted through addNextValue *excluding* those on the diagonal (A_{i,j} with i = j)
\param rows Row-Count and therefore column-count of the square matrix
*/ */
StaticSparseMatrix(uint_fast32_t rows, uint_fast32_t non_zero_entries) {
setState(MatrixStatus::UnInitialized);
StaticSparseMatrix(uint_fast32_t rows) {
// Using direct access instead of setState() because of undefined initialization value
// setState() stays in Error should Error be the current value
internal_status = MatrixStatus::UnInitialized;
current_size = 0; current_size = 0;
storage_size = 0;
value_storage = NULL; value_storage = NULL;
diagonal_storage = NULL; diagonal_storage = NULL;
@ -60,7 +61,7 @@ class StaticSparseMatrix {
row_indications = NULL; row_indications = NULL;
row_count = rows; row_count = rows;
non_zero_entry_count = non_zero_entries;
non_zero_entry_count = 0;
//initialize(rows, non_zero_entries); //initialize(rows, non_zero_entries);
} }
@ -85,98 +86,123 @@ class StaticSparseMatrix {
} }
} }
//! Getter for saving matrix entry A_{row,col} to target
/*!
Getter function for the matrix. This function does not check the internal status for errors for performance reasons.
\param row 1-based index of the requested row
\param col 1-based index of the requested column
\param target pointer to where the result will be stored
\return True iff the value was set, false otherwise. On false, 0 will be written to *target.
*/
inline bool getValue(uint_fast32_t row, uint_fast32_t col, T* const target) {
if (row == col) {
// storage is row_count + 1 large for direct access without the -1
*target = diagonal_storage[row];
return true;
}
if ((row > row_count) || (col > row_count) || (row == 0) || (col == 0)) {
throw mrmc::exceptions::out_of_range("mrmc::StaticSparseMatrix::getValue: row or col not in 1 .. rows");
}
uint_fast32_t row_start = row_indications[row - 1];
uint_fast32_t row_end = row_indications[row];
while (row_start < row_end) {
if (column_indications[row_start] == col) {
*target = value_storage[row_start];
return true;
}
if (column_indications[row_start] > col) {
break;
}
row_start++;
}
*target = 0;
return false;
}
//! Mandatory initialization of the matrix
//! Mandatory initialization of the matrix, variant for initialize(), addNextValue() and finalize()
/*! /*!
Mandatory initialization of the matrix, must be called before using any other member function. Mandatory initialization of the matrix, must be called before using any other member function.
This version is to be used together with addNextValue().
For initialization from a Eigen SparseMatrix, use initialize(Eigen::SparseMatrix<T> &).
\param non_zero_entries The exact count of entries that will be submitted through addNextValue *excluding* those on the diagonal (A_{i,j} with i = j)
*/ */
void initialize() {
void initialize(uint_fast32_t non_zero_entries) {
if (internal_status != MatrixStatus::UnInitialized) { if (internal_status != MatrixStatus::UnInitialized) {
triggerErrorState();
pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing invalid state for status flag != 0 (is ", pantheios::integer(internal_status)," - Already initialized?"); pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing invalid state for status flag != 0 (is ", pantheios::integer(internal_status)," - Already initialized?");
throw mrmc::exceptions::invalid_state("StaticSparseMatrix::initialize: Invalid state for status flag != 0 - Already initialized?"); throw mrmc::exceptions::invalid_state("StaticSparseMatrix::initialize: Invalid state for status flag != 0 - Already initialized?");
triggerErrorState();
} else if (row_count == 0) { } else if (row_count == 0) {
triggerErrorState();
pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing invalid_argument for row_count = 0"); pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing invalid_argument for row_count = 0");
throw mrmc::exceptions::invalid_argument("mrmc::StaticSparseMatrix::initialize: Matrix with 0 rows is not reasonable"); throw mrmc::exceptions::invalid_argument("mrmc::StaticSparseMatrix::initialize: Matrix with 0 rows is not reasonable");
} else if (((row_count * row_count) - row_count) < non_zero_entries) {
triggerErrorState(); triggerErrorState();
} else if (((row_count * row_count) - row_count) < non_zero_entry_count) {
pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing invalid_argument: More non-zero entries than entries in target matrix"); pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing invalid_argument: More non-zero entries than entries in target matrix");
throw mrmc::exceptions::invalid_argument("mrmc::StaticSparseMatrix::initialize: More non-zero entries than entries in target matrix"); throw mrmc::exceptions::invalid_argument("mrmc::StaticSparseMatrix::initialize: More non-zero entries than entries in target matrix");
triggerErrorState();
} else { } else {
storage_size = non_zero_entry_count;
non_zero_entry_count = non_zero_entries;
last_row = 0; last_row = 0;
//value_storage = static_cast<T*>(calloc(storage_size, sizeof(*value_storage)));
value_storage = new (std::nothrow) T[storage_size]();
//column_indications = static_cast<uint_fast32_t*>(calloc(storage_size, sizeof(*column_indications)));
column_indications = new (std::nothrow) uint_fast32_t[storage_size]();
//row_indications = static_cast<uint_fast32_t*>(calloc(row_count + 1, sizeof(*row_indications)));
row_indications = new (std::nothrow) uint_fast32_t[row_count + 1]();
// row_count + 1 so that access with 1-based indices can be direct without the overhead of a -1 each time
//diagonal_storage = static_cast<T*>(calloc(row_count + 1, sizeof(*diagonal_storage)));
diagonal_storage = new (std::nothrow) T[row_count + 1]();
if ((value_storage == NULL) || (column_indications == NULL) || (row_indications == NULL) || (diagonal_storage == NULL)) {
if (!prepareInternalStorage()) {
triggerErrorState();
pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing bad_alloc: memory allocation failed"); pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing bad_alloc: memory allocation failed");
throw std::bad_alloc(); throw std::bad_alloc();
triggerErrorState();
} else { } else {
setState(MatrixStatus::Initialized); setState(MatrixStatus::Initialized);
} }
} }
} }
//! Mandatory initialization of the matrix, variant for initialize(), addNextValue() and finalize()
/*!
Mandatory initialization of the matrix, must be called before using any other member function.
This version is to be used for initialization from a Eigen SparseMatrix, use initialize(uint_fast32_t) for addNextValue.
\param eigen_sparse_matrix The Eigen Sparse Matrix to be copied/ initialized from. MUST BE in compressed form!
*/
template<typename _Scalar, int _Options, typename _Index>
void initialize(const Eigen::SparseMatrix<_Scalar, _Options, _Index> &eigen_sparse_matrix) {
if (!eigen_sparse_matrix.isCompressed()) {
triggerErrorState();
pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing invalid_argument: eigen_sparse_matrix is not in Compressed form.");
throw mrmc::exceptions::invalid_argument("StaticSparseMatrix::initialize: Throwing invalid_argument: eigen_sparse_matrix is not in Compressed form.");
}
non_zero_entry_count = getEigenSparseMatrixCorrectNonZeroEntryCount(eigen_sparse_matrix);
last_row = 0;
if (!prepareInternalStorage()) {
triggerErrorState();
pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing bad_alloc: memory allocation failed");
throw std::bad_alloc();
} else {
// easy case, we can simply copy the data
// RowMajor: Easy, ColMajor: Hmm. But how to detect?
const T* valuePtr = eigen_sparse_matrix.valuePtr();
const int_fast32_t* indexPtr = eigen_sparse_matrix.innerIndexPtr();
const int_fast32_t* outerPtr = eigen_sparse_matrix.outerIndexPtr();
const int_fast32_t entryCount = eigen_sparse_matrix.nonZeros();
const int_fast32_t outerCount = eigen_sparse_matrix.outerSize();
if (isEigenRowMajor(eigen_sparse_matrix)) {
// Easy case, all data can be copied with some minor changes.
// We have to separate diagonal entries from others
for (int row = 1; row <= outerCount; ++row) {
for (int col = outerPtr[row - 1]; col < outerPtr[row]; ++col) {
addNextValue(row, indexPtr[col] + 1, valuePtr[col]);
}
}
} else {
// temp copies, anyone?
const int eigen_col_count = eigen_sparse_matrix.cols();
const int eigen_row_count = eigen_sparse_matrix.rows();
// initialise all column-start positions to known lower boundarys
int_fast32_t* positions = new int_fast32_t[eigen_col_count]();
for (int i = 0; i < eigen_col_count; ++i) {
positions[i] = outerPtr[i];
}
int i = 0;
int currentRow = 0;
int currentColumn = 0;
while (i < entryCount) {
if ((positions[currentColumn] < outerPtr[currentColumn + 1]) && (indexPtr[positions[currentColumn]] == currentRow)) {
addNextValue(currentRow + 1, currentColumn + 1, valuePtr[positions[currentColumn]]);
// one more found
++i;
// mark this position as "used"
++positions[currentColumn];
}
// advance to next column
++currentColumn;
if (currentColumn == eigen_col_count) {
currentColumn = 0;
++currentRow;
}
}
}
setState(MatrixStatus::Initialized);
}
}
//! Linear Setter for matrix entry A_{row, col} to value //! Linear Setter for matrix entry A_{row, col} to value
/*! /*!
Linear Setter function for matrix entry A_{row, col} to value. Must be called consecutively for each element in a row in ascending order of columns AND in ascending order of rows. Linear Setter function for matrix entry A_{row, col} to value. Must be called consecutively for each element in a row in ascending order of columns AND in ascending order of rows.
Diagonal entries may be set at any time. Diagonal entries may be set at any time.
*/ */
void addNextValue(const uint_fast32_t row, const uint_fast32_t col, const T value) {
void addNextValue(const uint_fast32_t row, const uint_fast32_t col, const T &value) {
if ((row > row_count) || (col > row_count) || (row == 0) || (col == 0)) { if ((row > row_count) || (col > row_count) || (row == 0) || (col == 0)) {
pantheios::log_ERROR("StaticSparseMatrix::addNextValue: Throwing out_of_range: row or col not in 1 .. rows");
throw mrmc::exceptions::out_of_range("mrmc::StaticSparseMatrix::addNextValue: row or col not in 1 .. rows");
triggerErrorState(); triggerErrorState();
pantheios::log_ERROR("StaticSparseMatrix::addNextValue: Throwing out_of_range: row or col not in 1 .. rows (is ", pantheios::integer(row), " x ", pantheios::integer(col), ", max is ", pantheios::integer(row_count), " x ", pantheios::integer(row_count), ").");
throw mrmc::exceptions::out_of_range("StaticSparseMatrix::addNextValue: row or col not in 1 .. rows");
} }
if (row == col) { if (row == col) {
@ -199,13 +225,13 @@ class StaticSparseMatrix {
void finalize() { void finalize() {
if (!isInitialized()) { if (!isInitialized()) {
triggerErrorState();
pantheios::log_ERROR("StaticSparseMatrix::finalize: Throwing invalid state for internal state not Initialized (is ", pantheios::integer(internal_status)," - Already finalized?"); pantheios::log_ERROR("StaticSparseMatrix::finalize: Throwing invalid state for internal state not Initialized (is ", pantheios::integer(internal_status)," - Already finalized?");
throw mrmc::exceptions::invalid_state("StaticSparseMatrix::finalize: Invalid state for internal state not Initialized - Already finalized?"); throw mrmc::exceptions::invalid_state("StaticSparseMatrix::finalize: Invalid state for internal state not Initialized - Already finalized?");
} else if (current_size != non_zero_entry_count) {
triggerErrorState(); triggerErrorState();
} else if (storage_size != current_size) {
pantheios::log_ERROR("StaticSparseMatrix::finalize: Throwing invalid_state: Wrong call count for addNextValue"); pantheios::log_ERROR("StaticSparseMatrix::finalize: Throwing invalid_state: Wrong call count for addNextValue");
throw mrmc::exceptions::invalid_state("mrmc::StaticSparseMatrix::finalize: Wrong call count for addNextValue");
triggerErrorState();
throw mrmc::exceptions::invalid_state("StaticSparseMatrix::finalize: Wrong call count for addNextValue");
} else { } else {
if (last_row != row_count) { if (last_row != row_count) {
for (uint_fast32_t i = last_row; i < row_count; ++i) { for (uint_fast32_t i = last_row; i < row_count; ++i) {
@ -213,12 +239,52 @@ class StaticSparseMatrix {
} }
} }
row_indications[row_count] = storage_size;
row_indications[row_count] = non_zero_entry_count;
setState(MatrixStatus::ReadReady); setState(MatrixStatus::ReadReady);
} }
} }
//! Getter for saving matrix entry A_{row,col} to target
/*!
Getter function for the matrix. This function does not check the internal status for errors for performance reasons.
\param row 1-based index of the requested row
\param col 1-based index of the requested column
\param target pointer to where the result will be stored
\return True iff the value was set, false otherwise. On false, 0 will be written to *target.
*/
inline bool getValue(uint_fast32_t row, uint_fast32_t col, T* const target) {
if (row == col) {
// storage is row_count + 1 large for direct access without the -1
*target = diagonal_storage[row];
return true;
}
if ((row > row_count) || (col > row_count) || (row == 0) || (col == 0)) {
pantheios::log_ERROR("StaticSparseMatrix::getValue: row or col not in 1 .. rows (is ", pantheios::integer(row), " x ", pantheios::integer(col), ", max is ", pantheios::integer(row_count), " x ", pantheios::integer(row_count), ").");
throw mrmc::exceptions::out_of_range("StaticSparseMatrix::getValue: row or col not in 1 .. rows");
return false;
}
uint_fast32_t row_start = row_indications[row - 1];
uint_fast32_t row_end = row_indications[row];
while (row_start < row_end) {
if (column_indications[row_start] == col) {
*target = value_storage[row_start];
return true;
}
if (column_indications[row_start] > col) {
break;
}
row_start++;
}
*target = 0;
return false;
}
uint_fast32_t getRowCount() const { uint_fast32_t getRowCount() const {
return row_count; return row_count;
} }
@ -243,16 +309,24 @@ class StaticSparseMatrix {
return (internal_status == MatrixStatus::Error); return (internal_status == MatrixStatus::Error);
} }
//! Converts this matrix to an equivalent sparse matrix in Eigens format.
/*!
Exports this sparse matrix to Eigens SparseMatrix format.
Required this matrix to be in the ReadReady state.
@return The Eigen SparseMatrix
*/
Eigen::SparseMatrix<T> toEigenSparseMatrix() { Eigen::SparseMatrix<T> toEigenSparseMatrix() {
Eigen::SparseMatrix<T> mat(row_count, row_count); Eigen::SparseMatrix<T> mat(row_count, row_count);
if (!isReadReady()) { if (!isReadReady()) {
triggerErrorState();
pantheios::log_ERROR("StaticSparseMatrix::toEigenSparseMatrix: Throwing invalid state for internal state not ReadReady (is ", pantheios::integer(internal_status),")."); pantheios::log_ERROR("StaticSparseMatrix::toEigenSparseMatrix: Throwing invalid state for internal state not ReadReady (is ", pantheios::integer(internal_status),").");
throw mrmc::exceptions::invalid_state("StaticSparseMatrix::toEigenSparseMatrix: Invalid state for internal state not ReadReady."); throw mrmc::exceptions::invalid_state("StaticSparseMatrix::toEigenSparseMatrix: Invalid state for internal state not ReadReady.");
triggerErrorState();
} else { } else {
typedef Eigen::Triplet<double> ETd;
std::vector<ETd> tripletList;
typedef Eigen::Triplet<int> IntTriplet;
std::vector<IntTriplet> tripletList;
tripletList.reserve(non_zero_entry_count + row_count); tripletList.reserve(non_zero_entry_count + row_count);
uint_fast32_t row_start; uint_fast32_t row_start;
@ -261,12 +335,12 @@ class StaticSparseMatrix {
row_start = row_indications[row - 1]; row_start = row_indications[row - 1];
row_end = row_indications[row]; row_end = row_indications[row];
while (row_start < row_end) { while (row_start < row_end) {
tripletList.push_back(ETd(row - 1, column_indications[row_start] - 1, value_storage[row_start]));
tripletList.push_back(IntTriplet(row - 1, column_indications[row_start] - 1, value_storage[row_start]));
++row_start; ++row_start;
} }
} }
for (uint_fast32_t i = 1; i <= row_count; ++i) { for (uint_fast32_t i = 1; i <= row_count; ++i) {
tripletList.push_back(ETd(i, i, diagonal_storage[i]));
tripletList.push_back(IntTriplet(i, i, diagonal_storage[i]));
} }
mat.setFromTriplets(tripletList.begin(), tripletList.end()); mat.setFromTriplets(tripletList.begin(), tripletList.end());
@ -276,8 +350,72 @@ class StaticSparseMatrix {
return mat; return mat;
} }
//! Alternative way to initialize this matrix instead of using initialize(), addNextValue() and finalize().
/*!
Initializes the matrix from the given eigen_sparse_matrix. Replaces the calls to initialize(), addNextValue() and finalize().
Requires eigen_sparse_matrix to have at most a size of rows x rows and not more than non_zero_entries on non-diagonal fields.
To calculate the non-zero-entry count on only non-diagonal fields, you may use getEigenSparseMatrixCorrectNonZeroEntryCount().
In most cases, it may be easier to use the alternative constructor StaticSparseMatrix(const Eigen::SparseMatrix<T> eigen_sparse_matrix).
@param eigen_sparse_matrix the Eigen Sparse Matrix from which this matrix should be initalized.
@see getEigenSparseMatrixCorrectNonZeroEntryCount()
@see StaticSparseMatrix(const Eigen::SparseMatrix<T>)
*/
bool fromEigenSparseMatrix(const Eigen::SparseMatrix<T> eigen_sparse_matrix) {
if (getState() != MatrixStatus::UnInitialized) {
triggerErrorState();
pantheios::log_ERROR("StaticSparseMatrix::fromEigenSparseMatrix: Throwing invalid state for internal state not UnInitialized (is ", pantheios::integer(internal_status),").");
throw mrmc::exceptions::invalid_state("StaticSparseMatrix::fromEigenSparseMatrix: Invalid state for internal state not UnInitialized.");
return false;
}
int_fast32_t eigen_row_count = eigen_sparse_matrix.rows();
int_fast32_t eigen_col_count = eigen_sparse_matrix.cols();
if ((eigen_row_count > row_count) || (eigen_col_count > row_count)) {
triggerErrorState();
pantheios::log_ERROR("StaticSparseMatrix::fromEigenSparseMatrix: Throwing invalid argument for eigenSparseMatrix is too big to fit (is ", pantheios::integer(eigen_row_count)," x ", pantheios::integer(eigen_col_count), ", max is ", pantheios::integer(row_count)," x ", pantheios::integer(row_count), ").");
throw mrmc::exceptions::invalid_argument("StaticSparseMatrix::fromEigenSparseMatrix: Invalid argument for eigenSparseMatrix is too big to fit.");
return false;
}
uint_fast32_t eigen_non_zero_entries = mrmc::sparse::getEigenSparseMatrixCorrectNonZeroEntryCount(eigen_sparse_matrix);
if (eigen_non_zero_entries > non_zero_entry_count) {
triggerErrorState();
pantheios::log_ERROR("StaticSparseMatrix::fromEigenSparseMatrix: Throwing invalid argument for eigenSparseMatrix has too many non-zero entries to fit (is ", pantheios::integer(eigen_non_zero_entries),", max is ", pantheios::integer(non_zero_entry_count),").");
throw mrmc::exceptions::invalid_argument("StaticSparseMatrix::fromEigenSparseMatrix: Invalid argument for eigenSparseMatrix has too many non-zero entries to fit.");
return false;
}
// make compressed
eigen_sparse_matrix.makeCompressed();
if (eigen_sparse_matrix.IsRowMajor()) {
// inner Index
int_fast32_t* eigenInnerIndex = eigen_sparse_matrix.innerIndexPtr();
T* eigenValuePtr = eigen_sparse_matrix.valuePtr();
}
for (int k = 0; k < tempESM.outerSize(); ++k) {
for (SparseMatrix<T>::InnerIterator it(tempESM, k); it; ++it) {
if (eigen_non_zero_entries >= non_zero_entry_count) {
// too many non zero entries for us.
}
addNextValue(it.row() - 1, it.col() - 1, it.value());
if (it.row() != it.col()) {
++eigen_non_zero_entries;
}
/*it.value();
it.row(); // row index
it.col(); // col index (here it is equal to k)
it.index(); // inner index, here it is equal to it.row()*/
}
}
}
private: private:
uint_fast32_t storage_size;
uint_fast32_t current_size; uint_fast32_t current_size;
uint_fast32_t row_count; uint_fast32_t row_count;
@ -309,6 +447,74 @@ class StaticSparseMatrix {
void setState(const MatrixStatus new_state) { void setState(const MatrixStatus new_state) {
internal_status = (internal_status == MatrixStatus::Error) ? internal_status : new_state; internal_status = (internal_status == MatrixStatus::Error) ? internal_status : new_state;
} }
/*!
Prepares the internal CSR storage.
Requires non_zero_entry_count and row_count to be set.
@return true on success, false otherwise (allocation failed).
*/
bool prepareInternalStorage() {
value_storage = new (std::nothrow) T[non_zero_entry_count]();
column_indications = new (std::nothrow) uint_fast32_t[non_zero_entry_count]();
row_indications = new (std::nothrow) uint_fast32_t[row_count + 1]();
// row_count + 1 so that access with 1-based indices can be direct without the overhead of a -1 each time
diagonal_storage = new (std::nothrow) T[row_count + 1]();
return ((value_storage != NULL) && (column_indications != NULL) && (row_indications != NULL) && (diagonal_storage != NULL));
}
template <typename _Scalar, typename _Index>
bool isEigenRowMajor(Eigen::SparseMatrix<_Scalar, Eigen::RowMajor, _Index>) {
return true;
}
template <typename _Scalar, typename _Index>
bool isEigenRowMajor(Eigen::SparseMatrix<_Scalar, Eigen::ColMajor, _Index>) {
return false;
}
template<typename _Scalar, int _Options, typename _Index>
uint_fast32_t getEigenSparseMatrixCorrectNonZeroEntryCount(const Eigen::SparseMatrix<_Scalar, _Options, _Index> &eigen_sparse_matrix) {
const int_fast32_t* indexPtr = eigen_sparse_matrix.innerIndexPtr();
const int_fast32_t* outerPtr = eigen_sparse_matrix.outerIndexPtr();
const int_fast32_t entryCount = eigen_sparse_matrix.nonZeros();
const int_fast32_t outerCount = eigen_sparse_matrix.outerSize();
uint_fast32_t diag_non_zeros = 0;
// for RowMajor, row is the current Row and col the column
// for ColMajor, row is the current Col and col the row
int_fast32_t innerStart = 0;
int_fast32_t innerEnd = 0;
int_fast32_t innerMid = 0;
for (int row = 0; row < outerCount; ++row) {
innerStart = outerPtr[row];
innerEnd = outerPtr[row + 1] - 1;
// Now with super fancy binary search, deferred equality detection
while (innerStart < innerEnd) {
innerMid = innerStart + ((innerEnd - innerStart) / 2);
if (indexPtr[innerMid] < row) {
innerStart = innerMid + 1;
} else {
innerEnd = innerMid;
}
}
if ((innerStart == innerEnd) && (indexPtr[innerStart] == row)) {
// found a diagonal entry
++diag_non_zeros;
}
}
return static_cast<uint_fast32_t>(entryCount - diag_non_zeros);
}
}; };
} // namespace sparse } // namespace sparse

196
test/sparse/static_sparse_matrix_test.cpp

@ -3,52 +3,70 @@
#include "src/exceptions/invalid_argument.h" #include "src/exceptions/invalid_argument.h"
TEST(StaticSparseMatrixTest, ZeroRowsTest) { TEST(StaticSparseMatrixTest, ZeroRowsTest) {
mrmc::sparse::StaticSparseMatrix<int> *ssm = new mrmc::sparse::StaticSparseMatrix<int>(0, 50);
mrmc::sparse::StaticSparseMatrix<int> *ssm = new mrmc::sparse::StaticSparseMatrix<int>(0);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::UnInitialized);
ASSERT_THROW(ssm->initialize(), mrmc::exceptions::invalid_argument);
ASSERT_THROW(ssm->initialize(50), mrmc::exceptions::invalid_argument);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::Error);
delete ssm; delete ssm;
} }
TEST(StaticSparseMatrixTest, TooManyEntriesTest) { TEST(StaticSparseMatrixTest, TooManyEntriesTest) {
mrmc::sparse::StaticSparseMatrix<int> *ssm = new mrmc::sparse::StaticSparseMatrix<int>(2, 10);
mrmc::sparse::StaticSparseMatrix<int> *ssm = new mrmc::sparse::StaticSparseMatrix<int>(2);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::UnInitialized);
ASSERT_THROW(ssm->initialize(), mrmc::exceptions::invalid_argument);
ASSERT_THROW(ssm->initialize(10), mrmc::exceptions::invalid_argument);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::Error);
delete ssm; delete ssm;
} }
TEST(StaticSparseMatrixTest, addNextValueTest) { TEST(StaticSparseMatrixTest, addNextValueTest) {
mrmc::sparse::StaticSparseMatrix<int> *ssm = new mrmc::sparse::StaticSparseMatrix<int>(5, 1);
mrmc::sparse::StaticSparseMatrix<int> *ssm = new mrmc::sparse::StaticSparseMatrix<int>(5);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::UnInitialized);
ASSERT_NO_THROW(ssm->initialize());
ASSERT_NO_THROW(ssm->initialize(1));
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::Initialized);
ASSERT_THROW(ssm->addNextValue(0, 1, 1), mrmc::exceptions::out_of_range); ASSERT_THROW(ssm->addNextValue(0, 1, 1), mrmc::exceptions::out_of_range);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::Error);
ASSERT_THROW(ssm->addNextValue(1, 0, 1), mrmc::exceptions::out_of_range); ASSERT_THROW(ssm->addNextValue(1, 0, 1), mrmc::exceptions::out_of_range);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::Error);
ASSERT_THROW(ssm->addNextValue(6, 1, 1), mrmc::exceptions::out_of_range); ASSERT_THROW(ssm->addNextValue(6, 1, 1), mrmc::exceptions::out_of_range);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::Error);
ASSERT_THROW(ssm->addNextValue(1, 6, 1), mrmc::exceptions::out_of_range); ASSERT_THROW(ssm->addNextValue(1, 6, 1), mrmc::exceptions::out_of_range);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::Error);
delete ssm; delete ssm;
} }
TEST(StaticSparseMatrixTest, finalizeTest) { TEST(StaticSparseMatrixTest, finalizeTest) {
mrmc::sparse::StaticSparseMatrix<int> *ssm = new mrmc::sparse::StaticSparseMatrix<int>(5, 5);
mrmc::sparse::StaticSparseMatrix<int> *ssm = new mrmc::sparse::StaticSparseMatrix<int>(5);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::UnInitialized);
ASSERT_NO_THROW(ssm->initialize());
ASSERT_NO_THROW(ssm->initialize(5));
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::Initialized);
ASSERT_NO_THROW(ssm->addNextValue(1, 2, 1)); ASSERT_NO_THROW(ssm->addNextValue(1, 2, 1));
ASSERT_NO_THROW(ssm->addNextValue(1, 3, 1)); ASSERT_NO_THROW(ssm->addNextValue(1, 3, 1));
ASSERT_NO_THROW(ssm->addNextValue(1, 4, 1)); ASSERT_NO_THROW(ssm->addNextValue(1, 4, 1));
ASSERT_NO_THROW(ssm->addNextValue(1, 5, 1)); ASSERT_NO_THROW(ssm->addNextValue(1, 5, 1));
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::Initialized);
ASSERT_THROW(ssm->finalize(), mrmc::exceptions::invalid_state); ASSERT_THROW(ssm->finalize(), mrmc::exceptions::invalid_state);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::Error);
delete ssm; delete ssm;
} }
TEST(StaticSparseMatrixTest, Test) { TEST(StaticSparseMatrixTest, Test) {
// 25 rows, 50 non zero entries // 25 rows, 50 non zero entries
mrmc::sparse::StaticSparseMatrix<int> *ssm = new mrmc::sparse::StaticSparseMatrix<int>(25, 50);
mrmc::sparse::StaticSparseMatrix<int> *ssm = new mrmc::sparse::StaticSparseMatrix<int>(25);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::UnInitialized);
int values[50] = { int values[50] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
@ -76,13 +94,16 @@ TEST(StaticSparseMatrixTest, Test) {
14, 15, 16, 17, 18, 19, 20, 21, 22, 23 /* second to last row */ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 /* second to last row */
}; };
ASSERT_NO_THROW(ssm->initialize());
ASSERT_NO_THROW(ssm->initialize(50));
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::Initialized);
for (int i = 0; i < 50; ++i) { for (int i = 0; i < 50; ++i) {
ASSERT_NO_THROW(ssm->addNextValue(position_row[i], position_col[i], values[i])); ASSERT_NO_THROW(ssm->addNextValue(position_row[i], position_col[i], values[i]));
} }
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::Initialized);
ASSERT_NO_THROW(ssm->finalize()); ASSERT_NO_THROW(ssm->finalize());
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::ReadReady);
int target; int target;
for (int i = 0; i < 50; ++i) { for (int i = 0; i < 50; ++i) {
@ -103,6 +124,161 @@ TEST(StaticSparseMatrixTest, Test) {
ASSERT_EQ(0, target); ASSERT_EQ(0, target);
} }
} }
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::ReadReady);
delete ssm; delete ssm;
} }
TEST(StaticSparseMatrixTest, ConversionFromDenseEigen_ColMajor_SparseMatrixTest) {
// 10 rows, 100 non zero entries
mrmc::sparse::StaticSparseMatrix<int> *ssm = new mrmc::sparse::StaticSparseMatrix<int>(10);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::UnInitialized);
Eigen::SparseMatrix<int> esm(10, 10);
for (int row = 0; row < 10; ++row) {
for (int col = 0; col < 10; ++col) {
esm.insert(row, col) = row * 10 + col;
}
}
// make compressed, important for initialize()
esm.makeCompressed();
ASSERT_NO_THROW(ssm->initialize(esm));
ASSERT_NO_THROW(ssm->finalize());
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::ReadReady);
int target = -1;
for (int row = 1; row <= 10; ++row) {
for (int col = 1; col <= 10; ++col) {
ASSERT_TRUE(ssm->getValue(row, col, &target));
ASSERT_EQ(target, (row - 1) * 10 + col - 1);
}
}
}
TEST(StaticSparseMatrixTest, ConversionFromDenseEigen_RowMajor_SparseMatrixTest) {
// 10 rows, 100 non zero entries
mrmc::sparse::StaticSparseMatrix<int> *ssm = new mrmc::sparse::StaticSparseMatrix<int>(10);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::UnInitialized);
Eigen::SparseMatrix<int, Eigen::RowMajor> esm(10, 10);
for (int row = 0; row < 10; ++row) {
for (int col = 0; col < 10; ++col) {
esm.insert(row, col) = row * 10 + col;
}
}
// make compressed, important for initialize()
esm.makeCompressed();
ASSERT_NO_THROW(ssm->initialize(esm));
ASSERT_NO_THROW(ssm->finalize());
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::ReadReady);
int target = -1;
for (int row = 1; row <= 10; ++row) {
for (int col = 1; col <= 10; ++col) {
ASSERT_TRUE(ssm->getValue(row, col, &target));
ASSERT_EQ(target, (row - 1) * 10 + col - 1);
}
}
}
TEST(StaticSparseMatrixTest, ConversionFromSparseEigen_ColMajor_SparseMatrixTest) {
// 10 rows, 15 non zero entries
mrmc::sparse::StaticSparseMatrix<int> *ssm = new mrmc::sparse::StaticSparseMatrix<int>(10);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::UnInitialized);
Eigen::SparseMatrix<int> esm(10, 10);
typedef Eigen::Triplet<int> IntTriplet;
std::vector<IntTriplet> tripletList;
tripletList.reserve(15);
tripletList.push_back(IntTriplet(1, 0, 0));
tripletList.push_back(IntTriplet(1, 1, 1));
tripletList.push_back(IntTriplet(1, 2, 2));
tripletList.push_back(IntTriplet(1, 3, 3));
tripletList.push_back(IntTriplet(1, 4, 4));
tripletList.push_back(IntTriplet(1, 5, 5));
tripletList.push_back(IntTriplet(1, 6, 6));
tripletList.push_back(IntTriplet(1, 7, 7));
tripletList.push_back(IntTriplet(1, 8, 8));
tripletList.push_back(IntTriplet(1, 9, 9));
tripletList.push_back(IntTriplet(4, 3, 10));
tripletList.push_back(IntTriplet(4, 6, 11));
tripletList.push_back(IntTriplet(4, 9, 12));
tripletList.push_back(IntTriplet(6, 0, 13));
tripletList.push_back(IntTriplet(8, 9, 14));
esm.setFromTriplets(tripletList.begin(), tripletList.end());
// make compressed, important for initialize()
esm.makeCompressed();
ASSERT_NO_THROW(ssm->initialize(esm));
ASSERT_NO_THROW(ssm->finalize());
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::ReadReady);
int target = -1;
for (auto &coeff: tripletList) {
ASSERT_TRUE(ssm->getValue(coeff.row() + 1, coeff.col() + 1, &target));
ASSERT_EQ(target, coeff.value());
}
}
TEST(StaticSparseMatrixTest, ConversionFromSparseEigen_RowMajor_SparseMatrixTest) {
// 10 rows, 15 non zero entries
mrmc::sparse::StaticSparseMatrix<int> *ssm = new mrmc::sparse::StaticSparseMatrix<int>(10);
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::UnInitialized);
Eigen::SparseMatrix<int, Eigen::RowMajor> esm(10, 10);
typedef Eigen::Triplet<int> IntTriplet;
std::vector<IntTriplet> tripletList;
tripletList.reserve(15);
tripletList.push_back(IntTriplet(1, 0, 0));
tripletList.push_back(IntTriplet(1, 1, 1));
tripletList.push_back(IntTriplet(1, 2, 2));
tripletList.push_back(IntTriplet(1, 3, 3));
tripletList.push_back(IntTriplet(1, 4, 4));
tripletList.push_back(IntTriplet(1, 5, 5));
tripletList.push_back(IntTriplet(1, 6, 6));
tripletList.push_back(IntTriplet(1, 7, 7));
tripletList.push_back(IntTriplet(1, 8, 8));
tripletList.push_back(IntTriplet(1, 9, 9));
tripletList.push_back(IntTriplet(4, 3, 10));
tripletList.push_back(IntTriplet(4, 6, 11));
tripletList.push_back(IntTriplet(4, 9, 12));
tripletList.push_back(IntTriplet(6, 0, 13));
tripletList.push_back(IntTriplet(8, 9, 14));
esm.setFromTriplets(tripletList.begin(), tripletList.end());
// make compressed, important for initialize()
esm.makeCompressed();
ASSERT_NO_THROW(ssm->initialize(esm));
ASSERT_NO_THROW(ssm->finalize());
ASSERT_EQ(ssm->getState(), mrmc::sparse::StaticSparseMatrix<int>::MatrixStatus::ReadReady);
int target = -1;
for (auto &coeff: tripletList) {
ASSERT_TRUE(ssm->getValue(coeff.row() + 1, coeff.col() + 1, &target));
ASSERT_EQ(target, coeff.value());
}
}
Loading…
Cancel
Save