|
|
@ -5,6 +5,7 @@ |
|
|
|
#include <new> |
|
|
|
#include <algorithm> |
|
|
|
#include <iostream> |
|
|
|
#include <iterator> |
|
|
|
#include "boost/integer/integer_mask.hpp" |
|
|
|
|
|
|
|
#include "src/exceptions/InvalidStateException.h" |
|
|
@ -31,8 +32,7 @@ namespace storm { |
|
|
|
namespace storage { |
|
|
|
|
|
|
|
/*! |
|
|
|
* A sparse matrix class with a constant number of non-zero entries on the non-diagonal fields |
|
|
|
* and a separate dense storage for the diagonal elements. |
|
|
|
* A sparse matrix class with a constant number of non-zero entries. |
|
|
|
* NOTE: Addressing *is* zero-based, so the valid range for getValue and addNextValue is 0..(rows - 1) |
|
|
|
* where rows is the first argument to the constructor. |
|
|
|
*/ |
|
|
@ -73,9 +73,25 @@ public: |
|
|
|
* Constructs a sparse matrix object with the given number of rows. |
|
|
|
* @param rows The number of rows of the matrix |
|
|
|
*/ |
|
|
|
SquareSparseMatrix(uint_fast64_t rows) |
|
|
|
: rowCount(rows), nonZeroEntryCount(0), valueStorage(nullptr), |
|
|
|
diagonalStorage(nullptr),columnIndications(nullptr), rowIndications(nullptr), |
|
|
|
SquareSparseMatrix(uint_fast64_t rows, uint_fast64_t cols) |
|
|
|
: rowCount(rows), colCount(cols), nonZeroEntryCount(0), |
|
|
|
internalStatus(MatrixStatus::UnInitialized), currentSize(0), lastRow(0) { } |
|
|
|
|
|
|
|
/* Sadly, Delegate Constructors are not yet available with MSVC2012 |
|
|
|
//! Constructor |
|
|
|
/*! |
|
|
|
* Constructs a square sparse matrix object with the given number rows |
|
|
|
* @param size The number of rows and cols in the matrix |
|
|
|
*/ /* |
|
|
|
SquareSparseMatrix(uint_fast64_t size) : SquareSparseMatrix(size, size) { } |
|
|
|
*/ |
|
|
|
|
|
|
|
//! Constructor |
|
|
|
/*! |
|
|
|
* Constructs a square sparse matrix object with the given number rows |
|
|
|
* @param size The number of rows and cols in the matrix |
|
|
|
*/ |
|
|
|
SquareSparseMatrix(uint_fast64_t size) : rowCount(size), colCount(size), nonZeroEntryCount(0), |
|
|
|
internalStatus(MatrixStatus::UnInitialized), currentSize(0), lastRow(0) { } |
|
|
|
|
|
|
|
//! Copy Constructor |
|
|
@ -84,7 +100,7 @@ public: |
|
|
|
* @param ssm A reference to the matrix to be copied. |
|
|
|
*/ |
|
|
|
SquareSparseMatrix(const SquareSparseMatrix<T> &ssm) |
|
|
|
: rowCount(ssm.rowCount), nonZeroEntryCount(ssm.nonZeroEntryCount), |
|
|
|
: rowCount(ssm.rowCount), colCount(ssm.colCount), nonZeroEntryCount(ssm.nonZeroEntryCount), |
|
|
|
internalStatus(ssm.internalStatus), currentSize(ssm.currentSize), lastRow(ssm.lastRow) { |
|
|
|
LOG4CPLUS_WARN(logger, "Invoking copy constructor."); |
|
|
|
// Check whether copying the matrix is safe. |
|
|
@ -98,24 +114,12 @@ public: |
|
|
|
LOG4CPLUS_ERROR(logger, "Unable to allocate internal storage."); |
|
|
|
throw std::bad_alloc(); |
|
|
|
} else { |
|
|
|
// Now that all storages have been prepared, copy over all |
|
|
|
// elements. Start by copying the elements of type value and |
|
|
|
// copy them seperately in order to invoke copy their copy |
|
|
|
// constructor. This may not be necessary, but it is safer to |
|
|
|
// do so in any case. |
|
|
|
for (uint_fast64_t i = 0; i < nonZeroEntryCount; ++i) { |
|
|
|
// use T() to force use of the copy constructor for complex T types |
|
|
|
valueStorage[i] = T(ssm.valueStorage[i]); |
|
|
|
} |
|
|
|
for (uint_fast64_t i = 0; i < rowCount; ++i) { |
|
|
|
// use T() to force use of the copy constructor for complex T types |
|
|
|
diagonalStorage[i] = T(ssm.diagonalStorage[i]); |
|
|
|
} |
|
|
|
std::copy(ssm.valueStorage.begin(), ssm.valueStorage.end(), std::back_inserter(valueStorage)); |
|
|
|
|
|
|
|
// The elements that are not of the value type but rather the |
|
|
|
// index type may be copied directly. |
|
|
|
std::copy(ssm.columnIndications, ssm.columnIndications + nonZeroEntryCount, columnIndications); |
|
|
|
std::copy(ssm.rowIndications, ssm.rowIndications + rowCount + 1, rowIndications); |
|
|
|
std::copy(ssm.columnIndications.begin(), ssm.columnIndications.end(), std::back_inserter(columnIndications)); |
|
|
|
std::copy(ssm.rowIndications.begin(), ssm.rowIndications.end(), std::back_inserter(rowIndications)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -126,18 +130,9 @@ public: |
|
|
|
*/ |
|
|
|
~SquareSparseMatrix() { |
|
|
|
setState(MatrixStatus::UnInitialized); |
|
|
|
if (valueStorage != nullptr) { |
|
|
|
delete[] valueStorage; |
|
|
|
} |
|
|
|
if (columnIndications != nullptr) { |
|
|
|
delete[] columnIndications; |
|
|
|
} |
|
|
|
if (rowIndications != nullptr) { |
|
|
|
delete[] rowIndications; |
|
|
|
} |
|
|
|
if (diagonalStorage != nullptr) { |
|
|
|
delete[] diagonalStorage; |
|
|
|
} |
|
|
|
valueStorage.resize(0); |
|
|
|
columnIndications.resize(0); |
|
|
|
rowIndications.resize(0); |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
@ -155,11 +150,11 @@ public: |
|
|
|
triggerErrorState(); |
|
|
|
LOG4CPLUS_ERROR(logger, "Trying to initialize matrix that is not uninitialized."); |
|
|
|
throw storm::exceptions::InvalidStateException("Trying to initialize matrix that is not uninitialized."); |
|
|
|
} else if (rowCount == 0) { |
|
|
|
} else if ((rowCount == 0) || (colCount == 0)) { |
|
|
|
triggerErrorState(); |
|
|
|
LOG4CPLUS_ERROR(logger, "Trying to create initialize a matrix with 0 rows."); |
|
|
|
throw storm::exceptions::InvalidArgumentException("Trying to create initialize a matrix with 0 rows."); |
|
|
|
} else if (((rowCount * rowCount) - rowCount) < nonZeroEntries) { |
|
|
|
LOG4CPLUS_ERROR(logger, "Trying to create initialize a matrix with 0 rows or 0 columns."); |
|
|
|
throw storm::exceptions::InvalidArgumentException("Trying to create initialize a matrix with 0 rows or 0 columns."); |
|
|
|
} else if ((rowCount * colCount) < nonZeroEntries) { |
|
|
|
triggerErrorState(); |
|
|
|
LOG4CPLUS_ERROR(logger, "Trying to initialize a matrix with more non-zero entries than there can be."); |
|
|
|
throw storm::exceptions::InvalidArgumentException("Trying to initialize a matrix with more non-zero entries than there can be."); |
|
|
@ -196,37 +191,72 @@ public: |
|
|
|
throw storm::exceptions::InvalidArgumentException("Trying to initialize from an Eigen matrix that is not in compressed form."); |
|
|
|
} |
|
|
|
|
|
|
|
// Compute the actual (i.e. non-diagonal) number of non-zero entries. |
|
|
|
nonZeroEntryCount = getEigenSparseMatrixCorrectNonZeroEntryCount(eigenSparseMatrix); |
|
|
|
if (eigenSparseMatrix.rows() > this->rowCount) { |
|
|
|
triggerErrorState(); |
|
|
|
LOG4CPLUS_ERROR(logger, "Trying to initialize from an Eigen matrix that has more rows than the target matrix."); |
|
|
|
throw storm::exceptions::InvalidArgumentException("Trying to initialize from an Eigen matrix that has more rows than the target matrix."); |
|
|
|
} |
|
|
|
if (eigenSparseMatrix.cols() > this->colCount) { |
|
|
|
triggerErrorState(); |
|
|
|
LOG4CPLUS_ERROR(logger, "Trying to initialize from an Eigen matrix that has more columns than the target matrix."); |
|
|
|
throw storm::exceptions::InvalidArgumentException("Trying to initialize from an Eigen matrix that has more columns than the target matrix."); |
|
|
|
} |
|
|
|
|
|
|
|
const _Index entryCount = eigenSparseMatrix.nonZeros(); |
|
|
|
nonZeroEntryCount = entryCount; |
|
|
|
lastRow = 0; |
|
|
|
|
|
|
|
// Try to prepare the internal storage and throw an error in case of |
|
|
|
// failure. |
|
|
|
if (!prepareInternalStorage()) { |
|
|
|
triggerErrorState(); |
|
|
|
LOG4CPLUS_ERROR(logger, "Unable to allocate internal storage."); |
|
|
|
throw std::bad_alloc(); |
|
|
|
} else { |
|
|
|
// Get necessary pointers to the contents of the Eigen matrix. |
|
|
|
const T* valuePtr = eigenSparseMatrix.valuePtr(); |
|
|
|
const _Index* indexPtr = eigenSparseMatrix.innerIndexPtr(); |
|
|
|
const _Index* outerPtr = eigenSparseMatrix.outerIndexPtr(); |
|
|
|
|
|
|
|
// If the given matrix is in RowMajor format, copying can simply |
|
|
|
// be done by adding all values in order. |
|
|
|
// Direct copying is, however, prevented because we have to |
|
|
|
// separate the diagonal entries from others. |
|
|
|
if (isEigenRowMajor(eigenSparseMatrix)) { |
|
|
|
// Because of the RowMajor format outerSize evaluates to the |
|
|
|
// number of rows. |
|
|
|
const _Index rowCount = eigenSparseMatrix.outerSize(); |
|
|
|
for (_Index row = 0; row < rowCount; ++row) { |
|
|
|
for (_Index col = outerPtr[row]; col < outerPtr[row + 1]; ++col) { |
|
|
|
addNextValue(row, indexPtr[col], valuePtr[col]); |
|
|
|
} |
|
|
|
|
|
|
|
// Get necessary pointers to the contents of the Eigen matrix. |
|
|
|
const T* valuePtr = eigenSparseMatrix.valuePtr(); |
|
|
|
const _Index* indexPtr = eigenSparseMatrix.innerIndexPtr(); |
|
|
|
const _Index* outerPtr = eigenSparseMatrix.outerIndexPtr(); |
|
|
|
|
|
|
|
// If the given matrix is in RowMajor format, copying can simply |
|
|
|
// be done by adding all values in order. |
|
|
|
// Direct copying is, however, prevented because we have to |
|
|
|
// separate the diagonal entries from others. |
|
|
|
if (isEigenRowMajor(eigenSparseMatrix)) { |
|
|
|
// Because of the RowMajor format outerSize evaluates to the |
|
|
|
// number of rows. |
|
|
|
if (!prepareInternalStorage(false)) { |
|
|
|
triggerErrorState(); |
|
|
|
LOG4CPLUS_ERROR(logger, "Unable to allocate internal storage."); |
|
|
|
throw std::bad_alloc(); |
|
|
|
} else { |
|
|
|
if ((eigenSparseMatrix.innerSize() > nonZeroEntryCount) || (entryCount > nonZeroEntryCount)) { |
|
|
|
triggerErrorState(); |
|
|
|
LOG4CPLUS_ERROR(logger, "Invalid internal composition of Eigen Sparse Matrix"); |
|
|
|
throw storm::exceptions::InvalidArgumentException("Invalid internal composition of Eigen Sparse Matrix"); |
|
|
|
} |
|
|
|
std::vector<uint_fast64_t> eigenColumnTemp; |
|
|
|
std::vector<uint_fast64_t> eigenRowTemp; |
|
|
|
std::vector<T> eigenValueTemp; |
|
|
|
uint_fast64_t outerSize = eigenSparseMatrix.outerSize() + 1; |
|
|
|
|
|
|
|
for (uint_fast64_t i = 0; i < entryCount; ++i) { |
|
|
|
eigenColumnTemp.push_back(indexPtr[i]); |
|
|
|
eigenValueTemp.push_back(valuePtr[i]); |
|
|
|
} |
|
|
|
for (uint_fast64_t i = 0; i < outerSize; ++i) { |
|
|
|
eigenRowTemp.push_back(outerPtr[i]); |
|
|
|
} |
|
|
|
|
|
|
|
std::copy(eigenRowTemp.begin(), eigenRowTemp.end(), std::back_inserter(this->rowIndications)); |
|
|
|
std::copy(eigenColumnTemp.begin(), eigenColumnTemp.end(), std::back_inserter(this->columnIndications)); |
|
|
|
std::copy(eigenValueTemp.begin(), eigenValueTemp.end(), std::back_inserter(this->valueStorage)); |
|
|
|
|
|
|
|
currentSize = entryCount; |
|
|
|
lastRow = rowCount; |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (!prepareInternalStorage()) { |
|
|
|
triggerErrorState(); |
|
|
|
LOG4CPLUS_ERROR(logger, "Unable to allocate internal storage."); |
|
|
|
throw std::bad_alloc(); |
|
|
|
} else { |
|
|
|
const _Index entryCount = eigenSparseMatrix.nonZeros(); |
|
|
|
// Because of the ColMajor format outerSize evaluates to the |
|
|
|
// number of columns. |
|
|
|
const _Index colCount = eigenSparseMatrix.outerSize(); |
|
|
@ -250,8 +280,7 @@ public: |
|
|
|
// add it in case it is also in the current row. |
|
|
|
if ((positions[currentColumn] < outerPtr[currentColumn + 1]) |
|
|
|
&& (indexPtr[positions[currentColumn]] == currentRow)) { |
|
|
|
addNextValue(currentRow, currentColumn, |
|
|
|
valuePtr[positions[currentColumn]]); |
|
|
|
addNextValue(currentRow, currentColumn, valuePtr[positions[currentColumn]]); |
|
|
|
// Remember that we found one more non-zero element. |
|
|
|
++i; |
|
|
|
// Mark this position as "used". |
|
|
@ -268,8 +297,8 @@ public: |
|
|
|
} |
|
|
|
delete[] positions; |
|
|
|
} |
|
|
|
setState(MatrixStatus::Initialized); |
|
|
|
} |
|
|
|
setState(MatrixStatus::Initialized); |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
@ -283,30 +312,27 @@ public: |
|
|
|
void addNextValue(const uint_fast64_t row, const uint_fast64_t col, const T& value) { |
|
|
|
// Check whether the given row and column positions are valid and throw |
|
|
|
// error otherwise. |
|
|
|
if ((row > rowCount) || (col > rowCount)) { |
|
|
|
if ((row > rowCount) || (col > colCount)) { |
|
|
|
triggerErrorState(); |
|
|
|
LOG4CPLUS_ERROR(logger, "Trying to add a value at illegal position (" << row << ", " << col << ")."); |
|
|
|
throw storm::exceptions::OutOfRangeException("Trying to add a value at illegal position."); |
|
|
|
} |
|
|
|
|
|
|
|
if (row == col) { // Set a diagonal element. |
|
|
|
diagonalStorage[row] = value; |
|
|
|
} else { // Set a non-diagonal element. |
|
|
|
// If we switched to another row, we have to adjust the missing |
|
|
|
// entries in the row_indications array. |
|
|
|
if (row != lastRow) { |
|
|
|
for (uint_fast64_t i = lastRow + 1; i <= row; ++i) { |
|
|
|
rowIndications[i] = currentSize; |
|
|
|
} |
|
|
|
lastRow = row; |
|
|
|
|
|
|
|
// If we switched to another row, we have to adjust the missing |
|
|
|
// entries in the row_indications array. |
|
|
|
if (row != lastRow) { |
|
|
|
for (uint_fast64_t i = lastRow + 1; i <= row; ++i) { |
|
|
|
rowIndications[i] = currentSize; |
|
|
|
} |
|
|
|
lastRow = row; |
|
|
|
} |
|
|
|
|
|
|
|
// Finally, set the element and increase the current size. |
|
|
|
valueStorage[currentSize] = value; |
|
|
|
columnIndications[currentSize] = col; |
|
|
|
// Finally, set the element and increase the current size. |
|
|
|
valueStorage[currentSize] = value; |
|
|
|
columnIndications[currentSize] = col; |
|
|
|
|
|
|
|
++currentSize; |
|
|
|
} |
|
|
|
++currentSize; |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
@ -355,18 +381,12 @@ public: |
|
|
|
*/ |
|
|
|
inline bool getValue(uint_fast64_t row, uint_fast64_t col, T* const target) const { |
|
|
|
// Check for illegal access indices. |
|
|
|
if ((row > rowCount) || (col > rowCount)) { |
|
|
|
if ((row > rowCount) || (col > colCount)) { |
|
|
|
LOG4CPLUS_ERROR(logger, "Trying to read a value from illegal position (" << row << ", " << col << ")."); |
|
|
|
throw storm::exceptions::OutOfRangeException("Trying to read a value from illegal position."); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// Read elements on the diagonal directly. |
|
|
|
if (row == col) { |
|
|
|
*target = diagonalStorage[row]; |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
// In case the element is not on the diagonal, we have to iterate |
|
|
|
// over the accessed row to find the element. |
|
|
|
uint_fast64_t rowStart = rowIndications[row]; |
|
|
@ -405,17 +425,12 @@ public: |
|
|
|
*/ |
|
|
|
inline T& getValue(uint_fast64_t row, uint_fast64_t col) { |
|
|
|
// Check for illegal access indices. |
|
|
|
if ((row > rowCount) || (col > rowCount)) { |
|
|
|
if ((row > rowCount) || (col > colCount)) { |
|
|
|
LOG4CPLUS_ERROR(logger, "Trying to read a value from illegal position (" << row << ", " << col << ")."); |
|
|
|
throw storm::exceptions::OutOfRangeException("Trying to read a value from illegal position."); |
|
|
|
} |
|
|
|
|
|
|
|
// Read elements on the diagonal directly. |
|
|
|
if (row == col) { |
|
|
|
return diagonalStorage[row]; |
|
|
|
} |
|
|
|
|
|
|
|
// In case the element is not on the diagonal, we have to iterate |
|
|
|
// we have to iterate |
|
|
|
// over the accessed row to find the element. |
|
|
|
uint_fast64_t rowStart = rowIndications[row]; |
|
|
|
uint_fast64_t rowEnd = rowIndications[row + 1]; |
|
|
@ -445,20 +460,18 @@ public: |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Returns a pointer to the value storage of the matrix. This storage does |
|
|
|
* *not* include elements on the diagonal. |
|
|
|
* @return A pointer to the value storage of the matrix. |
|
|
|
* Returns the number of columns of the matrix. |
|
|
|
*/ |
|
|
|
T* getStoragePointer() const { |
|
|
|
return valueStorage; |
|
|
|
uint_fast64_t getColumnCount() const { |
|
|
|
return colCount; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Returns a pointer to the storage of elements on the diagonal. |
|
|
|
* @return A pointer to the storage of elements on the diagonal. |
|
|
|
* Returns a pointer to the value storage of the matrix. |
|
|
|
* @return A pointer to the value storage of the matrix. |
|
|
|
*/ |
|
|
|
T* getDiagonalStoragePointer() const { |
|
|
|
return diagonalStorage; |
|
|
|
std::vector<T>& getStoragePointer() { |
|
|
|
return valueStorage; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
@ -467,17 +480,17 @@ public: |
|
|
|
* @return A pointer to the array that stores the start indices of non-zero |
|
|
|
* entries in the value storage for each row. |
|
|
|
*/ |
|
|
|
uint_fast64_t* getRowIndicationsPointer() const { |
|
|
|
std::vector<uint_fast64_t>& getRowIndicationsPointer() { |
|
|
|
return rowIndications; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Returns a pointer to an array that stores the column of each non-zero |
|
|
|
* element that is not on the diagonal. |
|
|
|
* element. |
|
|
|
* @return A pointer to an array that stores the column of each non-zero |
|
|
|
* element that is not on the diagonal. |
|
|
|
* element. |
|
|
|
*/ |
|
|
|
uint_fast64_t* getColumnIndicationsPointer() const { |
|
|
|
std::vector<uint_fast64_t>& getColumnIndicationsPointer() { |
|
|
|
return columnIndications; |
|
|
|
} |
|
|
|
|
|
|
@ -548,10 +561,6 @@ public: |
|
|
|
#define STORM_USE_TRIPLETCONVERT |
|
|
|
# ifdef STORM_USE_TRIPLETCONVERT |
|
|
|
|
|
|
|
// FIXME: Wouldn't it be more efficient to add the elements in |
|
|
|
// order including the diagonal elements? Otherwise, Eigen has to |
|
|
|
// perform some sorting. |
|
|
|
|
|
|
|
// Prepare the triplet storage. |
|
|
|
typedef Eigen::Triplet<T> IntTriplet; |
|
|
|
std::vector<IntTriplet> tripletList; |
|
|
@ -572,12 +581,6 @@ public: |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Then add the elements on the diagonal. |
|
|
|
for (uint_fast64_t i = 0; i < rowCount; ++i) { |
|
|
|
if (diagonalStorage[i] == 0) zeroCount++; |
|
|
|
tripletList.push_back(IntTriplet(static_cast<int_fast32_t>(i), static_cast<int_fast32_t>(i), diagonalStorage[i])); |
|
|
|
} |
|
|
|
|
|
|
|
// Let Eigen create a matrix from the given list of triplets. |
|
|
|
mat->setFromTriplets(tripletList.begin(), tripletList.end()); |
|
|
|
|
|
|
@ -596,10 +599,6 @@ public: |
|
|
|
rowStart = rowIndications[row]; |
|
|
|
rowEnd = rowIndications[row + 1]; |
|
|
|
|
|
|
|
// Insert the element on the diagonal. |
|
|
|
mat->insert(row, row) = diagonalStorage[row]; |
|
|
|
count++; |
|
|
|
|
|
|
|
// Insert the elements that are not on the diagonal |
|
|
|
while (rowStart < rowEnd) { |
|
|
|
mat->insert(row, columnIndications[rowStart]) = valueStorage[rowStart]; |
|
|
@ -628,19 +627,6 @@ public: |
|
|
|
return nonZeroEntryCount; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Returns the number of non-zero entries on the diagonal. |
|
|
|
* @return The number of non-zero entries on the diagonal. |
|
|
|
*/ |
|
|
|
uint_fast64_t getDiagonalNonZeroEntryCount() const { |
|
|
|
uint_fast64_t result = 0; |
|
|
|
T zero(0); |
|
|
|
for (uint_fast64_t i = 0; i < rowCount; ++i) { |
|
|
|
if (diagonalStorage[i] != zero) ++result; |
|
|
|
} |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* This function makes the rows given by the bit vector absorbing. |
|
|
|
* @param rows A bit vector indicating which rows to make absorbing. |
|
|
@ -658,7 +644,7 @@ public: |
|
|
|
/*! |
|
|
|
* This function makes the given row absorbing. This means that all |
|
|
|
* entries in will be set to 0 and the value 1 will be written |
|
|
|
* to the element on the diagonal. |
|
|
|
* to the element on the (pseudo-) diagonal. |
|
|
|
* @param row The row to be made absorbing. |
|
|
|
* @returns True iff the operation was successful. |
|
|
|
*/ |
|
|
@ -675,13 +661,31 @@ public: |
|
|
|
uint_fast64_t rowStart = rowIndications[row]; |
|
|
|
uint_fast64_t rowEnd = rowIndications[row + 1]; |
|
|
|
|
|
|
|
if (rowStart >= rowEnd) { |
|
|
|
LOG4CPLUS_ERROR(logger, "The row " << row << " can not be made absorbing, no state in row, would have to recreate matrix!"); |
|
|
|
throw storm::exceptions::InvalidStateException("A row can not be made absorbing, no state in row, would have to recreate matrix!"); |
|
|
|
} |
|
|
|
uint_fast64_t pseudoDiagonal = row % colCount; |
|
|
|
|
|
|
|
bool foundDiagonal = false; |
|
|
|
while (rowStart < rowEnd) { |
|
|
|
valueStorage[rowStart] = storm::utility::constGetZero<T>(); |
|
|
|
if (!foundDiagonal && columnIndications[rowStart] >= pseudoDiagonal) { |
|
|
|
foundDiagonal = true; |
|
|
|
// insert/replace the diagonal entry |
|
|
|
columnIndications[rowStart] = pseudoDiagonal; |
|
|
|
valueStorage[rowStart] = storm::utility::constGetOne<T>(); |
|
|
|
} else { |
|
|
|
valueStorage[rowStart] = storm::utility::constGetZero<T>(); |
|
|
|
} |
|
|
|
++rowStart; |
|
|
|
} |
|
|
|
|
|
|
|
// Set the element on the diagonal to one. |
|
|
|
diagonalStorage[row] = storm::utility::constGetOne<T>(); |
|
|
|
if (!foundDiagonal) { |
|
|
|
--rowStart; |
|
|
|
columnIndications[rowStart] = pseudoDiagonal; |
|
|
|
valueStorage[rowStart] = storm::utility::constGetOne<T>(); |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
@ -763,8 +767,6 @@ public: |
|
|
|
// Copy over selected entries. |
|
|
|
uint_fast64_t rowCount = 0; |
|
|
|
for (auto rowIndex : constraint) { |
|
|
|
result->addNextValue(rowCount, rowCount, diagonalStorage[rowIndex]); |
|
|
|
|
|
|
|
for (uint_fast64_t i = rowIndications[rowIndex]; i < rowIndications[rowIndex + 1]; ++i) { |
|
|
|
if (constraint.get(columnIndications[i])) { |
|
|
|
result->addNextValue(rowCount, bitsSetBeforeIndex[columnIndications[i]], valueStorage[i]); |
|
|
@ -794,8 +796,17 @@ public: |
|
|
|
*/ |
|
|
|
void invertDiagonal() { |
|
|
|
T one(1); |
|
|
|
for (uint_fast64_t i = 0; i < rowCount; ++i) { |
|
|
|
diagonalStorage[i] = one - diagonalStorage[i]; |
|
|
|
for (uint_fast64_t row = 0; row < rowCount; ++row) { |
|
|
|
uint_fast64_t rowStart = rowIndications[row]; |
|
|
|
uint_fast64_t rowEnd = rowIndications[row + 1]; |
|
|
|
uint_fast64_t pseudoDiagonal = row % colCount; |
|
|
|
while (rowStart < rowEnd) { |
|
|
|
if (columnIndications[rowStart] == pseudoDiagonal) { |
|
|
|
valueStorage[rowStart] = one - valueStorage[rowStart]; |
|
|
|
break; |
|
|
|
} |
|
|
|
++rowStart; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -803,8 +814,16 @@ public: |
|
|
|
* Negates all non-zero elements that are not on the diagonal. |
|
|
|
*/ |
|
|
|
void negateAllNonDiagonalElements() { |
|
|
|
for (uint_fast64_t i = 0; i < nonZeroEntryCount; ++i) { |
|
|
|
valueStorage[i] = - valueStorage[i]; |
|
|
|
for (uint_fast64_t row = 0; row < rowCount; ++row) { |
|
|
|
uint_fast64_t rowStart = rowIndications[row]; |
|
|
|
uint_fast64_t rowEnd = rowIndications[row + 1]; |
|
|
|
uint_fast64_t pseudoDiagonal = row % colCount; |
|
|
|
while (rowStart < rowEnd) { |
|
|
|
if (columnIndications[rowStart] != pseudoDiagonal) { |
|
|
|
valueStorage[rowStart] = - valueStorage[rowStart]; |
|
|
|
} |
|
|
|
++rowStart; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -844,7 +863,6 @@ public: |
|
|
|
// in case the given matrix does not have a non-zero element at this column position, or |
|
|
|
// multiply the two entries and add the result to the corresponding position in the vector. |
|
|
|
for (uint_fast64_t row = 0; row < rowCount && row < otherMatrix.rowCount; ++row) { |
|
|
|
(*result)[row] += diagonalStorage[row] * otherMatrix.diagonalStorage[row]; |
|
|
|
for (uint_fast64_t element = rowIndications[row], nextOtherElement = otherMatrix.rowIndications[row]; element < rowIndications[row + 1] && nextOtherElement < otherMatrix.rowIndications[row + 1]; ++element) { |
|
|
|
if (columnIndications[element] < otherMatrix.columnIndications[nextOtherElement]) { |
|
|
|
continue; |
|
|
@ -868,25 +886,23 @@ public: |
|
|
|
uint_fast64_t getSizeInMemory() const { |
|
|
|
uint_fast64_t size = sizeof(*this); |
|
|
|
// Add value_storage size. |
|
|
|
size += sizeof(T) * nonZeroEntryCount; |
|
|
|
// Add diagonal_storage size. |
|
|
|
size += sizeof(T) * (rowCount + 1); |
|
|
|
size += sizeof(T) * valueStorage.capacity(); |
|
|
|
// Add column_indications size. |
|
|
|
size += sizeof(uint_fast64_t) * nonZeroEntryCount; |
|
|
|
size += sizeof(uint_fast64_t) * columnIndications.capacity(); |
|
|
|
// Add row_indications size. |
|
|
|
size += sizeof(uint_fast64_t) * (rowCount + 1); |
|
|
|
size += sizeof(uint_fast64_t) * rowIndications.capacity(); |
|
|
|
return size; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Returns an iterator to the columns of the non-zero entries of the given |
|
|
|
* row that are not on the diagonal. |
|
|
|
* row. |
|
|
|
* @param row The row whose columns the iterator will return. |
|
|
|
* @return An iterator to the columns of the non-zero entries of the given |
|
|
|
* row that are not on the diagonal. |
|
|
|
* row. |
|
|
|
*/ |
|
|
|
constIndexIterator beginConstColumnNoDiagIterator(uint_fast64_t row) const { |
|
|
|
return this->columnIndications + this->rowIndications[row]; |
|
|
|
constIndexIterator beginConstColumnIterator(uint_fast64_t row) const { |
|
|
|
return &(this->columnIndications[0]) + this->rowIndications[row]; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
@ -894,18 +910,18 @@ public: |
|
|
|
* @param row The row for which the iterator should point to the past-the-end |
|
|
|
* element. |
|
|
|
*/ |
|
|
|
constIndexIterator endConstColumnNoDiagIterator(uint_fast64_t row) const { |
|
|
|
return this->columnIndications + this->rowIndications[row + 1]; |
|
|
|
constIndexIterator endConstColumnIterator(uint_fast64_t row) const { |
|
|
|
return &(this->columnIndications[0]) + this->rowIndications[row + 1]; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Returns an iterator over the elements of the given row. The iterator |
|
|
|
* will include neither the diagonal element nor zero entries. |
|
|
|
* will include no zero entries. |
|
|
|
* @param row The row whose elements the iterator will return. |
|
|
|
* @return An iterator over the elements of the given row. |
|
|
|
*/ |
|
|
|
constIterator beginConstNoDiagIterator(uint_fast64_t row) const { |
|
|
|
return this->valueStorage + this->rowIndications[row]; |
|
|
|
constIterator beginConstIterator(uint_fast64_t row) const { |
|
|
|
return &(this->valueStorage[0]) + this->rowIndications[row]; |
|
|
|
} |
|
|
|
/*! |
|
|
|
* Returns an iterator pointing to the first element after the given |
|
|
@ -914,32 +930,28 @@ public: |
|
|
|
* past-the-end element. |
|
|
|
* @return An iterator to the element after the given row. |
|
|
|
*/ |
|
|
|
constIterator endConstNoDiagIterator(uint_fast64_t row) const { |
|
|
|
return this->valueStorage + this->rowIndications[row + 1]; |
|
|
|
constIterator endConstIterator(uint_fast64_t row) const { |
|
|
|
return &(this->valueStorage[0]) + this->rowIndications[row + 1]; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* @brief Calculate sum of all entries in given row. |
|
|
|
* |
|
|
|
* Adds up all values in the given row (including the diagonal value) |
|
|
|
* Adds up all values in the given row |
|
|
|
* and returns the sum. |
|
|
|
* @param row The row that should be added up. |
|
|
|
* @return Sum of the row. |
|
|
|
*/ |
|
|
|
T getRowSum(uint_fast64_t row) const { |
|
|
|
T sum = this->diagonalStorage[row]; |
|
|
|
for (auto it = this->beginConstNoDiagIterator(row); it != this->endConstNoDiagIterator(row); it++) { |
|
|
|
T sum = storm::utility::constGetZero<T>(); |
|
|
|
for (auto it = this->beginConstIterator(row); it != this->endConstIterator(row); it++) { |
|
|
|
sum += *it; |
|
|
|
} |
|
|
|
return sum; |
|
|
|
} |
|
|
|
|
|
|
|
void print() const { |
|
|
|
std::cout << "diag: --------------------------------" << std::endl; |
|
|
|
for (uint_fast64_t i = 0; i < rowCount; ++i) { |
|
|
|
std::cout << "(" << i << "," << i << ") = " << diagonalStorage[i] << std::endl; |
|
|
|
} |
|
|
|
std::cout << "non diag: ----------------------------" << std::endl; |
|
|
|
std::cout << "entries: ----------------------------" << std::endl; |
|
|
|
for (uint_fast64_t i = 0; i < rowCount; ++i) { |
|
|
|
for (uint_fast64_t j = rowIndications[i]; j < rowIndications[i + 1]; ++j) { |
|
|
|
std::cout << "(" << i << "," << columnIndications[j] << ") = " << valueStorage[j] << std::endl; |
|
|
@ -955,31 +967,31 @@ private: |
|
|
|
uint_fast64_t rowCount; |
|
|
|
|
|
|
|
/*! |
|
|
|
* The number of non-zero elements that are not on the diagonal. |
|
|
|
* The number of columns of the matrix. |
|
|
|
*/ |
|
|
|
uint_fast64_t nonZeroEntryCount; |
|
|
|
uint_fast64_t colCount; |
|
|
|
|
|
|
|
/*! |
|
|
|
* Stores all non-zero values that are not on the diagonal. |
|
|
|
* The number of non-zero elements. |
|
|
|
*/ |
|
|
|
T* valueStorage; |
|
|
|
uint_fast64_t nonZeroEntryCount; |
|
|
|
|
|
|
|
/*! |
|
|
|
* Stores all elements on the diagonal, even the ones that are zero. |
|
|
|
* Stores all non-zero values. |
|
|
|
*/ |
|
|
|
T* diagonalStorage; |
|
|
|
std::vector<T> valueStorage; |
|
|
|
|
|
|
|
/*! |
|
|
|
* Stores the column for each non-zero element that is not on the diagonal. |
|
|
|
* Stores the column for each non-zero element. |
|
|
|
*/ |
|
|
|
uint_fast64_t* columnIndications; |
|
|
|
std::vector<uint_fast64_t> columnIndications; |
|
|
|
|
|
|
|
/*! |
|
|
|
* Array containing the boundaries (indices) in the value_storage array |
|
|
|
* Vector containing the boundaries (indices) in the value_storage array |
|
|
|
* for each row. All elements of value_storage with indices between the |
|
|
|
* i-th and the (i+1)-st element of this array belong to row i. |
|
|
|
*/ |
|
|
|
uint_fast64_t* rowIndications; |
|
|
|
std::vector<uint_fast64_t> rowIndications; |
|
|
|
|
|
|
|
/*! |
|
|
|
* The internal status of the matrix. |
|
|
@ -1017,24 +1029,37 @@ private: |
|
|
|
/*! |
|
|
|
* Prepares the internal CSR storage. For this, it requires |
|
|
|
* non_zero_entry_count and row_count to be set correctly. |
|
|
|
* @param alsoPerformAllocation If set to true, all entries are pre-allocated. This is the default. |
|
|
|
* @return True on success, false otherwise (allocation failed). |
|
|
|
*/ |
|
|
|
bool prepareInternalStorage() { |
|
|
|
// Set up the arrays for the elements that are not on the diagonal. |
|
|
|
valueStorage = new (std::nothrow) T[nonZeroEntryCount](); |
|
|
|
columnIndications = new (std::nothrow) uint_fast64_t[nonZeroEntryCount](); |
|
|
|
|
|
|
|
// Set up the row_indications array and reserve one element more than |
|
|
|
// there are rows in order to put a sentinel element at the end, |
|
|
|
// which eases iteration process. |
|
|
|
rowIndications = new (std::nothrow) uint_fast64_t[rowCount + 1](); |
|
|
|
|
|
|
|
// Set up the array for the elements on the diagonal. |
|
|
|
diagonalStorage = new (std::nothrow) T[rowCount](); |
|
|
|
bool prepareInternalStorage(const bool alsoPerformAllocation) { |
|
|
|
if (alsoPerformAllocation) { |
|
|
|
// Set up the arrays for the elements that are not on the diagonal. |
|
|
|
valueStorage.resize(nonZeroEntryCount, storm::utility::constGetZero<T>()); |
|
|
|
columnIndications.resize(nonZeroEntryCount, 0); |
|
|
|
|
|
|
|
// Set up the row_indications vector and reserve one element more than |
|
|
|
// there are rows in order to put a sentinel element at the end, |
|
|
|
// which eases iteration process. |
|
|
|
rowIndications.resize(rowCount + 1, 0); |
|
|
|
|
|
|
|
// Return whether all the allocations could be made without error. |
|
|
|
return ((valueStorage.capacity() >= nonZeroEntryCount) && (columnIndications.capacity() >= nonZeroEntryCount) |
|
|
|
&& (rowIndications.capacity() >= (rowCount + 1))); |
|
|
|
} else { |
|
|
|
valueStorage.reserve(nonZeroEntryCount); |
|
|
|
columnIndications.reserve(nonZeroEntryCount); |
|
|
|
rowIndications.reserve(rowCount + 1); |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Return whether all the allocations could be made without error. |
|
|
|
return ((valueStorage != NULL) && (columnIndications != NULL) |
|
|
|
&& (rowIndications != NULL) && (diagonalStorage != NULL)); |
|
|
|
/*! |
|
|
|
* Shorthand for prepareInternalStorage(true) |
|
|
|
* @see prepareInternalStorage(const bool) |
|
|
|
*/ |
|
|
|
bool prepareInternalStorage() { |
|
|
|
return this->prepareInternalStorage(true); |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
@ -1060,53 +1085,6 @@ private: |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Helper function to determine the number of non-zero elements that are |
|
|
|
* not on the diagonal of the given Eigen matrix. |
|
|
|
* @param eigen_sparse_matrix The Eigen matrix to analyze. |
|
|
|
* @return The number of non-zero elements that are not on the diagonal of |
|
|
|
* the given Eigen matrix. |
|
|
|
*/ |
|
|
|
template<typename _Scalar, int _Options, typename _Index> |
|
|
|
_Index getEigenSparseMatrixCorrectNonZeroEntryCount(const Eigen::SparseMatrix<_Scalar, _Options, _Index>& eigen_sparse_matrix) const { |
|
|
|
const _Index* indexPtr = eigen_sparse_matrix.innerIndexPtr(); |
|
|
|
const _Index* outerPtr = eigen_sparse_matrix.outerIndexPtr(); |
|
|
|
|
|
|
|
const _Index entryCount = eigen_sparse_matrix.nonZeros(); |
|
|
|
const _Index outerCount = eigen_sparse_matrix.outerSize(); |
|
|
|
|
|
|
|
uint_fast64_t diagNonZeros = 0; |
|
|
|
|
|
|
|
// For RowMajor, row is the current row and col the column and for |
|
|
|
// ColMajor, row is the current column and col the row, but this is |
|
|
|
// not important as we are only looking for elements on the diagonal. |
|
|
|
_Index innerStart = 0; |
|
|
|
_Index innerEnd = 0; |
|
|
|
_Index innerMid = 0; |
|
|
|
for (_Index row = 0; row < outerCount; ++row) { |
|
|
|
innerStart = outerPtr[row]; |
|
|
|
innerEnd = outerPtr[row + 1] - 1; |
|
|
|
|
|
|
|
// Now use binary search (but defer equality detection). |
|
|
|
while (innerStart < innerEnd) { |
|
|
|
innerMid = innerStart + ((innerEnd - innerStart) / 2); |
|
|
|
|
|
|
|
if (indexPtr[innerMid] < row) { |
|
|
|
innerStart = innerMid + 1; |
|
|
|
} else { |
|
|
|
innerEnd = innerMid; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Check whether we have found an element on the diagonal. |
|
|
|
if ((innerStart == innerEnd) && (indexPtr[innerStart] == row)) { |
|
|
|
++diagNonZeros; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return static_cast<_Index>(entryCount - diagNonZeros); |
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} // namespace storage |
|
|
|