diff --git a/src/storage/SparseMatrix.cpp b/src/storage/SparseMatrix.cpp index 0a10291d2..f0185eb9a 100644 --- a/src/storage/SparseMatrix.cpp +++ b/src/storage/SparseMatrix.cpp @@ -9,109 +9,49 @@ extern log4cplus::Logger logger; namespace storm { namespace storage { - - template - template - SparseMatrix::BaseIterator::BaseIterator(ValueType* valuePtr, uint_fast64_t const* columnPtr) : valuePtr(valuePtr), columnPtr(columnPtr) { - // Intentionally left empty. - } - - template - template - SparseMatrix::BaseIterator::BaseIterator(SparseMatrix::BaseIterator const& other) : valuePtr(other.valuePtr), columnPtr(other.columnPtr) { - // Intentionally left empty. - } - - template - template - typename SparseMatrix::template BaseIterator& SparseMatrix::BaseIterator::operator=(BaseIterator const& other) { - if (this != &other) { - valuePtr = other.valuePtr, - columnPtr = other.columnPtr; - } - return *this; - } - - template - template - SparseMatrix::BaseIterator& SparseMatrix::BaseIterator::operator++() { - this->valuePtr++; - this->columnPtr++; - return *this; - } - - template - template - SparseMatrix::BaseIterator& SparseMatrix::BaseIterator::operator*() { - return *this; - } - - template - template - bool SparseMatrix::BaseIterator::operator!=(BaseIterator const& other) const { - return this->valuePtr != other.valuePtr; - } - - template - template - bool SparseMatrix::BaseIterator::operator==(BaseIterator const& other) const { - return this->valuePtr == other.valuePtr; - } - - template - template - uint_fast64_t SparseMatrix::BaseIterator::column() const { - return *columnPtr; - } - - template - template - ValueType& SparseMatrix::BaseIterator::value() const { - return *valuePtr; - } - + template - SparseMatrix::rows::rows(T* valuePtr, uint_fast64_t const* columnPtr, uint_fast64_t entryCount) : valuePtr(valuePtr), columnPtr(columnPtr), entryCount(entryCount) { + SparseMatrix::rows::rows(std::pair* columnAndValuePtr, uint_fast64_t entryCount) : columnAndValuePtr(columnAndValuePtr), entryCount(entryCount) { // Intentionally left empty. } template typename SparseMatrix::iterator SparseMatrix::rows::begin() { - return iterator(valuePtr, columnPtr); + return columnAndValuePtr; } template typename SparseMatrix::iterator SparseMatrix::rows::end() { - return iterator(valuePtr + entryCount, columnPtr + entryCount); + return columnAndValuePtr + entryCount; } template - SparseMatrix::const_rows::const_rows(T const* valuePtr, uint_fast64_t const* columnPtr, uint_fast64_t entryCount) : valuePtr(valuePtr), columnPtr(columnPtr), entryCount(entryCount) { + SparseMatrix::const_rows::const_rows(std::pair const* columnAndValuePtr, uint_fast64_t entryCount) : columnAndValuePtr(columnAndValuePtr), entryCount(entryCount) { // Intentionally left empty. } template typename SparseMatrix::const_iterator SparseMatrix::const_rows::begin() const { - return const_iterator(valuePtr, columnPtr); + return columnAndValuePtr; } template typename SparseMatrix::const_iterator SparseMatrix::const_rows::end() const { - return const_iterator(valuePtr + entryCount, columnPtr + entryCount); + return columnAndValuePtr + entryCount; } template - SparseMatrix::SparseMatrix(uint_fast64_t rows, uint_fast64_t columns, uint_fast64_t entries) : rowCountSet(rows != 0), rowCount(rows), columnCountSet(columns != 0), columnCount(columns), entryCount(entries), storagePreallocated(rows != 0 && columns != 0 && entries != 0), valueStorage(), columnIndications(), rowIndications(), internalStatus(UNINITIALIZED), currentEntryCount(0), lastRow(0), lastColumn(0) { + SparseMatrix::SparseMatrix(uint_fast64_t rows, uint_fast64_t columns, uint_fast64_t entries) : rowCountSet(rows != 0), rowCount(rows), columnCountSet(columns != 0), columnCount(columns), entryCount(entries), storagePreallocated(rows != 0 && columns != 0 && entries != 0), columnsAndValues(), rowIndications(), internalStatus(UNINITIALIZED), currentEntryCount(0), lastRow(0), lastColumn(0) { prepareInternalStorage(); } template - SparseMatrix::SparseMatrix(SparseMatrix const& other) : rowCountSet(other.rowCountSet), rowCount(other.rowCount), columnCountSet(other.columnCountSet), columnCount(other.columnCount), entryCount(other.entryCount), storagePreallocated(other.storagePreallocated), valueStorage(other.valueStorage), columnIndications(other.columnIndications), rowIndications(other.rowIndications), internalStatus(other.internalStatus), currentEntryCount(other.currentEntryCount), lastRow(other.lastRow), lastColumn(other.lastColumn) { + SparseMatrix::SparseMatrix(SparseMatrix const& other) : rowCountSet(other.rowCountSet), rowCount(other.rowCount), columnCountSet(other.columnCountSet), columnCount(other.columnCount), entryCount(other.entryCount), storagePreallocated(other.storagePreallocated), columnsAndValues(other.columnsAndValues), rowIndications(other.rowIndications), internalStatus(other.internalStatus), currentEntryCount(other.currentEntryCount), lastRow(other.lastRow), lastColumn(other.lastColumn) { // Intentionally left empty. } template - SparseMatrix::SparseMatrix(SparseMatrix&& other) : rowCountSet(other.rowCountSet), rowCount(other.rowCount), columnCountSet(other.columnCountSet), columnCount(other.columnCount), entryCount(other.entryCount), storagePreallocated(other.storagePreallocated), valueStorage(std::move(other.valueStorage)), columnIndications(std::move(other.columnIndications)), rowIndications(std::move(other.rowIndications)), internalStatus(other.internalStatus), currentEntryCount(other.currentEntryCount), lastRow(other.lastRow), lastColumn(other.lastColumn) { + SparseMatrix::SparseMatrix(SparseMatrix&& other) : rowCountSet(other.rowCountSet), rowCount(other.rowCount), columnCountSet(other.columnCountSet), columnCount(other.columnCount), entryCount(other.entryCount), storagePreallocated(other.storagePreallocated), columnsAndValues(std::move(other.columnsAndValues)), rowIndications(std::move(other.rowIndications)), internalStatus(other.internalStatus), currentEntryCount(other.currentEntryCount), lastRow(other.lastRow), lastColumn(other.lastColumn) { // Now update the source matrix other.rowCountSet = false; other.rowCount = 0; @@ -126,15 +66,47 @@ namespace storm { } template - SparseMatrix::SparseMatrix(uint_fast64_t columnCount, std::vector const& rowIndications, std::vector const& columnIndications, std::vector const& values) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(values.size()), valueStorage(values), columnIndications(columnIndications), rowIndications(rowIndications), internalStatus(INITIALIZED), currentEntryCount(0), lastRow(0), lastColumn(0) { + SparseMatrix::SparseMatrix(uint_fast64_t columnCount, std::vector const& rowIndications, std::vector> const& columnsAndValues) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(values.size()), storagePreallocated(true), columnsAndValues(columnsAndValues), rowIndications(rowIndications), internalStatus(INITIALIZED), currentEntryCount(0), lastRow(0), lastColumn(0) { // Intentionally left empty. } template - SparseMatrix::SparseMatrix(uint_fast64_t columnCount, std::vector&& rowIndications, std::vector&& columnIndications, std::vector&& values) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(values.size()), valueStorage(std::move(values)), columnIndications(std::move(columnIndications)), rowIndications(std::move(rowIndications)), internalStatus(INITIALIZED), currentEntryCount(0), lastRow(0), lastColumn(0) { + SparseMatrix::SparseMatrix(uint_fast64_t columnCount, std::vector const& rowIndications, std::vector const& columnIndications, std::vector const& values) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(values.size()), storagePreallocated(true), columnsAndValues(), rowIndications(rowIndications), internalStatus(INITIALIZED), currentEntryCount(0), lastRow(0), lastColumn(0) { + if (columnIndications.size() != values.size()) { + throw storm::exceptions::InvalidArgumentException() << "Illegal call to SparseMatrix::SparseMatrix: value and column vector length mismatch."; + } + + // Preserve enough storage to avoid reallocations. + columnsAndValues.reserve(values.size()); + + // Now zip the two vectors for columns and values. + typename std::vector::const_iterator columnIt = columnIndications.begin(); + for (typename std::vector::const_iterator valueIt = values.begin(), valueIte = values.end(); valueIt != valueIte; ++valueIt, ++columnIt) { + columnsAndValues.emplace_back(*columnIt, *valueIt); + } + } + + template + SparseMatrix::SparseMatrix(uint_fast64_t columnCount, std::vector&& rowIndications, std::vector>&& columnsAndValues) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(values.size()), storagePreallocated(true), columnsAndValues(std::move(columnsAndValues)), rowIndications(std::move(rowIndications)), internalStatus(INITIALIZED), currentEntryCount(0), lastRow(0), lastColumn(0) { // Intentionally left empty. } + template + SparseMatrix::SparseMatrix(uint_fast64_t columnCount, std::vector&& rowIndications, std::vector&& columnIndications, std::vector&& values) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(values.size()), columnsAndValues(), rowIndications(std::move(rowIndications)), internalStatus(INITIALIZED), currentEntryCount(0), lastRow(0), lastColumn(0) { + if (columnIndications.size() != values.size()) { + throw storm::exceptions::InvalidArgumentException() << "Illegal call to SparseMatrix::SparseMatrix: value and column vector length mismatch."; + } + + // Preserve enough storage to avoid reallocations. + columnsAndValues.reserve(values.size()); + + // Now zip the two vectors for columns and values. + typename std::vector::const_iterator columnIt = columnIndications.begin(); + for (typename std::vector::const_iterator valueIt = values.begin(), valueIte = values.end(); valueIt != valueIte; ++valueIt, ++columnIt) { + columnsAndValues.emplace_back(*columnIt, *valueIt); + } + } + template SparseMatrix& SparseMatrix::operator=(SparseMatrix const& other) { // Only perform assignment if source and target are not the same. @@ -145,8 +117,7 @@ namespace storm { columnCount = other.columnCount; entryCount = other.entryCount; - valueStorage = other.valueStorage; - columnIndications = other.columnIndications; + columnsAndValues = other.columnsAndValues; rowIndications = other.rowIndications; internalStatus = other.internalStatus; @@ -168,8 +139,7 @@ namespace storm { columnCount = other.columnCount; entryCount = other.entryCount; - valueStorage = std::move(other.valueStorage); - columnIndications = std::move(other.columnIndications); + columnsAndValues = std::move(other.columnsAndValues); rowIndications = std::move(other.rowIndications); internalStatus = other.internalStatus; @@ -209,17 +179,22 @@ namespace storm { // 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) { + for (const_iterator it1 = this->begin(row), ite1 = this->end(row), it2 = other.begin(row), ite2 = other.end(row); it1 != ite1 && it2 != ite2; ++it1, ++it2) { // Skip over all zero entries in both matrices. - while (elem < rowIndications[row + 1] && valueStorage[elem] == storm::utility::constantZero()) { - ++elem; + while (it1 != ite1 && it1->second == storm::utility::constantZero()) { + ++it1; } - while (elem2 < other.rowIndications[row + 1] && other.valueStorage[elem2] == storm::utility::constantZero()) { - ++elem2; + while (it2 != ite2 && it2->second == storm::utility::constantZero()) { + ++it2; } - if ((elem == rowIndications[row + 1]) ^ (elem2 == other.rowIndications[row + 1]) || columnIndications[elem] != other.columnIndications[elem2] || valueStorage[elem] != other.valueStorage[elem2]) { - equalityResult = false; + if ((it1 == ite1) || (it2 == ite2)) { + equalityResult = (it1 == ite1) ^ (it2 == ite2); break; + } else { + if (it1->first != it2->first || it1->second != it2->second) { + equalityResult = false; + break; + } } } } @@ -284,11 +259,9 @@ namespace storm { // Finally, set the element and increase the current size. if (storagePreallocated) { - valueStorage[currentEntryCount] = value; - columnIndications[currentEntryCount] = column; + columnsAndValues[currentEntryCount] = std::make_pair(column, value); } else { - valueStorage.push_back(value); - columnIndications.push_back(column); + columnsAndValues.emplace_back(column, value); if (!columnCountSet) { columnCount = column + 1; } @@ -380,32 +353,29 @@ namespace storm { } template - void SparseMatrix::makeRowAbsorbing(const uint_fast64_t row, const uint_fast64_t column) { + void SparseMatrix::makeRowAbsorbing(uint_fast64_t row, 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."; } - // Iterate over the elements in the row that are not on the diagonal and set them to zero. - T* valuePtr = valueStorage.data() + rowIndications[row]; - T* valuePtrEnd = valueStorage.data() + rowIndications[row + 1]; - uint_fast64_t* columnPtr = columnIndications.data() + rowIndications[row]; + const_iterator columnValuePtr = columnsAndValues.begin() + rowIndications[row]; + const_iterator columnValuePtrEnd = columnsAndValues.begin() + rowIndications[row + 1]; // If the row has no elements in it, we cannot make it absorbing, because we would need to move all elements // in the vector of nonzeros otherwise. - if (valuePtr >= valuePtrEnd) { + if (columnValuePtr >= columnValuePtrEnd) { throw storm::exceptions::InvalidStateException() << "Illegal call to SparseMatrix::makeRowAbsorbing: cannot make row " << row << " absorbing, but there is no entry in this row."; } // If there is at least one entry in this row, we can just set it to one, modify its column value to the // one given by the parameter and set all subsequent elements of this row to zero. - *valuePtr = storm::utility::constantOne(); - *columnPtr = column; - ++valuePtr; - ++columnPtr; - for (; valuePtr != valuePtrEnd; ++valuePtr) { - *valuePtr = storm::utility::constantZero(); - *columnPtr = 0; + columnValuePtr->first = column; + columnValuePtr->second = storm::utility::constantOne(); + ++columnValuePtr; + for (; columnValuePtr != columnValuePtr; ++columnValuePtr) { + columnValuePtr->first = 0; + columnValuePtr->second = storm::utility::constantZero(); } } @@ -413,9 +383,9 @@ namespace storm { T SparseMatrix::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])) { - result += valueStorage[i]; + for (typename std::vector>::const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) { + if (constraint.get(it->first)) { + result += it->second; } } return result; @@ -472,11 +442,11 @@ namespace storm { for (uint_fast64_t i = rowGroupIndices[index]; i < rowGroupIndices[index + 1]; ++i) { bool foundDiagonalElement = false; - for (uint_fast64_t j = rowIndications[i]; j < rowIndications[i + 1]; ++j) { - if (columnConstraint.get(columnIndications[j])) { + for (const_iterator it = this->begin(i), ite = this->end(i); it != ite; ++it) { + if (columnConstraint.get(it->first)) { ++subEntries; - if (index == columnIndications[j]) { + if (index == it->first) { foundDiagonalElement = true; } } @@ -521,15 +491,15 @@ namespace storm { for (uint_fast64_t i = rowGroupIndices[index]; i < rowGroupIndices[index + 1]; ++i) { bool insertedDiagonalElement = false; - for (uint_fast64_t j = rowIndications[i]; j < rowIndications[i + 1]; ++j) { - if (columnConstraint.get(columnIndications[j])) { - if (index == columnIndications[j]) { + for (const_iterator it = this->begin(i), ite = this->end(i); it != ite; ++it) { + if (columnConstraint.get(it->first)) { + if (index == it->first) { insertedDiagonalElement = true; - } else if (insertDiagonalEntries && !insertedDiagonalElement && columnIndications[j] > index) { + } else if (insertDiagonalEntries && !insertedDiagonalElement && it->first > index) { result.addNextValue(rowCount, bitsSetBeforeIndex[index], storm::utility::constantZero()); insertedDiagonalElement = true; } - result.addNextValue(rowCount, bitsSetBeforeIndex[columnIndications[j]], valueStorage[j]); + result.addNextValue(rowCount, bitsSetBeforeIndex[it->first], it->second); } } if (insertDiagonalEntries && !insertedDiagonalElement) { @@ -556,8 +526,8 @@ namespace storm { // Iterate through that row and count the number of slots we have to reserve for copying. bool foundDiagonalElement = false; - for (uint_fast64_t i = rowIndications[rowToCopy], rowEnd = rowIndications[rowToCopy + 1]; i < rowEnd; ++i) { - if (columnIndications[i] == rowGroupIndex) { + for (const_iterator it = this->begin(rowToCopy), ite = this->end(rowToCopy); it != ite; ++it) { + if (it->first == rowGroupIndex) { foundDiagonalElement = true; } ++subEntries; @@ -578,14 +548,14 @@ namespace storm { // Iterate through that row and copy the entries. This also inserts a zero element on the diagonal if // there is no entry yet. bool insertedDiagonalElement = false; - for (uint_fast64_t i = rowIndications[rowToCopy], rowEnd = rowIndications[rowToCopy + 1]; i < rowEnd; ++i) { - if (columnIndications[i] == rowGroupIndex) { + for (const_iterator it = this->begin(rowToCopy), ite = this->end(rowToCopy); it != ite; ++it) { + if (it->first == rowGroupIndex) { insertedDiagonalElement = true; - } else if (insertDiagonalEntries && !insertedDiagonalElement && columnIndications[i] > rowGroupIndex) { + } else if (insertDiagonalEntries && !insertedDiagonalElement && it->first > rowGroupIndex) { submatrix.addNextValue(rowGroupIndex, rowGroupIndex, storm::utility::constantZero()); insertedDiagonalElement = true; } - submatrix.addNextValue(rowGroupIndex, columnIndications[i], valueStorage[i]); + submatrix.addNextValue(rowGroupIndex, it->first, it->second); } if (insertDiagonalEntries && !insertedDiagonalElement) { submatrix.addNextValue(rowGroupIndex, rowGroupIndex, storm::utility::constantZero()); @@ -606,14 +576,13 @@ namespace storm { uint_fast64_t entryCount = this->entryCount; std::vector rowIndications(rowCount + 1); - std::vector columnIndications(entryCount); - std::vector values(entryCount); + std::vector> columnsAndValues(entryCount); // First, we need to count how many entries each column has. - for (uint_fast64_t i = 0; i < this->rowCount; ++i) { - for (auto const& transition : this->getRow(i)) { - if (transition.value() > 0) { - ++rowIndications[transition.column() + 1]; + for (uint_fast64_t row = 0; row < this->rowCount; ++row) { + for (const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) { + if (it->second > 0) { + ++rowIndications[it->first + 1]; } } } @@ -629,16 +598,16 @@ namespace storm { std::vector nextIndices = rowIndications; // Now we are ready to actually fill in the values of the transposed matrix. - for (uint_fast64_t i = 0; i < this->rowCount; ++i) { - for (auto& transition : this->getRow(i)) { - if (transition.value() > 0) { - values[nextIndices[transition.column()]] = transition.value(); - columnIndications[nextIndices[transition.column()]++] = i; + for (uint_fast64_t row = 0; row < this->rowCount; ++row) { + for (const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) { + if (it->second > 0) { + columnsAndValues[nextIndices[it->first]] = std::make_pair(row, it->second); + nextIndices[it->first]++; } } } - storm::storage::SparseMatrix transposedMatrix(columnCount, std::move(rowIndications), std::move(columnIndications), std::move(values)); + storm::storage::SparseMatrix transposedMatrix(columnCount, std::move(rowIndications), std::move(columnsAndValues)); return transposedMatrix; } @@ -664,21 +633,16 @@ namespace storm { T one = storm::utility::constantOne(); bool foundDiagonalElement = false; for (uint_fast64_t row = 0; row < rowCount; ++row) { - uint_fast64_t rowStart = rowIndications[row]; - uint_fast64_t rowEnd = rowIndications[row + 1]; - foundDiagonalElement = false; - while (rowStart < rowEnd) { - if (columnIndications[rowStart] == row) { - valueStorage[rowStart] = one - valueStorage[rowStart]; + for (const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) { + if (it->first == row) { + it->second = one - it->second; foundDiagonalElement = true; - break; } - ++rowStart; } // Throw an exception if a row did not have an element on the diagonal. if (!foundDiagonalElement) { - throw storm::exceptions::InvalidArgumentException() << "SparseMatrix::invertDiagonal requires the Matrix to contain all diagonal entries!"; + throw storm::exceptions::InvalidArgumentException() << "Illegal call to SparseMatrix::invertDiagonal: matrix is missing diagonal entries."; } } } @@ -694,13 +658,10 @@ namespace storm { // Iterate over all rows and negate all the elements that are not on the diagonal. for (uint_fast64_t row = 0; row < rowCount; ++row) { - uint_fast64_t rowStart = rowIndications[row]; - uint_fast64_t rowEnd = rowIndications[row + 1]; - while (rowStart < rowEnd) { - if (columnIndications[rowStart] != row) { - valueStorage[rowStart] = -valueStorage[rowStart]; + for (const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) { + if (it->first != row) { + it->second = -it->second; } - ++rowStart; } } } @@ -716,13 +677,10 @@ namespace storm { // Iterate over all rows and negate all the elements that are not on the diagonal. for (uint_fast64_t row = 0; row < rowCount; ++row) { - uint_fast64_t rowStart = rowIndications[row]; - uint_fast64_t rowEnd = rowIndications[row + 1]; - while (rowStart < rowEnd) { - if (columnIndications[rowStart] == row) { - valueStorage[rowStart] = storm::utility::constantZero(); + for (const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) { + if (it->first == row) { + it->second = storm::utility::constantZero(); } - ++rowStart; } } } @@ -745,10 +703,10 @@ namespace storm { // Because the matrix may have several entries on the diagonal, we need to sum them before we are able // to invert the entry. T diagonalValue = storm::utility::constantZero(); - for (const_iterator rowIt = this->begin(rowNumber), rowIte = this->end(rowNumber); rowIt != rowIte; ++rowIt) { - if (rowIt.column() == rowNumber) { - diagonalValue += rowIt.value(); - } else if (rowIt.column() > rowNumber) { + for (const_iterator it = this->begin(rowNumber), ite = this->end(rowNumber); it != ite; ++it) { + if (it->first == rowNumber) { + diagonalValue += it->second; + } else if (it->first > rowNumber) { break; } } @@ -769,15 +727,15 @@ namespace storm { // 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) { - 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]) { + for (const_iterator it1 = this->begin(row), ite1 = this->end(row), it2 = otherMatrix.begin(row), ite2 = otherMatrix.end(row); it1 != ite1 && it2 != ite2; ++it1) { + if (it1->first < it2->first) { continue; } else { // If the precondition of this method (i.e. that the given matrix is a submatrix // of the current one) was fulfilled, we know now that the two elements are in // the same column, so we can multiply and add them to the row sum vector. - result[row] += otherMatrix.valueStorage[nextOtherElement] * valueStorage[element]; - ++nextOtherElement; + result[row] += it2->second * it1->second; + ++it2; } } } @@ -792,9 +750,8 @@ namespace storm { #ifdef STORM_HAVE_INTELTBB tbb::parallel_for(tbb::blocked_range(0, result.size()), tbbHelper_MatrixRowVectorScalarProduct, std::vector, T>(this, &vector, &result)); #else - typename std::vector::const_iterator valueIterator = valueStorage.begin(); - typename std::vector::const_iterator valueIteratorEnd; - typename std::vector::const_iterator columnIterator = columnIndications.begin(); + const_iterator it = this->begin(); + const_iterator ite = this->begin(); typename std::vector::const_iterator rowIterator = rowIndications.begin(); typename std::vector::const_iterator rowIteratorEnd = rowIndications.end(); typename std::vector::iterator resultIterator = result.begin(); @@ -803,8 +760,8 @@ namespace storm { for (; resultIterator != resultIteratorEnd; ++rowIterator, ++resultIterator) { *resultIterator = storm::utility::constantZero(); - for (valueIteratorEnd = valueIterator + (*(rowIterator + 1) - *rowIterator); valueIterator != valueIteratorEnd; ++valueIterator, ++columnIterator) { - *resultIterator += *valueIterator * vector[*columnIterator]; + for (ite = it + (*(rowIterator + 1) - *rowIterator); it != ite; ++it) { + *resultIterator += it->second * vector[it->first]; } } #endif @@ -816,11 +773,8 @@ namespace storm { uint_fast64_t size = sizeof(*this); - // Add value_storage size. - size += sizeof(T) * valueStorage.capacity(); - - // Add column_indications size. - size += sizeof(uint_fast64_t) * columnIndications.capacity(); + // Add size of columns and values. + size += sizeof(std::pair) * columnsAndValues.capacity(); // Add row_indications size. size += sizeof(uint_fast64_t) * rowIndications.capacity(); @@ -855,45 +809,45 @@ namespace storm { template typename SparseMatrix::const_iterator SparseMatrix::begin(uint_fast64_t row) const { checkReady("begin"); - return const_iterator(this->valueStorage.data() + this->rowIndications[row], this->columnIndications.data() + this->rowIndications[row]); + return this->columnsAndValues.begin() + this->rowIndications[row]; } template typename SparseMatrix::iterator SparseMatrix::begin(uint_fast64_t row) { checkReady("begin"); - return iterator(this->valueStorage.data() + this->rowIndications[row], this->columnIndications.data() + this->rowIndications[row]); + return this->columnsAndValues.begin() + this->rowIndications[row]; } template typename SparseMatrix::const_iterator SparseMatrix::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]); + return this->columnsAndValues.begin() + this->rowIndications[row + 1]; } template typename SparseMatrix::iterator SparseMatrix::end(uint_fast64_t row) { checkReady("end"); - return iterator(this->valueStorage.data() + this->rowIndications[row + 1], this->columnIndications.data() + this->rowIndications[row + 1]); + return this->columnsAndValues.begin() + this->rowIndications[row + 1]; } template typename SparseMatrix::const_iterator SparseMatrix::end() const { checkReady("end"); - return const_iterator(this->valueStorage.data() + this->rowIndications[rowCount], this->columnIndications.data() + this->rowIndications[rowCount]); + return this->columnsAndValues.begin() + this->rowIndications[rowCount]; } template typename SparseMatrix::iterator SparseMatrix::end() { checkReady("end"); - return iterator(this->valueStorage.data() + this->rowIndications[rowCount], this->columnIndications.data() + this->rowIndications[rowCount]); + return this->columnsAndValues.begin() + this->rowIndications[rowCount]; } template T SparseMatrix::getRowSum(uint_fast64_t row) const { checkReady("getRowSum"); T sum = storm::utility::constantZero(); - for (typename std::vector::const_iterator valueIterator = valueStorage.begin() + rowIndications[row], valueIteratorEnd = valueStorage.begin() + rowIndications[row + 1]; valueIterator != valueIteratorEnd; ++valueIterator) { - sum += *valueIterator; + for (const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) { + sum += it->second; } return sum; } @@ -908,12 +862,13 @@ namespace storm { // Check the subset property for all rows individually. for (uint_fast64_t row = 0; row < this->getRowCount(); ++row) { + for (const_iterator it1 = this->begin(row), ite1 = this->end(row), it2 = matrix.begin(row), ite2 = matrix.end(row); it1 != ite1; ++it1) { 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; + while (it2->first != ite2 && it2->first < it1->first) { + ++it2; } - if (!(elem2 < matrix.rowIndications[row + 1]) || columnIndications[elem] != matrix.columnIndications[elem2]) { + if (it2->first == ite2 || it1->first != it2->first) { return false; } } @@ -940,8 +895,8 @@ namespace storm { out << i << "\t(\t"; uint_fast64_t currentRealIndex = 0; while (currentRealIndex < matrix.columnCount) { - if (nextIndex < matrix.rowIndications[i + 1] && currentRealIndex == matrix.columnIndications[nextIndex]) { - out << matrix.valueStorage[nextIndex] << "\t"; + if (nextIndex < matrix.rowIndications[i + 1] && currentRealIndex == matrix.columnsAndValues[nextIndex].first) { + out << matrix.columnsAndValues[nextIndex].second << "\t"; ++nextIndex; } else { out << "0\t"; @@ -969,8 +924,7 @@ namespace storm { boost::hash_combine(result, columnCount); boost::hash_combine(result, entryCount); boost::hash_combine(result, internalStatus); - boost::hash_combine(result, boost::hash_range(valueStorage.begin(), valueStorage.end())); - boost::hash_combine(result, boost::hash_range(columnIndications.begin(), columnIndications.end())); + boost::hash_combine(result, boost::hash_range(columnsAndValues.begin(), columnsAndValues.end())); boost::hash_combine(result, boost::hash_range(rowIndications.begin(), rowIndications.end())); return result; diff --git a/src/storage/SparseMatrix.h b/src/storage/SparseMatrix.h index 4c9d43627..9406f3e79 100644 --- a/src/storage/SparseMatrix.h +++ b/src/storage/SparseMatrix.h @@ -68,88 +68,8 @@ namespace storm { friend class tbbHelper_MatrixRowVectorScalarProduct; #endif - /*! - * A class representing an iterator over consecutive entries of the matrix. If the value type is const, - * then the values cannot be changed by an iterator. If the value type is not const, the value of an entry - * may be changed, but the column value not. This is due to the internal representation of the matrix, - * which would break down when arbitrarily changing column values. - */ - template - class BaseIterator : std::iterator { - public: - /*! - * Constructs an iterator point to the given value and column entry. - * - * @param valuePtr A pointer to the value of the first entry of the iterator range. - * @param columnPtr A pointer to the column of the first entry of the iterator range. - */ - BaseIterator(ValueType* valuePtr, uint_fast64_t const* columnPtr); - - /*! - * Constructs an iterator that points to the same entry as the given iterator. - */ - BaseIterator(BaseIterator const& other); - - /*! - * Assigns the position of the given iterator to the current iterator. - * - * @return A reference to the iterator itself. - */ - BaseIterator& operator=(BaseIterator const& other); - - /*! - * Moves the iterator to the next entry. - * - * @return A reference to the iterator itself. - */ - BaseIterator& operator++(); - - /*! - * Dereferences the iterator by returning a reference to itself. This is needed for making use of the - * range-based for loop over transitions. - * - * @return A reference to the iterator itself. - */ - BaseIterator& operator*(); - - /*! - * Compares the two iterators for inequality. - * - * @return True iff the given iterator points to different entries. - */ - bool operator!=(BaseIterator const& other) const; - - /*! - * Compares the two iterators for equality. - * - * @return True iff the given iterator points to the same entry. - */ - bool operator==(BaseIterator const& other) const; - - /*! - * Retrieves the column that is associated with the entry to which this iterator points. - * - * @return The column of the entry to which this iterator points. - */ - uint_fast64_t column() const; - - /*! - * Retrieves the value of the entry to which this iterator points. - * - * @return The value of the entry to which this iterator points. - */ - ValueType& value() const; - - private: - // A pointer to the value of the current non-zero entry. - ValueType* valuePtr; - - // A pointer to the column of the current non-zero entry. - uint_fast64_t const* columnPtr; - }; - - typedef BaseIterator iterator; - typedef BaseIterator const_iterator; + typedef typename std::vector>::iterator iterator; + typedef typename std::vector>::const_iterator const_iterator; /*! * This class represents a number of consecutive rows of the matrix. @@ -160,11 +80,10 @@ namespace storm { * Constructs an object that represents the rows defined by the value of the first entry, the column * of the first entry and the number of entries in this row set. * - * @param valuePtr A pointer to the value of the first entry of the rows. - * @param columnPtr A pointer to the column of the first entry of the rows. + * @param columnAndValuePtr A pointer to the columnd and value of the first entry of the rows. * @param entryCount The number of entrys in the rows. */ - rows(T* valuePtr, uint_fast64_t const* columnPtr, uint_fast64_t entryCount); + rows(std::pair* columnAndValuePtr, uint_fast64_t entryCount); /*! * Retrieves an iterator that points to the beginning of the rows. @@ -181,11 +100,8 @@ namespace storm { iterator end(); private: - // The pointer to the value of the first entry. - T* valuePtr; - - // The pointer to the column of the first entry. - uint_fast64_t const* columnPtr; + // The pointer to the columnd and value of the first entry. + std::pair* columnAndValuePtr; // The number of non-zero entries in the rows. uint_fast64_t entryCount; @@ -200,11 +116,10 @@ namespace storm { * Constructs an object that represents the rows defined by the value of the first entry, the column * of the first entry and the number of entries in this row set. * - * @param valuePtr A pointer to the value of the first entry of the rows. - * @param columnPtr A pointer to the column of the first entry of the rows. + * @param columnAndValuePtr A pointer to the columnd and value of the first entry of the rows. * @param entryCount The number of entrys in the rows. */ - const_rows(T const* valuePtr, uint_fast64_t const* columnPtr, uint_fast64_t entryCount); + const_rows(std::pair const* columnAndValuePtr, uint_fast64_t entryCount); /*! * Retrieves an iterator that points to the beginning of the rows. @@ -221,11 +136,8 @@ namespace storm { const_iterator end() const; private: - // The pointer to the value of the first entry. - T const* valuePtr; - - // The pointer to the column of the first entry. - uint_fast64_t const* columnPtr; + // The pointer to the columnd and value of the first entry. + std::pair const* columnAndValuePtr; // The number of non-zero entries in the rows. uint_fast64_t entryCount; @@ -261,6 +173,15 @@ namespace storm { */ SparseMatrix(SparseMatrix&& other); + /*! + * Constructs a sparse matrix by copying the given contents. + * + * @param columnCount The number of columns of the matrix. + * @param rowIndications The row indications vector of the matrix to be constructed. + * @param columnsAndValues The vector containing the columns and values of the entries in the matrix. + */ + SparseMatrix(uint_fast64_t columnCount, std::vector const& rowIndications, std::vector> const& columnsAndValues); + /*! * Constructs a sparse matrix by copying the given contents. * @@ -281,6 +202,15 @@ namespace storm { */ SparseMatrix(uint_fast64_t columnCount, std::vector&& rowIndications, std::vector&& columnIndications, std::vector&& values); + /*! + * Constructs a sparse matrix by moving the given contents. + * + * @param columnCount The number of columns of the matrix. + * @param rowIndications The row indications vector of the matrix to be constructed. + * @param columnsAndValues The vector containing the columns and values of the entries in the matrix. + */ + SparseMatrix(uint_fast64_t columnCount, std::vector&& rowIndications, std::vector>&& columnsAndValues); + /*! * Assigns the contents of the given matrix to the current one by deep-copying its contents. * @@ -666,11 +596,8 @@ namespace storm { // Stores whether the storage of the matrix was preallocated or not. bool storagePreallocated; - // The storage for the values of all entries in the matrix. - std::vector valueStorage; - - // Stores the column for each entry of the matrix. - std::vector columnIndications; + // The storage for the columns and values of all entries in the matrix. + std::vector> columnsAndValues; // A vector containing the indices at which each given row begins. This index is to be interpreted as an // index in the valueStorage and the columnIndications vectors. Put differently, the values of the entries