Browse Source

Added functional and performance tests for sparse matrix.

Former-commit-id: dd9abe1826
tempestpy_adaptions
dehnert 11 years ago
parent
commit
e08b61b9f7
  1. 2
      CMakeLists.txt
  2. 179
      src/storage/SparseMatrix.cpp
  3. 15
      src/storage/SparseMatrix.h
  4. 80
      test/functional/storage/BitVectorTest.cpp
  5. 569
      test/functional/storage/SparseMatrixTest.cpp
  6. 2
      test/performance/storage/BitVectorTest.cpp
  7. 43
      test/performance/storage/SparseMatrixTest.cpp

2
CMakeLists.txt

@ -144,7 +144,7 @@ else(CLANG)
# As CLANG is not set as a variable, we need to set it in case we have not matched another compiler.
set (CLANG ON)
# Set standard flags for clang
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -funroll-loops -O3")
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -funroll-loops -O4")
if(UNIX AND NOT APPLE AND NOT USE_LIBCXX)
set(CLANG_STDLIB libstdc++)
message(STATUS "StoRM - Linking against libstdc++")

179
src/storage/SparseMatrix.cpp

@ -181,8 +181,58 @@ namespace storm {
return *this;
}
template<typename T>
bool SparseMatrix<T>::operator==(SparseMatrix<T> const& other) const {
if (this == &other) {
return true;
}
if (this->isInitialized() != other.isInitialized()) {
return false;
}
bool equalityResult = true;
// If the matrix is initialized, we only care about the contents and not the auxiliary members.
if (!this->isInitialized()) {
equalityResult &= rowCountSet == other.rowCountSet;
equalityResult &= columnCountSet == other.columnCountSet;
equalityResult &= internalStatus == other.internalStatus;
equalityResult &= currentEntryCount == other.currentEntryCount;
equalityResult &= lastRow == other.lastRow;
equalityResult &= lastColumn == other.lastColumn;
}
equalityResult &= rowCount == other.rowCount;
equalityResult &= columnCount == other.columnCount;
// For the actual contents, we need to do a little bit more work, because we want to ignore elements that
// are set to zero, please they may be represented implicitly in the other matrix.
for (uint_fast64_t row = 0; row < this->getRowCount(); ++row) {
for (uint_fast64_t elem = rowIndications[row], elem2 = other.rowIndications[row]; elem < rowIndications[row + 1] && elem2 < other.rowIndications[row + 1]; ++elem, ++elem2) {
// Skip over all zero entries in both matrices.
while (elem < rowIndications[row + 1] && valueStorage[elem] == storm::utility::constantZero<T>()) {
++elem;
}
while (elem2 < other.rowIndications[row + 1] && other.valueStorage[elem2] == storm::utility::constantZero<T>()) {
++elem2;
}
if ((elem == rowIndications[row + 1]) ^ (elem2 == other.rowIndications[row + 1]) || columnIndications[elem] != other.columnIndications[elem2] || valueStorage[elem] != other.valueStorage[elem2]) {
equalityResult = false;
break;
}
}
}
return equalityResult;
}
template<typename T>
void SparseMatrix<T>::addNextValue(uint_fast64_t row, uint_fast64_t column, T const& value) {
if (this->isInitialized()) {
throw storm::exceptions::InvalidStateException() << "Illegal call to SparseMatrix::addNextValue: adding an entry to an already initialized matrix.";
}
// Depending on whether the internal data storage was preallocated or not, adding the value is done somewhat
// differently.
if (storagePreallocated) {
@ -190,13 +240,16 @@ namespace storm {
if (row >= rowCount || column >= columnCount) {
throw storm::exceptions::OutOfRangeException() << "Illegal call to SparseMatrix::addNextValue: adding entry at out-of-bounds position (" << row << ", " << column << ") in matrix of size (" << rowCount << ", " << columnCount << ").";
}
} else if (rowCountSet) {
if (row >= rowCount) {
throw storm::exceptions::OutOfRangeException() << "Illegal call to SparseMatrix::addNextValue: adding entry at out-of-bounds row " << row << " in matrix with " << rowCount << " rows.";
} else {
if (rowCountSet) {
if (row >= rowCount) {
throw storm::exceptions::OutOfRangeException() << "Illegal call to SparseMatrix::addNextValue: adding entry at out-of-bounds row " << row << " in matrix with " << rowCount << " rows.";
}
}
} else if (columnCountSet) {
if (column >= columnCount) {
throw storm::exceptions::OutOfRangeException() << "Illegal call to SparseMatrix::addNextValue: adding entry at out-of-bounds column " << column << " in matrix with " << columnCount << " columns.";
if (columnCountSet) {
if (column >= columnCount) {
throw storm::exceptions::OutOfRangeException() << "Illegal call to SparseMatrix::addNextValue: adding entry at out-of-bounds column " << column << " in matrix with " << columnCount << " columns.";
}
}
}
@ -249,8 +302,8 @@ namespace storm {
template<typename T>
void SparseMatrix<T>::finalize(uint_fast64_t overriddenRowCount, uint_fast64_t overridenColumnCount) {
// Check whether it's safe to finalize the matrix and throw error otherwise.
if (internalStatus == INITIALIZED) {
throw storm::exceptions::InvalidStateException() << "Illegal call to SparseMatrix::finalize: finalizing an initialized matrix is forbidden.";
if (this->isInitialized()) {
throw storm::exceptions::InvalidStateException() << "Illegal call to SparseMatrix::finalize: matrix has already been initialized.";
} else if (storagePreallocated && currentEntryCount != entryCount) {
throw storm::exceptions::InvalidStateException() << "Illegal call to SparseMatrix::finalize: expected " << entryCount << " entries, but got " << currentEntryCount << " instead.";
} else {
@ -287,26 +340,30 @@ namespace storm {
template<typename T>
uint_fast64_t SparseMatrix<T>::getRowCount() const {
checkReady("getRowCount");
return rowCount;
}
template<typename T>
uint_fast64_t SparseMatrix<T>::getColumnCount() const {
checkReady("getColumnCount");
return columnCount;
}
template<typename T>
bool SparseMatrix<T>::isInitialized() {
bool SparseMatrix<T>::isInitialized() const {
return internalStatus == INITIALIZED;
}
template<typename T>
uint_fast64_t SparseMatrix<T>::getEntryCount() const {
checkReady("getEntryCount");
return entryCount;
}
template<typename T>
void SparseMatrix<T>::makeRowsAbsorbing(storm::storage::BitVector const& rows) {
checkReady("makeRowsAbsorbing");
for (auto row : rows) {
makeRowAbsorbing(row, row);
}
@ -314,6 +371,7 @@ namespace storm {
template<typename T>
void SparseMatrix<T>::makeRowsAbsorbing(storm::storage::BitVector const& rowGroupConstraint, std::vector<uint_fast64_t> const& rowGroupIndices) {
checkReady("makeRowsAbsorbing");
for (auto rowGroup : rowGroupConstraint) {
for (uint_fast64_t row = rowGroupIndices[rowGroup]; row < rowGroupIndices[rowGroup + 1]; ++row) {
makeRowAbsorbing(row, rowGroup);
@ -323,6 +381,7 @@ namespace storm {
template<typename T>
void SparseMatrix<T>::makeRowAbsorbing(const uint_fast64_t row, const uint_fast64_t column) {
checkReady("makeRowAbsorbing");
if (row > rowCount) {
throw storm::exceptions::OutOfRangeException() << "Illegal call to SparseMatrix::makeRowAbsorbing: access to row " << row << " is out of bounds.";
}
@ -352,6 +411,7 @@ namespace storm {
template<typename T>
T SparseMatrix<T>::getConstrainedRowSum(uint_fast64_t row, storm::storage::BitVector const& constraint) const {
checkReady("getConstrainedRowSum");
T result(0);
for (uint_fast64_t i = rowIndications[row]; i < rowIndications[row + 1]; ++i) {
if (constraint.get(columnIndications[i])) {
@ -363,6 +423,7 @@ namespace storm {
template<typename T>
std::vector<T> SparseMatrix<T>::getConstrainedRowSumVector(storm::storage::BitVector const& rowConstraint, storm::storage::BitVector const& columnConstraint) const {
checkReady("getConstrainedRowSumVector");
std::vector<T> result(rowConstraint.getNumberOfSetBits());
uint_fast64_t currentRowCount = 0;
for (auto row : rowConstraint) {
@ -373,6 +434,7 @@ namespace storm {
template<typename T>
std::vector<T> SparseMatrix<T>::getConstrainedRowSumVector(storm::storage::BitVector const& rowGroupConstraint, std::vector<uint_fast64_t> const& rowGroupIndices, storm::storage::BitVector const& columnConstraint) const {
checkReady("getConstrainedRowSumVector");
std::vector<T> result;
result.reserve(rowGroupConstraint.getNumberOfSetBits());
for (auto rowGroup : rowGroupConstraint) {
@ -385,55 +447,13 @@ namespace storm {
template<typename T>
SparseMatrix<T> SparseMatrix<T>::getSubmatrix(storm::storage::BitVector const& constraint) const {
// Check whether we select at least some rows and columns.
if (constraint.getNumberOfSetBits() == 0) {
throw storm::exceptions::InvalidArgumentException() << "Illegal call to SparseMatrix::getSubmatrix: cannot create empty submatrix.";
}
// First, we need to determine the number of entries of the submatrix.
uint_fast64_t subEntries = 0;
for (auto rowIndex : constraint) {
for (uint_fast64_t i = rowIndications[rowIndex]; i < rowIndications[rowIndex + 1]; ++i) {
if (constraint.get(columnIndications[i])) {
++subEntries;
}
}
// Create a fake row grouping to reduce this to a call to a more general method.
std::vector<uint_fast64_t> rowGroupIndices(rowCount + 1);
uint_fast64_t i = 0;
for (std::vector<uint_fast64_t>::iterator it = rowGroupIndices.begin(); it != rowGroupIndices.end(); ++it, ++i) {
*it = i;
}
// Create and initialize resulting matrix.
SparseMatrix result(constraint.getNumberOfSetBits(), constraint.getNumberOfSetBits(), subEntries);
// Create a temporary vecotr that stores for each index whose bit is set to true the number of bits that
// were set before that particular index.
std::vector<uint_fast64_t> bitsSetBeforeIndex;
bitsSetBeforeIndex.reserve(columnCount);
// Compute the information to fill this vector.
uint_fast64_t lastIndex = 0;
uint_fast64_t currentNumberOfSetBits = 0;
for (auto index : constraint) {
while (lastIndex <= index) {
bitsSetBeforeIndex.push_back(currentNumberOfSetBits);
++lastIndex;
}
++currentNumberOfSetBits;
}
// Copy over selected entries and use the previously computed vector to get the column offset.
uint_fast64_t rowCount = 0;
for (auto rowIndex : constraint) {
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]);
}
}
++rowCount;
}
// Finalize submatrix and return result.
result.finalize();
return result;
return getSubmatrix(constraint, constraint, rowGroupIndices);
}
template<typename T>
@ -443,6 +463,7 @@ namespace storm {
template<typename T>
SparseMatrix<T> SparseMatrix<T>::getSubmatrix(storm::storage::BitVector const& rowGroupConstraint, storm::storage::BitVector const& columnConstraint, std::vector<uint_fast64_t> const& rowGroupIndices, bool insertDiagonalEntries) const {
checkReady("getSubmatrix");
// First, we need to determine the number of entries and the number of rows of the submatrix.
uint_fast64_t subEntries = 0;
uint_fast64_t subRows = 0;
@ -525,6 +546,7 @@ namespace storm {
template<typename T>
SparseMatrix<T> SparseMatrix<T>::getSubmatrix(std::vector<uint_fast64_t> const& rowGroupToRowIndexMapping, std::vector<uint_fast64_t> const& rowGroupIndices, bool insertDiagonalEntries) const {
checkReady("getSubmatrix");
// First, we need to count how many non-zero entries the resulting matrix will have and reserve space for
// diagonal entries if requested.
uint_fast64_t subEntries = 0;
@ -577,7 +599,8 @@ namespace storm {
template <typename T>
SparseMatrix<T> SparseMatrix<T>::transpose() const {
checkReady("transpose");
uint_fast64_t rowCount = this->columnCount;
uint_fast64_t columnCount = this->rowCount;
uint_fast64_t entryCount = this->entryCount;
@ -628,6 +651,8 @@ namespace storm {
template<typename T>
void SparseMatrix<T>::invertDiagonal() {
checkReady("invertDiagonal");
// Check if the matrix is square, because only then it makes sense to perform this
// transformation.
if (this->getRowCount() != this->getColumnCount()) {
@ -660,6 +685,8 @@ namespace storm {
template<typename T>
void SparseMatrix<T>::negateAllNonDiagonalEntries() {
checkReady("negateAllNonDiagonalEntries");
// Check if the matrix is square, because only then it makes sense to perform this transformation.
if (this->getRowCount() != this->getColumnCount()) {
throw storm::exceptions::InvalidArgumentException() << "Illegal call to SparseMatrix::invertDiagonal: matrix is non-square.";
@ -680,6 +707,8 @@ namespace storm {
template<typename T>
void SparseMatrix<T>::deleteDiagonalEntries() {
checkReady("deleteDiagonalEntries");
// Check if the matrix is square, because only then it makes sense to perform this transformation.
if (this->getRowCount() != this->getColumnCount()) {
throw storm::exceptions::InvalidArgumentException() << "Illegal call to SparseMatrix::deleteDiagonalEntries: matrix is non-square.";
@ -700,6 +729,8 @@ namespace storm {
template<typename T>
typename std::pair<storm::storage::SparseMatrix<T>, storm::storage::SparseMatrix<T>> SparseMatrix<T>::getJacobiDecomposition() const {
checkReady("getJacobiDecomposition");
if (rowCount != columnCount) {
throw storm::exceptions::InvalidArgumentException() << "Illegal call to SparseMatrix::invertDiagonal: matrix is non-square.";
}
@ -730,6 +761,8 @@ namespace storm {
template<typename T>
std::vector<T> SparseMatrix<T>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<T> const& otherMatrix) const {
checkReady("getPointwiseProductRowSumVector");
std::vector<T> result(rowCount, storm::utility::constantZero<T>());
// Iterate over all elements of the current matrix and either continue with the next element in case the
@ -755,6 +788,7 @@ namespace storm {
template<typename T>
void SparseMatrix<T>::multiplyWithVector(std::vector<T> const& vector, std::vector<T>& result) const {
checkReady("multiplyWithVector");
#ifdef STORM_HAVE_INTELTBB
tbb::parallel_for(tbb::blocked_range<uint_fast64_t>(0, result.size()), tbbHelper_MatrixRowVectorScalarProduct<storm::storage::SparseMatrix<T>, std::vector<T>, T>(this, &vector, &result));
#else
@ -778,6 +812,8 @@ namespace storm {
template<typename T>
uint_fast64_t SparseMatrix<T>::getSizeInMemory() const {
checkReady("getSizeInMemory");
uint_fast64_t size = sizeof(*this);
// Add value_storage size.
@ -794,56 +830,67 @@ namespace storm {
template<typename T>
typename SparseMatrix<T>::const_rows SparseMatrix<T>::getRows(uint_fast64_t startRow, uint_fast64_t endRow) const {
checkReady("getRows");
return const_rows(this->valueStorage.data() + this->rowIndications[startRow], this->columnIndications.data() + this->rowIndications[startRow], this->rowIndications[endRow + 1] - this->rowIndications[startRow]);
}
template<typename T>
typename SparseMatrix<T>::rows SparseMatrix<T>::getRows(uint_fast64_t startRow, uint_fast64_t endRow) {
checkReady("getRows");
return rows(this->valueStorage.data() + this->rowIndications[startRow], this->columnIndications.data() + this->rowIndications[startRow], this->rowIndications[endRow + 1] - this->rowIndications[startRow]);
}
template<typename T>
typename SparseMatrix<T>::const_rows SparseMatrix<T>::getRow(uint_fast64_t row) const {
checkReady("getRow");
return getRows(row, row);
}
template<typename T>
typename SparseMatrix<T>::rows SparseMatrix<T>::getRow(uint_fast64_t row) {
checkReady("getRow");
return getRows(row, row);
}
template<typename T>
typename SparseMatrix<T>::const_iterator SparseMatrix<T>::begin(uint_fast64_t row) const {
checkReady("begin");
return const_iterator(this->valueStorage.data() + this->rowIndications[row], this->columnIndications.data() + this->rowIndications[row]);
}
template<typename T>
typename SparseMatrix<T>::iterator SparseMatrix<T>::begin(uint_fast64_t row) {
checkReady("begin");
return iterator(this->valueStorage.data() + this->rowIndications[row], this->columnIndications.data() + this->rowIndications[row]);
}
template<typename T>
typename SparseMatrix<T>::const_iterator SparseMatrix<T>::end(uint_fast64_t row) const {
checkReady("end");
return const_iterator(this->valueStorage.data() + this->rowIndications[row + 1], this->columnIndications.data() + this->rowIndications[row + 1]);
}
template<typename T>
typename SparseMatrix<T>::iterator SparseMatrix<T>::end(uint_fast64_t row) {
checkReady("end");
return iterator(this->valueStorage.data() + this->rowIndications[row + 1], this->columnIndications.data() + this->rowIndications[row + 1]);
}
template<typename T>
typename SparseMatrix<T>::const_iterator SparseMatrix<T>::end() const {
checkReady("end");
return const_iterator(this->valueStorage.data() + this->rowIndications[rowCount], this->columnIndications.data() + this->rowIndications[rowCount]);
}
template<typename T>
typename SparseMatrix<T>::iterator SparseMatrix<T>::end() {
checkReady("end");
return iterator(this->valueStorage.data() + this->rowIndications[rowCount], this->columnIndications.data() + this->rowIndications[rowCount]);
}
template<typename T>
T SparseMatrix<T>::getRowSum(uint_fast64_t row) const {
checkReady("getRowSum");
T sum = storm::utility::constantZero<T>();
for (typename std::vector<T>::const_iterator valueIterator = valueStorage.begin() + rowIndications[row], valueIteratorEnd = valueStorage.begin() + rowIndications[row + 1]; valueIterator != valueIteratorEnd; ++valueIterator) {
sum += *valueIterator;
@ -853,13 +900,15 @@ namespace storm {
template<typename T>
bool SparseMatrix<T>::isSubmatrixOf(SparseMatrix<T> const& matrix) const {
checkReady("isSubmatrixOf");
// Check for matching sizes.
if (this->getRowCount() != matrix.getRowCount()) return false;
if (this->getColumnCount() != matrix.getColumnCount()) return false;
// Check the subset property for all rows individually.
for (uint_fast64_t row = 0; row < this->getRowCount(); ++row) {
for (uint_fast64_t elem = rowIndications[row], elem2 = matrix.rowIndications[row]; elem < rowIndications[row + 1] && elem < matrix.rowIndications[row + 1]; ++elem) {
for (uint_fast64_t elem = rowIndications[row], elem2 = matrix.rowIndications[row]; elem < rowIndications[row + 1]; ++elem) {
// Skip over all entries of the other matrix that are before the current entry in the current matrix.
while (elem2 < matrix.rowIndications[row + 1] && matrix.columnIndications[elem2] < columnIndications[elem]) {
++elem2;
@ -874,6 +923,8 @@ namespace storm {
template<typename T>
std::ostream& operator<<(std::ostream& out, SparseMatrix<T> const& matrix) {
matrix.checkReady("operator<<");
// Print column numbers in header.
out << "\t\t";
for (uint_fast64_t i = 0; i < matrix.columnCount; ++i) {
@ -937,13 +988,22 @@ namespace storm {
}
}
template<typename T>
void SparseMatrix<T>::checkReady(std::string const& methodName) const {
if (!this->isInitialized()) {
throw storm::exceptions::InvalidStateException() << "Invalid call to SparseMatrix::" << methodName << ": matrix used for operation has not been initialized properly.";
}
}
// Explicitly instantiate the matrix and the nested classes.
template class SparseMatrix<double>::BaseIterator<double const>;
template class SparseMatrix<double>::BaseIterator<double>;
template class SparseMatrix<double>;
template std::ostream& operator<<(std::ostream& out, SparseMatrix<double> const& matrix);
template class SparseMatrix<int>::BaseIterator<int const>;
template class SparseMatrix<int>::BaseIterator<int>;
template class SparseMatrix<int>;
template std::ostream& operator<<(std::ostream& out, SparseMatrix<int> const& matrix);
#ifdef STORM_HAVE_INTELTBB
@ -973,7 +1033,6 @@ namespace storm {
#endif
} // namespace storage
} // namespace storm

15
src/storage/SparseMatrix.h

@ -295,6 +295,14 @@ namespace storm {
*/
SparseMatrix<T>& operator=(SparseMatrix<T>&& other);
/*!
* Determines whether the current and the given matrix are semantically equal.
*
* @param other The matrix with which to compare the current matrix.
* @return True iff the given matrix is semantically equal to the current one.
*/
bool operator==(SparseMatrix<T> const& other) const;
/*!
* Sets the matrix entry at the given row and column to the given value. After all entries have been added,
* a call to finalize(false) is mandatory.
@ -352,7 +360,7 @@ namespace storm {
*
* @return True iff the matrix was initialized properly and is ready for further use.
*/
bool isInitialized();
bool isInitialized() const;
/*!
* This function makes the given rows absorbing.
@ -634,6 +642,11 @@ namespace storm {
* will cause occasional reallocations.
*/
void prepareInternalStorage();
/*!
* Checks whether the matrix is properly initialized and throws an exception otherwise.
*/
void checkReady(std::string const& methodName) const;
// A flag indicating whether the number of rows was set upon construction.
bool rowCountSet;

80
test/functional/storage/BitVectorTest.cpp

@ -3,7 +3,7 @@
#include "src/exceptions/InvalidArgumentException.h"
#include "src/exceptions/OutOfRangeException.h"
TEST(BitVectorTest, InitToZeroTest) {
TEST(BitVectorTest, InitToZero) {
storm::storage::BitVector vector(32);
for (uint_fast64_t i = 0; i < 32; ++i) {
@ -14,7 +14,7 @@ TEST(BitVectorTest, InitToZeroTest) {
ASSERT_FALSE(vector.full());
}
TEST(BitVectorTest, InitToOneTest) {
TEST(BitVectorTest, InitToOne) {
storm::storage::BitVector vector(32, true);
for (uint_fast64_t i = 0; i < 32; ++i) {
@ -24,11 +24,11 @@ TEST(BitVectorTest, InitToOneTest) {
ASSERT_TRUE(vector.full());
}
TEST(BitVectorTest, InitFromIteratorTest) {
TEST(BitVectorTest, InitFromIterator) {
std::vector<uint_fast64_t> valueVector = {0, 4, 10};
storm::storage::BitVector vector(32, valueVector.begin(), valueVector.end());
ASSERT_EQ(vector.size(), 32);
ASSERT_EQ(32, vector.size());
for (uint_fast64_t i = 0; i < 32; ++i) {
if (i == 0 || i == 4 || i == 10) {
@ -39,7 +39,7 @@ TEST(BitVectorTest, InitFromIteratorTest) {
}
}
TEST(BitVectorTest, GetSetTest) {
TEST(BitVectorTest, GetSet) {
storm::storage::BitVector vector(32);
for (uint_fast64_t i = 0; i < 32; ++i) {
@ -47,18 +47,18 @@ TEST(BitVectorTest, GetSetTest) {
}
for (uint_fast64_t i = 0; i < 32; ++i) {
ASSERT_EQ(vector.get(i), i % 2 == 0);
ASSERT_EQ(i % 2 == 0, vector.get(i));
}
}
TEST(BitVectorTest, GetSetExceptionTest) {
TEST(BitVectorTest, GetSetException) {
storm::storage::BitVector vector(32);
ASSERT_THROW(vector.get(32), storm::exceptions::OutOfRangeException);
ASSERT_THROW(vector.set(32), storm::exceptions::OutOfRangeException);
}
TEST(BitVectorTest, ResizeTest) {
TEST(BitVectorTest, Resize) {
storm::storage::BitVector vector(32);
for (uint_fast64_t i = 0; i < 32; ++i) {
@ -67,8 +67,8 @@ TEST(BitVectorTest, ResizeTest) {
vector.resize(70);
ASSERT_EQ(vector.size(), 70);
ASSERT_EQ(vector.getNumberOfSetBits(), 32);
ASSERT_EQ(70, vector.size());
ASSERT_EQ(32, vector.getNumberOfSetBits());
for (uint_fast64_t i = 0; i < 32; ++i) {
ASSERT_TRUE(vector.get(i));
@ -82,8 +82,8 @@ TEST(BitVectorTest, ResizeTest) {
vector.resize(72, true);
ASSERT_EQ(vector.size(), 72);
ASSERT_EQ(vector.getNumberOfSetBits(), 34);
ASSERT_EQ(72, vector.size());
ASSERT_EQ(34, vector.getNumberOfSetBits());
for (uint_fast64_t i = 0; i < 32; ++i) {
ASSERT_TRUE(vector.get(i));
@ -98,19 +98,19 @@ TEST(BitVectorTest, ResizeTest) {
}
vector.resize(16, 0);
ASSERT_EQ(vector.size(), 16);
ASSERT_EQ(vector.getNumberOfSetBits(), 16);
ASSERT_EQ(16, vector.size());
ASSERT_EQ(16, vector.getNumberOfSetBits());
for (uint_fast64_t i = 0; i < 16; ++i) {
ASSERT_TRUE(vector.get(i));
}
vector.resize(65, 1);
ASSERT_EQ(vector.size(), 65);
ASSERT_EQ(65, vector.size());
ASSERT_TRUE(vector.full());
}
TEST(BitVectorTest, OperatorAndTest) {
TEST(BitVectorTest, OperatorAnd) {
storm::storage::BitVector vector1(32);
storm::storage::BitVector vector2(32);
@ -129,7 +129,7 @@ TEST(BitVectorTest, OperatorAndTest) {
ASSERT_TRUE(andResult.get(31));
}
TEST(BitVectorTest, OperatorAndEqualTest) {
TEST(BitVectorTest, OperatorAndEqual) {
storm::storage::BitVector vector1(32);
storm::storage::BitVector vector2(32);
@ -149,7 +149,7 @@ TEST(BitVectorTest, OperatorAndEqualTest) {
}
TEST(BitVectorTest, OperatorOrTest) {
TEST(BitVectorTest, OperatorOr) {
storm::storage::BitVector vector1(32);
storm::storage::BitVector vector2(32);
@ -168,7 +168,7 @@ TEST(BitVectorTest, OperatorOrTest) {
ASSERT_FALSE(orResult.get(31));
}
TEST(BitVectorTest, OperatorOrEqualTest) {
TEST(BitVectorTest, OperatorOrEqual) {
storm::storage::BitVector vector1(32);
storm::storage::BitVector vector2(32);
@ -187,7 +187,7 @@ TEST(BitVectorTest, OperatorOrEqualTest) {
ASSERT_FALSE(vector1.get(31));
}
TEST(BitVectorTest, OperatorXorTest) {
TEST(BitVectorTest, OperatorXor) {
storm::storage::BitVector vector1(32);
storm::storage::BitVector vector2(32);
@ -206,7 +206,7 @@ TEST(BitVectorTest, OperatorXorTest) {
}
}
TEST(BitVectorTest, OperatorModuloTest) {
TEST(BitVectorTest, OperatorModulo) {
storm::storage::BitVector vector1(32);
storm::storage::BitVector vector2(32);
@ -240,7 +240,7 @@ TEST(BitVectorTest, OperatorModuloTest) {
ASSERT_THROW(vector1 % vector3, storm::exceptions::InvalidArgumentException);
}
TEST(BitVectorTest, OperatorNotTest) {
TEST(BitVectorTest, OperatorNot) {
storm::storage::BitVector vector1(32);
storm::storage::BitVector vector2(32);
@ -256,7 +256,7 @@ TEST(BitVectorTest, OperatorNotTest) {
}
}
TEST(BitVectorTest, ComplementTest) {
TEST(BitVectorTest, Complement) {
storm::storage::BitVector vector1(32);
storm::storage::BitVector vector2(32);
@ -272,7 +272,7 @@ TEST(BitVectorTest, ComplementTest) {
}
}
TEST(BitVectorTest, ImpliesTest) {
TEST(BitVectorTest, Implies) {
storm::storage::BitVector vector1(32);
storm::storage::BitVector vector2(32, true);
@ -291,7 +291,7 @@ TEST(BitVectorTest, ImpliesTest) {
ASSERT_TRUE(impliesResult.get(31));
}
TEST(BitVectorTest, SubsetTest) {
TEST(BitVectorTest, Subset) {
storm::storage::BitVector vector1(32);
storm::storage::BitVector vector2(32, true);
@ -306,7 +306,7 @@ TEST(BitVectorTest, SubsetTest) {
ASSERT_FALSE(vector1.isSubsetOf(vector2));
}
TEST(BitVectorTest, DisjointTest) {
TEST(BitVectorTest, Disjoint) {
storm::storage::BitVector vector1(32);
storm::storage::BitVector vector2(32);
@ -322,7 +322,7 @@ TEST(BitVectorTest, DisjointTest) {
ASSERT_FALSE(vector1.isDisjointFrom(vector2));
}
TEST(BitVectorTest, EmptyTest) {
TEST(BitVectorTest, Empty) {
storm::storage::BitVector vector(32);
ASSERT_TRUE(vector.empty());
@ -337,7 +337,7 @@ TEST(BitVectorTest, EmptyTest) {
ASSERT_TRUE(vector.empty());
}
TEST(BitVectorTest, FullTest) {
TEST(BitVectorTest, Full) {
storm::storage::BitVector vector(32, true);
ASSERT_TRUE(vector.full());
@ -352,27 +352,27 @@ TEST(BitVectorTest, FullTest) {
ASSERT_TRUE(vector.full());
}
TEST(BitVectorTest, NumberOfSetBitsTest) {
TEST(BitVectorTest, NumberOfSetBits) {
storm::storage::BitVector vector(32);
for (uint_fast64_t i = 0; i < 32; ++i) {
vector.set(i, i % 2 == 0);
}
ASSERT_EQ(vector.getNumberOfSetBits(), 16);
ASSERT_EQ(16, vector.getNumberOfSetBits());
}
TEST(BitVectorTest, NumberOfSetBitsBeforeIndexTest) {
TEST(BitVectorTest, NumberOfSetBitsBeforeIndex) {
storm::storage::BitVector vector(32);
for (uint_fast64_t i = 0; i < 32; ++i) {
vector.set(i, i % 2 == 0);
}
ASSERT_EQ(vector.getNumberOfSetBitsBeforeIndex(14), 7);
ASSERT_EQ(7, vector.getNumberOfSetBitsBeforeIndex(14));
}
TEST(BitVectorTest, BeginEndTest) {
TEST(BitVectorTest, BeginEnd) {
storm::storage::BitVector vector(32);
ASSERT_TRUE(vector.begin() == vector.end());
@ -386,20 +386,20 @@ TEST(BitVectorTest, BeginEndTest) {
ASSERT_TRUE(vector.begin() == vector.end());
}
TEST(BitVectorTest, NextSetIndexTest) {
TEST(BitVectorTest, NextSetIndex) {
storm::storage::BitVector vector(32);
vector.set(14);
vector.set(17);
ASSERT_EQ(vector.getNextSetIndex(14), 14);
ASSERT_EQ(vector.getNextSetIndex(15), 17);
ASSERT_EQ(vector.getNextSetIndex(16), 17);
ASSERT_EQ(vector.getNextSetIndex(17), 17);
ASSERT_EQ(vector.getNextSetIndex(18), vector.size());
ASSERT_EQ(14, vector.getNextSetIndex(14));
ASSERT_EQ(17, vector.getNextSetIndex(15));
ASSERT_EQ(17, vector.getNextSetIndex(16));
ASSERT_EQ(17, vector.getNextSetIndex(17));
ASSERT_EQ(vector.size(), vector.getNextSetIndex(18));
}
TEST(BitVectorTest, IteratorTest) {
TEST(BitVectorTest, Iterator) {
storm::storage::BitVector vector(32);
for (uint_fast64_t i = 0; i < 32; ++i) {

569
test/functional/storage/SparseMatrixTest.cpp

@ -0,0 +1,569 @@
#include "gtest/gtest.h"
#include "src/storage/SparseMatrix.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "src/exceptions/OutOfRangeException.h"
TEST(SparseMatrix, SimpleCreation) {
ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix);
ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix(3));
ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix(3, 4));
ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix(3, 4, 5));
}
TEST(SparseMatrix, CreationWithMovingContents) {
ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, {1, 2, 0, 1, 3}, {1.0, 1.2, 0.5, 0.7, 0.2}));
storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, {1, 2, 0, 1, 3}, {1.0, 1.2, 0.5, 0.7, 0.2});
ASSERT_EQ(3, matrix.getRowCount());
ASSERT_EQ(4, matrix.getColumnCount());
ASSERT_EQ(5, matrix.getEntryCount());
}
TEST(SparseMatrix, CreationWithDimensions) {
storm::storage::SparseMatrix<double> matrix(3, 4, 5);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(1, 3, 0.2));
ASSERT_NO_THROW(matrix.finalize());
ASSERT_EQ(3, matrix.getRowCount());
ASSERT_EQ(4, matrix.getColumnCount());
ASSERT_EQ(5, matrix.getEntryCount());
}
TEST(SparseMatrix, CreationWithoutNumberOfEntries) {
storm::storage::SparseMatrix<double> matrix(3, 4);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(1, 3, 0.2));
ASSERT_NO_THROW(matrix.finalize());
ASSERT_EQ(3, matrix.getRowCount());
ASSERT_EQ(4, matrix.getColumnCount());
ASSERT_EQ(5, matrix.getEntryCount());
}
TEST(SparseMatrix, CreationWithNumberOfRows) {
storm::storage::SparseMatrix<double> matrix(3);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(1, 3, 0.2));
ASSERT_NO_THROW(matrix.finalize());
ASSERT_EQ(3, matrix.getRowCount());
ASSERT_EQ(4, matrix.getColumnCount());
ASSERT_EQ(5, matrix.getEntryCount());
}
TEST(SparseMatrix, CreationWithoutDimensions) {
storm::storage::SparseMatrix<double> matrix;
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(1, 3, 0.2));
ASSERT_NO_THROW(matrix.finalize());
ASSERT_EQ(2, matrix.getRowCount());
ASSERT_EQ(4, matrix.getColumnCount());
ASSERT_EQ(5, matrix.getEntryCount());
}
TEST(SparseMatrix, CopyConstruct) {
storm::storage::SparseMatrix<double> matrix;
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(1, 3, 0.2));
ASSERT_NO_THROW(matrix.finalize());
ASSERT_NO_THROW(storm::storage::SparseMatrix<double> copy(matrix));
storm::storage::SparseMatrix<double> copy(matrix);
ASSERT_TRUE(matrix == copy);
}
TEST(SparseMatrix, CopyAssign) {
storm::storage::SparseMatrix<double> matrix;
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(1, 3, 0.2));
ASSERT_NO_THROW(matrix.finalize());
ASSERT_NO_THROW(storm::storage::SparseMatrix<double> copy = matrix);
storm::storage::SparseMatrix<double> copy = matrix;
ASSERT_TRUE(matrix == copy);
}
TEST(SparseMatrix, AddNextValue) {
storm::storage::SparseMatrix<double> matrix(3, 4, 5);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_THROW(matrix.addNextValue(0, 4, 0.5), storm::exceptions::OutOfRangeException);
ASSERT_THROW(matrix.addNextValue(3, 1, 0.5), storm::exceptions::OutOfRangeException);
storm::storage::SparseMatrix<double> matrix2(3, 4);
ASSERT_NO_THROW(matrix2.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix2.addNextValue(0, 2, 1.2));
ASSERT_THROW(matrix2.addNextValue(0, 4, 0.5), storm::exceptions::OutOfRangeException);
ASSERT_THROW(matrix.addNextValue(3, 1, 0.5), storm::exceptions::OutOfRangeException);
storm::storage::SparseMatrix<double> matrix3(3);
ASSERT_NO_THROW(matrix3.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix3.addNextValue(1, 2, 1.2));
ASSERT_NO_THROW(matrix3.addNextValue(2, 4, 0.5));
ASSERT_THROW(matrix3.addNextValue(3, 1, 0.2), storm::exceptions::OutOfRangeException);
storm::storage::SparseMatrix<double> matrix4;
ASSERT_NO_THROW(matrix4.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix4.addNextValue(1, 2, 1.2));
ASSERT_NO_THROW(matrix4.addNextValue(2, 4, 0.5));
ASSERT_NO_THROW(matrix4.addNextValue(3, 1, 0.2));
}
TEST(SparseMatrix, Finalize) {
storm::storage::SparseMatrix<double> matrix(3, 4, 5);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(1, 3, 0.2));
ASSERT_FALSE(matrix.isInitialized());
ASSERT_NO_THROW(matrix.finalize());
ASSERT_TRUE(matrix.isInitialized());
storm::storage::SparseMatrix<double> matrix2(3, 4, 5);
ASSERT_NO_THROW(matrix2.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix2.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix2.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix2.addNextValue(1, 1, 0.7));
ASSERT_THROW(matrix2.finalize(), storm::exceptions::InvalidStateException);
storm::storage::SparseMatrix<double> matrix3;
ASSERT_NO_THROW(matrix3.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix3.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix3.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix3.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix3.addNextValue(1, 3, 0.2));
ASSERT_NO_THROW(matrix3.finalize());
ASSERT_EQ(2, matrix3.getRowCount());
ASSERT_EQ(4, matrix3.getColumnCount());
ASSERT_EQ(5, matrix3.getEntryCount());
storm::storage::SparseMatrix<double> matrix4;
ASSERT_NO_THROW(matrix4.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix4.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix4.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix4.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix4.addNextValue(1, 3, 0.2));
ASSERT_NO_THROW(matrix4.finalize(4));
ASSERT_EQ(4, matrix4.getRowCount());
ASSERT_EQ(4, matrix4.getColumnCount());
ASSERT_EQ(5, matrix4.getEntryCount());
storm::storage::SparseMatrix<double> matrix5;
ASSERT_NO_THROW(matrix5.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix5.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix5.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix5.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix5.addNextValue(1, 3, 0.2));
ASSERT_NO_THROW(matrix5.finalize(0, 6));
ASSERT_EQ(2, matrix5.getRowCount());
ASSERT_EQ(6, matrix5.getColumnCount());
ASSERT_EQ(5, matrix5.getEntryCount());
}
TEST(SparseMatrix, MakeAbsorbing) {
storm::storage::SparseMatrix<double> matrix(3, 4, 5);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(1, 3, 0.2));
ASSERT_NO_THROW(matrix.finalize());
storm::storage::BitVector absorbingRows(3);
absorbingRows.set(1);
ASSERT_NO_THROW(matrix.makeRowsAbsorbing(absorbingRows));
storm::storage::SparseMatrix<double> matrix2(3, 4, 3);
ASSERT_NO_THROW(matrix2.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix2.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix2.addNextValue(1, 1, 1));
ASSERT_NO_THROW(matrix2.finalize());
ASSERT_TRUE(matrix == matrix2);
}
TEST(SparseMatrix, MakeRowGroupAbsorbing) {
storm::storage::SparseMatrix<double> matrix(5, 4, 9);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(2, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(3, 2, 1.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 0, 0.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 1, 0.2));
ASSERT_NO_THROW(matrix.addNextValue(4, 3, 0.3));
ASSERT_NO_THROW(matrix.finalize());
std::vector<uint_fast64_t> rowGroupIndices = {0, 2, 4, 5};
storm::storage::BitVector absorbingRowGroups(3);
absorbingRowGroups.set(1);
ASSERT_NO_THROW(matrix.makeRowsAbsorbing(absorbingRowGroups, rowGroupIndices));
storm::storage::SparseMatrix<double> matrix2;
ASSERT_NO_THROW(matrix2.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix2.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix2.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix2.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix2.addNextValue(2, 1, 1));
ASSERT_NO_THROW(matrix2.addNextValue(3, 1, 1));
ASSERT_NO_THROW(matrix2.addNextValue(4, 0, 0.1));
ASSERT_NO_THROW(matrix2.addNextValue(4, 1, 0.2));
ASSERT_NO_THROW(matrix2.addNextValue(4, 3, 0.3));
ASSERT_NO_THROW(matrix2.finalize());
ASSERT_TRUE(matrix == matrix2);
}
TEST(SparseMatrix, ConstrainedRowSumVector) {
storm::storage::SparseMatrix<double> matrix(5, 4, 9);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(2, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(3, 2, 1.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 0, 0.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 1, 0.2));
ASSERT_NO_THROW(matrix.addNextValue(4, 3, 0.3));
ASSERT_NO_THROW(matrix.finalize());
storm::storage::BitVector columnConstraint(4);
columnConstraint.set(1);
columnConstraint.set(3);
ASSERT_NO_THROW(std::vector<double> constrainedRowSum = matrix.getConstrainedRowSumVector(storm::storage::BitVector(5, true), columnConstraint));
std::vector<double> constrainedRowSum = matrix.getConstrainedRowSumVector(storm::storage::BitVector(5, true), columnConstraint);
ASSERT_TRUE(constrainedRowSum == std::vector<double>({1.0, 0.7, 0, 0, 0.5}));
storm::storage::SparseMatrix<double> matrix2(5, 4, 9);
ASSERT_NO_THROW(matrix2.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix2.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix2.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix2.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix2.addNextValue(2, 0, 0.5));
ASSERT_NO_THROW(matrix2.addNextValue(3, 2, 1.1));
ASSERT_NO_THROW(matrix2.addNextValue(3, 3, 1.2));
ASSERT_NO_THROW(matrix2.addNextValue(4, 0, 0.1));
ASSERT_NO_THROW(matrix2.addNextValue(4, 3, 0.3));
ASSERT_NO_THROW(matrix2.finalize());
std::vector<uint_fast64_t> rowGroupIndices = {0, 2, 4, 5};
storm::storage::BitVector rowGroupConstraint(3);
rowGroupConstraint.set(1);
storm::storage::BitVector columnConstraint2(4);
columnConstraint2.set(2);
columnConstraint2.set(3);
ASSERT_NO_THROW(std::vector<double> constrainedRowSum2 = matrix2.getConstrainedRowSumVector(rowGroupConstraint, rowGroupIndices, columnConstraint2));
std::vector<double> constrainedRowSum2 = matrix2.getConstrainedRowSumVector(rowGroupConstraint, rowGroupIndices, columnConstraint2);
ASSERT_TRUE(constrainedRowSum2 == std::vector<double>({0, 2.3}));
}
TEST(SparseMatrix, Submatrix) {
storm::storage::SparseMatrix<double> matrix(5, 4, 9);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(2, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(3, 2, 1.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 0, 0.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 1, 0.2));
ASSERT_NO_THROW(matrix.addNextValue(4, 3, 0.3));
ASSERT_NO_THROW(matrix.finalize());
std::vector<uint_fast64_t> rowGroupIndices = {0, 1, 2, 4, 5};
storm::storage::BitVector rowGroupConstraint(4);
rowGroupConstraint.set(2);
rowGroupConstraint.set(3);
storm::storage::BitVector columnConstraint(4);
columnConstraint.set(0);
columnConstraint.set(3);
ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix2 = matrix.getSubmatrix(rowGroupConstraint, columnConstraint, rowGroupIndices, false));
storm::storage::SparseMatrix<double> matrix2 = matrix.getSubmatrix(rowGroupConstraint, columnConstraint, rowGroupIndices, false);
storm::storage::SparseMatrix<double> matrix3(3, 2, 3);
ASSERT_NO_THROW(matrix3.addNextValue(0, 0, 0.5));
ASSERT_NO_THROW(matrix3.addNextValue(2, 0, 0.1));
ASSERT_NO_THROW(matrix3.addNextValue(2, 1, 0.3));
ASSERT_NO_THROW(matrix3.finalize());
ASSERT_TRUE(matrix2 == matrix3);
std::vector<uint_fast64_t> rowGroupToIndexMapping = {0, 0, 1, 0};
ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix4 = matrix.getSubmatrix(rowGroupToIndexMapping, rowGroupIndices));
storm::storage::SparseMatrix<double> matrix4 = matrix.getSubmatrix(rowGroupToIndexMapping, rowGroupIndices);
storm::storage::SparseMatrix<double> matrix5(4, 4, 8);
ASSERT_NO_THROW(matrix5.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix5.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix5.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix5.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix5.addNextValue(2, 2, 1.1));
ASSERT_NO_THROW(matrix5.addNextValue(3, 0, 0.1));
ASSERT_NO_THROW(matrix5.addNextValue(3, 1, 0.2));
ASSERT_NO_THROW(matrix5.addNextValue(3, 3, 0.3));
ASSERT_NO_THROW(matrix5.finalize());
ASSERT_TRUE(matrix4 == matrix5);
}
TEST(SparseMatrix, Transpose) {
storm::storage::SparseMatrix<double> matrix(5, 4, 9);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(2, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(3, 2, 1.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 0, 0.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 1, 0.2));
ASSERT_NO_THROW(matrix.addNextValue(4, 3, 0.3));
ASSERT_NO_THROW(matrix.finalize());
ASSERT_NO_THROW(storm::storage::SparseMatrix<double> transposeResult = matrix.transpose());
storm::storage::SparseMatrix<double> transposeResult = matrix.transpose();
storm::storage::SparseMatrix<double> matrix2(4, 5, 9);
ASSERT_NO_THROW(matrix2.addNextValue(0, 1, 0.5));
ASSERT_NO_THROW(matrix2.addNextValue(0, 2, 0.5));
ASSERT_NO_THROW(matrix2.addNextValue(0, 4, 0.1));
ASSERT_NO_THROW(matrix2.addNextValue(1, 0, 1.0));
ASSERT_NO_THROW(matrix2.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix2.addNextValue(1, 4, 0.2));
ASSERT_NO_THROW(matrix2.addNextValue(2, 0, 1.2));
ASSERT_NO_THROW(matrix2.addNextValue(2, 3, 1.1));
ASSERT_NO_THROW(matrix2.addNextValue(3, 4, 0.3));
ASSERT_NO_THROW(matrix2.finalize());
ASSERT_TRUE(transposeResult == matrix2);
}
TEST(SparseMatrix, EquationSystem) {
storm::storage::SparseMatrix<double> matrix(4, 4, 7);
ASSERT_NO_THROW(matrix.addNextValue(0, 0, 1.1));
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 3, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(2, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(2, 2, 0.99));
ASSERT_NO_THROW(matrix.addNextValue(3, 3, 0.11));
ASSERT_NO_THROW(matrix.finalize());
ASSERT_NO_THROW(matrix.convertToEquationSystem());
storm::storage::SparseMatrix<double> matrix2(4, 4, 7);
ASSERT_NO_THROW(matrix2.addNextValue(0, 0, 1 - 1.1));
ASSERT_NO_THROW(matrix2.addNextValue(0, 1, -1.2));
ASSERT_NO_THROW(matrix2.addNextValue(1, 1, 1 - 0.5));
ASSERT_NO_THROW(matrix2.addNextValue(1, 3, -0.7));
ASSERT_NO_THROW(matrix2.addNextValue(2, 0, -0.5));
ASSERT_NO_THROW(matrix2.addNextValue(2, 2, 1 - 0.99));
ASSERT_NO_THROW(matrix2.addNextValue(3, 3, 1 - 0.11));
ASSERT_NO_THROW(matrix2.finalize());
ASSERT_TRUE(matrix == matrix2);
}
TEST(SparseMatrix, JacobiDecomposition) {
storm::storage::SparseMatrix<double> matrix(4, 4, 7);
ASSERT_NO_THROW(matrix.addNextValue(0, 0, 1.1));
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 3, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(2, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(2, 2, 0.99));
ASSERT_NO_THROW(matrix.addNextValue(3, 3, 0.11));
ASSERT_NO_THROW(matrix.finalize());
ASSERT_NO_THROW(matrix.getJacobiDecomposition());
std::pair<storm::storage::SparseMatrix<double>, storm::storage::SparseMatrix<double>> jacobiDecomposition = matrix.getJacobiDecomposition();
storm::storage::SparseMatrix<double> LU(4, 4, 3);
ASSERT_NO_THROW(LU.addNextValue(0, 1, 1.2));
ASSERT_NO_THROW(LU.addNextValue(1, 3, 0.7));
ASSERT_NO_THROW(LU.addNextValue(2, 0, 0.5));
ASSERT_NO_THROW(LU.finalize());
storm::storage::SparseMatrix<double> Dinv(4, 4, 4);
ASSERT_NO_THROW(Dinv.addNextValue(0, 0, 1 / 1.1));
ASSERT_NO_THROW(Dinv.addNextValue(1, 1, 1 / 0.5));
ASSERT_NO_THROW(Dinv.addNextValue(2, 2, 1 / 0.99));
ASSERT_NO_THROW(Dinv.addNextValue(3, 3, 1 / 0.11));
ASSERT_NO_THROW(Dinv.finalize());
ASSERT_TRUE(LU == jacobiDecomposition.first);
ASSERT_TRUE(Dinv == jacobiDecomposition.second);
}
TEST(SparseMatrix, PointwiseMultiplicationVector) {
storm::storage::SparseMatrix<double> matrix(5, 4, 9);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(2, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(3, 2, 1.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 0, 0.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 1, 0.2));
ASSERT_NO_THROW(matrix.addNextValue(4, 3, 0.3));
ASSERT_NO_THROW(matrix.finalize());
storm::storage::SparseMatrix<double> matrix2(5, 4, 9);
ASSERT_NO_THROW(matrix2.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix2.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix2.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix2.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix2.addNextValue(2, 0, 0.5));
ASSERT_NO_THROW(matrix2.addNextValue(3, 2, 1.1));
ASSERT_NO_THROW(matrix2.addNextValue(4, 0, 0.1));
ASSERT_NO_THROW(matrix2.addNextValue(4, 1, 0.2));
ASSERT_NO_THROW(matrix2.addNextValue(4, 3, 0.3));
ASSERT_NO_THROW(matrix2.finalize());
ASSERT_NO_THROW(std::vector<double> pointwiseProductRowSums = matrix.getPointwiseProductRowSumVector(matrix2));
std::vector<double> pointwiseProductRowSums = matrix.getPointwiseProductRowSumVector(matrix2);
std::vector<double> correctResult = {1.0*1.0+1.2*1.2, 0.5*0.5+0.7*0.7, 0.5*0.5, 1.1*1.1, 0.1*0.1+0.2*0.2+0.3*0.3};
ASSERT_TRUE(pointwiseProductRowSums == correctResult);
}
TEST(SparseMatrix, MatrixVectorMultiply) {
storm::storage::SparseMatrix<double> matrix(5, 4, 9);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(2, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(3, 2, 1.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 0, 0.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 1, 0.2));
ASSERT_NO_THROW(matrix.addNextValue(4, 3, 0.3));
ASSERT_NO_THROW(matrix.finalize());
std::vector<double> x = {1, 0.3, 1.4, 7.1};
std::vector<double> result(matrix.getRowCount());
ASSERT_NO_THROW(matrix.multiplyWithVector(x, result));
std::vector<double> correctResult = {1.0*0.3+1.2*1.4, 0.5*1+0.7*0.3, 0.5*1, 1.1*1.4, 0.1*1+0.2*0.3+0.3*7.1};
ASSERT_TRUE(result == correctResult);
}
TEST(SparseMatrix, Iteration) {
storm::storage::SparseMatrix<double> matrix(5, 4, 9);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(2, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(3, 2, 1.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 0, 0.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 1, 0.2));
ASSERT_NO_THROW(matrix.addNextValue(4, 3, 0.3));
ASSERT_NO_THROW(matrix.finalize());
for (auto const& entry : matrix.getRow(4)) {
if (entry.column() == 0) {
ASSERT_EQ(0.1, entry.value());
} else if (entry.column() == 1) {
ASSERT_EQ(0.2, entry.value());
} else if (entry.column() == 3) {
ASSERT_EQ(0.3, entry.value());
} else {
ASSERT_TRUE(false);
}
}
for (storm::storage::SparseMatrix<double>::iterator it = matrix.begin(4), ite = matrix.end(4); it != ite; ++it) {
if (it.column() == 0) {
ASSERT_EQ(0.1, it.value());
} else if (it.column() == 1) {
ASSERT_EQ(0.2, it.value());
} else if (it.column() == 3) {
ASSERT_EQ(0.3, it.value());
} else {
ASSERT_TRUE(false);
}
}
}
TEST(SparseMatrix, RowSum) {
storm::storage::SparseMatrix<double> matrix(5, 4, 8);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(3, 2, 1.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 0, 0.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 1, 0.2));
ASSERT_NO_THROW(matrix.addNextValue(4, 3, 0.3));
ASSERT_NO_THROW(matrix.finalize());
ASSERT_EQ(0, matrix.getRowSum(2));
ASSERT_EQ(0.1+0.2+0.3, matrix.getRowSum(4));
}
TEST(SparseMatrix, IsSubmatrix) {
storm::storage::SparseMatrix<double> matrix(5, 4, 8);
ASSERT_NO_THROW(matrix.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix.addNextValue(0, 2, 1.2));
ASSERT_NO_THROW(matrix.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix.addNextValue(3, 2, 1.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 0, 0.1));
ASSERT_NO_THROW(matrix.addNextValue(4, 1, 0.2));
ASSERT_NO_THROW(matrix.addNextValue(4, 3, 0.3));
ASSERT_NO_THROW(matrix.finalize());
storm::storage::SparseMatrix<double> matrix2(5, 4, 5);
ASSERT_NO_THROW(matrix2.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(matrix2.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix2.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix2.addNextValue(4, 0, 0.1));
ASSERT_NO_THROW(matrix2.addNextValue(4, 1, 0.2));
ASSERT_NO_THROW(matrix2.finalize());
ASSERT_TRUE(matrix2.isSubmatrixOf(matrix));
storm::storage::SparseMatrix<double> matrix3(5, 4, 5);
ASSERT_NO_THROW(matrix3.addNextValue(0, 3, 1.0));
ASSERT_NO_THROW(matrix3.addNextValue(1, 0, 0.5));
ASSERT_NO_THROW(matrix3.addNextValue(1, 1, 0.7));
ASSERT_NO_THROW(matrix3.addNextValue(4, 0, 0.1));
ASSERT_NO_THROW(matrix3.addNextValue(4, 1, 0.2));
ASSERT_NO_THROW(matrix3.finalize());
ASSERT_FALSE(matrix3.isSubmatrixOf(matrix));
ASSERT_FALSE(matrix3.isSubmatrixOf(matrix2));
}

2
test/performance/storage/BitVectorTest.cpp

@ -1,7 +1,7 @@
#include "gtest/gtest.h"
#include "src/storage/BitVector.h"
TEST(BitVectorTest, IterationTest) {
TEST(BitVectorTest, Iteration) {
storm::storage::BitVector vector(819200, true);
for (uint_fast64_t i = 0; i < 10000; ++i) {

43
test/performance/storage/SparseMatrixTest.cpp

@ -0,0 +1,43 @@
#include "gtest/gtest.h"
#include "src/storage/SparseMatrix.h"
TEST(SparseMatrix, Iteration) {
storm::storage::SparseMatrix<double> matrix;
for (uint_fast64_t row = 0; row < 10000; ++row) {
for (uint_fast64_t column = 0; column < row; ++column) {
ASSERT_NO_THROW(matrix.addNextValue(row, column, row+column));
}
}
ASSERT_NO_THROW(matrix.finalize());
for (uint_fast64_t row = 0; row < matrix.getRowCount(); ++row) {
for (auto const& entry : matrix.getRow(row)) {
// The following can never be true, but prevents the compiler from optimizing away the loop.
if (entry.column() > matrix.getColumnCount()) {
ASSERT_TRUE(false);
}
}
}
}
TEST(SparseMatrix, Multiplication) {
storm::storage::SparseMatrix<double> matrix;
for (uint_fast64_t row = 0; row < 2000; ++row) {
for (uint_fast64_t column = 0; column < row; ++column) {
ASSERT_NO_THROW(matrix.addNextValue(row, column, row+column));
}
}
ASSERT_NO_THROW(matrix.finalize());
std::vector<double> x(matrix.getColumnCount(), 1.0);
std::vector<double> result(matrix.getRowCount());
for (uint_fast64_t i = 0; i < 5000; ++i) {
matrix.multiplyWithVector(x, result);
// The following can never be true, but prevents the compiler from optimizing away the loop.
if (result.size() > matrix.getRowCount()) {
ASSERT_TRUE(false);
}
}
}
Loading…
Cancel
Save