Storm
A Modern Probabilistic Model Checker
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SparseMatrix.cpp
Go to the documentation of this file.
1#include <boost/functional/hash.hpp>
2
6
12
18
20
21#include <iterator>
22
23namespace storm {
24namespace storage {
25
26template<typename IndexType, typename ValueType>
27MatrixEntry<IndexType, ValueType>::MatrixEntry(IndexType column, ValueType value) : entry(column, value) {
28 // Intentionally left empty.
29}
30
31template<typename IndexType, typename ValueType>
32MatrixEntry<IndexType, ValueType>::MatrixEntry(std::pair<IndexType, ValueType>&& pair) : entry(std::move(pair)) {
33 // Intentionally left empty.
34}
35
36template<typename IndexType, typename ValueType>
38 return this->entry.first;
39}
40
41template<typename IndexType, typename ValueType>
42void MatrixEntry<IndexType, ValueType>::setColumn(IndexType const& column) {
43 this->entry.first = column;
44}
45
46template<typename IndexType, typename ValueType>
48 return this->entry.second;
49}
50
51template<typename IndexType, typename ValueType>
52void MatrixEntry<IndexType, ValueType>::setValue(ValueType const& value) {
53 this->entry.second = value;
54}
55
56template<typename IndexType, typename ValueType>
57std::pair<IndexType, ValueType> const& MatrixEntry<IndexType, ValueType>::getColumnValuePair() const {
58 return this->entry;
59}
60
61template<typename IndexType, typename ValueType>
63 return MatrixEntry(this->getColumn(), this->getValue() * factor);
64}
65
66template<typename IndexType, typename ValueType>
68 return this->entry.first == other.entry.first && this->entry.second == other.entry.second;
69}
70
71template<typename IndexType, typename ValueType>
73 return !(*this == other);
74}
75
76template<typename IndexTypePrime, typename ValueTypePrime>
77std::ostream& operator<<(std::ostream& out, MatrixEntry<IndexTypePrime, ValueTypePrime> const& entry) {
78 out << "(" << entry.getColumn() << ", " << entry.getValue() << ")";
79 return out;
80}
81
82template<typename ValueType>
83SparseMatrixBuilder<ValueType>::SparseMatrixBuilder(index_type rows, index_type columns, index_type entries, bool forceDimensions, bool hasCustomRowGrouping,
84 index_type rowGroups)
85 : initialRowCountSet(rows != 0),
86 initialRowCount(rows),
87 initialColumnCountSet(columns != 0),
88 initialColumnCount(columns),
89 initialEntryCountSet(entries != 0),
90 initialEntryCount(entries),
91 forceInitialDimensions(forceDimensions),
92 hasCustomRowGrouping(hasCustomRowGrouping),
93 initialRowGroupCountSet(rowGroups != 0),
94 initialRowGroupCount(rowGroups),
95 rowGroupIndices(),
96 columnsAndValues(),
97 rowIndications(),
98 currentEntryCount(0),
99 lastRow(0),
100 lastColumn(0),
101 highestColumn(0),
102 currentRowGroupCount(0) {
103 // Prepare the internal storage.
104 if (initialRowCountSet) {
105 rowIndications.reserve(initialRowCount + 1);
106 }
107 if (initialEntryCountSet) {
108 columnsAndValues.reserve(initialEntryCount);
109 }
110 if (hasCustomRowGrouping) {
111 rowGroupIndices = std::vector<index_type>();
112 }
113 if (initialRowGroupCountSet && hasCustomRowGrouping) {
114 rowGroupIndices.get().reserve(initialRowGroupCount + 1);
115 }
116 rowIndications.push_back(0);
117}
118
119template<typename ValueType>
121 : initialRowCountSet(false),
122 initialRowCount(0),
123 initialColumnCountSet(false),
124 initialColumnCount(0),
125 initialEntryCountSet(false),
126 initialEntryCount(0),
127 forceInitialDimensions(false),
128 hasCustomRowGrouping(!matrix.trivialRowGrouping),
129 initialRowGroupCountSet(false),
130 initialRowGroupCount(0),
131 rowGroupIndices(),
132 columnsAndValues(std::move(matrix.columnsAndValues)),
133 rowIndications(std::move(matrix.rowIndications)),
134 currentEntryCount(matrix.entryCount),
135 currentRowGroupCount() {
136 lastRow = matrix.rowCount == 0 ? 0 : matrix.rowCount - 1;
137 lastColumn = columnsAndValues.empty() ? 0 : columnsAndValues.back().getColumn();
138 highestColumn = matrix.getColumnCount() == 0 ? 0 : matrix.getColumnCount() - 1;
139
140 // If the matrix has a custom row grouping, we move it and remove the last element to make it 'open' again.
141 if (hasCustomRowGrouping) {
142 rowGroupIndices = std::move(matrix.rowGroupIndices);
143 if (!rowGroupIndices->empty()) {
144 rowGroupIndices.get().pop_back();
145 }
146 currentRowGroupCount = rowGroupIndices->empty() ? 0 : rowGroupIndices.get().size() - 1;
147 }
148
149 // Likewise, we need to 'open' the row indications again.
150 if (!rowIndications.empty()) {
151 rowIndications.pop_back();
152 }
153}
154
155template<typename ValueType>
156void SparseMatrixBuilder<ValueType>::addNextValue(index_type row, index_type column, ValueType const& value) {
157 // Check that we did not move backwards wrt. the row.
158 STORM_LOG_THROW(row >= lastRow, storm::exceptions::InvalidArgumentException,
159 "Adding an element in row " << row << ", but an element in row " << lastRow << " has already been added.");
160 STORM_LOG_ASSERT(columnsAndValues.size() == currentEntryCount, "Unexpected size of columnsAndValues vector.");
161
162 // Check if a diagonal entry shall be inserted before
163 if (pendingDiagonalEntry) {
164 index_type diagColumn = hasCustomRowGrouping ? currentRowGroupCount - 1 : lastRow;
165 if (row > lastRow || column >= diagColumn) {
166 ValueType diagValue = std::move(pendingDiagonalEntry.get());
167 pendingDiagonalEntry = boost::none;
168 // Add the pending diagonal value now
169 if (row == lastRow && column == diagColumn) {
170 // The currently added value coincides with the diagonal entry!
171 // We add up the values and repeat this call.
172 addNextValue(row, column, diagValue + value);
173 // We return here because the above call already did all the work.
174 return;
175 } else {
176 addNextValue(lastRow, diagColumn, diagValue);
177 }
178 }
179 }
180
181 // If the element is in the same row, but was not inserted in the correct order, we need to fix the row after
182 // the insertion.
183 bool fixCurrentRow = row == lastRow && column < lastColumn;
184 // If the element is in the same row and column as the previous entry, we add them up...
185 // unless there is no entry in this row yet, which might happen either for the very first entry or when only a diagonal value has been added
186 if (row == lastRow && column == lastColumn && rowIndications.back() < currentEntryCount) {
187 columnsAndValues.back().setValue(columnsAndValues.back().getValue() + value);
188 } else {
189 // If we switched to another row, we have to adjust the missing entries in the row indices vector.
190 if (row != lastRow) {
191 // Otherwise, we need to push the correct values to the vectors, which might trigger reallocations.
192 assert(rowIndications.size() == lastRow + 1);
193 rowIndications.resize(row + 1, currentEntryCount);
194 lastRow = row;
195 }
196
197 lastColumn = column;
198
199 // Finally, set the element and increase the current size.
200 columnsAndValues.emplace_back(column, value);
201 highestColumn = std::max(highestColumn, column);
202 ++currentEntryCount;
203
204 // If we need to fix the row, do so now.
205 if (fixCurrentRow) {
206 // TODO we fix this row directly after the out-of-order insertion, but the code does not exploit that fact.
207 STORM_LOG_TRACE("Fix row " << row << " as column " << column << " is added out-of-order.");
208 // First, we sort according to columns.
209 std::sort(columnsAndValues.begin() + rowIndications.back(), columnsAndValues.end(),
211 return a.getColumn() < b.getColumn();
212 });
213
214 auto insertIt = columnsAndValues.begin() + rowIndications.back();
215 uint64_t elementsToRemove = 0;
216 for (auto it = insertIt + 1; it != columnsAndValues.end(); ++it) {
217 // Iterate over all entries in this last row and detect duplicates.
218 if (it->getColumn() == insertIt->getColumn()) {
219 // This entry is a duplicate of the column. Update the previous entry.
220 insertIt->setValue(insertIt->getValue() + it->getValue());
221 elementsToRemove++;
222 } else {
223 insertIt = it;
224 }
225 }
226 // Then, we eliminate those duplicate entries.
227 // We cast the result of std::unique to void to silence a warning issued due to a [[nodiscard]] attribute
228 static_cast<void>(std::unique(columnsAndValues.begin() + rowIndications.back(), columnsAndValues.end(),
230 storm::storage::MatrixEntry<index_type, ValueType> const& b) { return a.getColumn() == b.getColumn(); }));
231
232 if (elementsToRemove > 0) {
233 STORM_LOG_WARN("Unordered insertion into matrix builder caused duplicate entries.");
234 currentEntryCount -= elementsToRemove;
235 columnsAndValues.resize(columnsAndValues.size() - elementsToRemove);
236 }
237 lastColumn = columnsAndValues.back().getColumn();
238 }
239 }
240
241 // In case we did not expect this value, we throw an exception.
242 if (forceInitialDimensions) {
243 STORM_LOG_THROW(!initialRowCountSet || lastRow < initialRowCount, storm::exceptions::OutOfRangeException,
244 "Cannot insert value at illegal row " << lastRow << ".");
245 STORM_LOG_THROW(!initialColumnCountSet || lastColumn < initialColumnCount, storm::exceptions::OutOfRangeException,
246 "Cannot insert value at illegal column " << lastColumn << ".");
247 STORM_LOG_THROW(!initialEntryCountSet || currentEntryCount <= initialEntryCount, storm::exceptions::OutOfRangeException,
248 "Too many entries in matrix, expected only " << initialEntryCount << ".");
249 }
250}
251
252template<typename ValueType>
254 STORM_LOG_THROW(hasCustomRowGrouping, storm::exceptions::InvalidStateException, "Matrix was not created to have a custom row grouping.");
255 STORM_LOG_THROW(startingRow >= lastRow, storm::exceptions::InvalidStateException, "Illegal row group with negative size.");
256
257 // If there still is a pending diagonal entry, we need to add it now (otherwise, the correct diagonal column will be unclear)
258 if (pendingDiagonalEntry) {
259 STORM_LOG_ASSERT(currentRowGroupCount > 0, "Diagonal entry was set before opening the first row group.");
260 index_type diagColumn = currentRowGroupCount - 1;
261 ValueType diagValue = std::move(pendingDiagonalEntry.get());
262 pendingDiagonalEntry = boost::none; // clear now, so addNextValue works properly
263 addNextValue(lastRow, diagColumn, diagValue);
264 }
265
266 rowGroupIndices.get().push_back(startingRow);
267 ++currentRowGroupCount;
268
269 // Handle the case where the previous row group ends with one or more empty rows
270 if (lastRow + 1 < startingRow) {
271 // Close all rows from the most recent one to the starting row.
272 assert(rowIndications.size() == lastRow + 1);
273 rowIndications.resize(startingRow, currentEntryCount);
274 // Reset the most recently seen row/column to allow for proper insertion of the following elements.
275 lastRow = startingRow - 1;
276 lastColumn = 0;
277 }
278}
279
280template<typename ValueType>
282 index_type overriddenRowGroupCount) {
283 // If there still is a pending diagonal entry, we need to add it now
284 if (pendingDiagonalEntry) {
285 index_type diagColumn = hasCustomRowGrouping ? currentRowGroupCount - 1 : lastRow;
286 ValueType diagValue = std::move(pendingDiagonalEntry.get());
287 pendingDiagonalEntry = boost::none; // clear now, so addNextValue works properly
288 addNextValue(lastRow, diagColumn, diagValue);
289 }
290
291 bool hasEntries = currentEntryCount != 0;
292
293 uint_fast64_t rowCount = hasEntries ? lastRow + 1 : 0;
294
295 // If the last row group was empty, we need to add one more to the row count, because otherwise this empty row is not counted.
296 if (hasCustomRowGrouping) {
297 if (lastRow < rowGroupIndices->back()) {
298 ++rowCount;
299 }
300 }
301
302 if (initialRowCountSet && forceInitialDimensions) {
303 STORM_LOG_THROW(rowCount <= initialRowCount, storm::exceptions::InvalidStateException,
304 "Expected not more than " << initialRowCount << " rows, but got " << rowCount << ".");
305 rowCount = std::max(rowCount, initialRowCount);
306 }
307
308 rowCount = std::max(rowCount, overriddenRowCount);
309
310 // If the current row count was overridden, we may need to add empty rows.
311 for (index_type i = lastRow + 1; i < rowCount; ++i) {
312 rowIndications.push_back(currentEntryCount);
313 }
314
315 // We put a sentinel element at the last position of the row indices array. This eases iteration work,
316 // as now the indices of row i are always between rowIndications[i] and rowIndications[i + 1], also for
317 // the first and last row.
318 if (rowCount > 0) {
319 rowIndications.push_back(currentEntryCount);
320 }
321 STORM_LOG_ASSERT(rowCount == rowIndications.size() - 1,
322 "Wrong sizes of row indications vector: (Rowcount) " << rowCount << " != " << (rowIndications.size() - 1) << " (Vector).");
323 uint_fast64_t columnCount = hasEntries ? highestColumn + 1 : 0;
324 if (initialColumnCountSet && forceInitialDimensions) {
325 STORM_LOG_THROW(columnCount <= initialColumnCount, storm::exceptions::InvalidStateException,
326 "Expected not more than " << initialColumnCount << " columns, but got " << columnCount << ".");
327 columnCount = std::max(columnCount, initialColumnCount);
328 }
329 columnCount = std::max(columnCount, overriddenColumnCount);
330
331 uint_fast64_t entryCount = currentEntryCount;
332 if (initialEntryCountSet && forceInitialDimensions) {
333 STORM_LOG_THROW(entryCount == initialEntryCount, storm::exceptions::InvalidStateException,
334 "Expected " << initialEntryCount << " entries, but got " << entryCount << ".");
335 }
336
337 // Check whether row groups are missing some entries.
338 if (hasCustomRowGrouping) {
339 uint_fast64_t rowGroupCount = currentRowGroupCount;
340 if (initialRowGroupCountSet && forceInitialDimensions) {
341 STORM_LOG_THROW(rowGroupCount <= initialRowGroupCount, storm::exceptions::InvalidStateException,
342 "Expected not more than " << initialRowGroupCount << " row groups, but got " << rowGroupCount << ".");
343 rowGroupCount = std::max(rowGroupCount, initialRowGroupCount);
344 }
345 rowGroupCount = std::max(rowGroupCount, overriddenRowGroupCount);
346
347 for (index_type i = currentRowGroupCount; i <= rowGroupCount; ++i) {
348 rowGroupIndices.get().push_back(rowCount);
349 }
350 }
351
352 return SparseMatrix<ValueType>(columnCount, std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices));
353}
354
355template<typename ValueType>
357 return lastRow;
358}
359
360template<typename ValueType>
362 if (this->hasCustomRowGrouping) {
363 return currentRowGroupCount;
364 } else {
365 return getLastRow() + 1;
366 }
367}
368
369template<typename ValueType>
371 return lastColumn;
372}
373
374// Debug method for printing the current matrix
375template<typename ValueType>
376void print(std::vector<typename SparseMatrix<ValueType>::index_type> const& rowGroupIndices,
377 std::vector<MatrixEntry<typename SparseMatrix<ValueType>::index_type, typename SparseMatrix<ValueType>::value_type>> const& columnsAndValues,
378 std::vector<typename SparseMatrix<ValueType>::index_type> const& rowIndications) {
379 typename SparseMatrix<ValueType>::index_type endGroups;
381 // Iterate over all row groups.
382 for (typename SparseMatrix<ValueType>::index_type group = 0; group < rowGroupIndices.size(); ++group) {
383 std::cout << "\t---- group " << group << "/" << (rowGroupIndices.size() - 1) << " ---- \n";
384 endGroups = group < rowGroupIndices.size() - 1 ? rowGroupIndices[group + 1] : rowIndications.size();
385 // Iterate over all rows in a row group
386 for (typename SparseMatrix<ValueType>::index_type i = rowGroupIndices[group]; i < endGroups; ++i) {
387 endRows = i < rowIndications.size() - 1 ? rowIndications[i + 1] : columnsAndValues.size();
388 // Print the actual row.
389 std::cout << "Row " << i << " (" << rowIndications[i] << " - " << endRows << ")" << ": ";
390 for (typename SparseMatrix<ValueType>::index_type pos = rowIndications[i]; pos < endRows; ++pos) {
391 std::cout << "(" << columnsAndValues[pos].getColumn() << ": " << columnsAndValues[pos].getValue() << ") ";
392 }
393 std::cout << '\n';
394 }
395 }
396}
397
398template<typename ValueType>
399void SparseMatrixBuilder<ValueType>::replaceColumns(std::vector<index_type> const& replacements, index_type offset) {
400 index_type maxColumn = 0;
401
402 for (index_type row = 0; row < rowIndications.size(); ++row) {
403 bool changed = false;
404 auto startRow = std::next(columnsAndValues.begin(), rowIndications[row]);
405 auto endRow = row < rowIndications.size() - 1 ? std::next(columnsAndValues.begin(), rowIndications[row + 1]) : columnsAndValues.end();
406 for (auto entry = startRow; entry != endRow; ++entry) {
407 if (entry->getColumn() >= offset) {
408 // Change column
409 entry->setColumn(replacements[entry->getColumn() - offset]);
410 changed = true;
411 }
412 maxColumn = std::max(maxColumn, entry->getColumn());
413 }
414 if (changed) {
415 // Sort columns in row
416 std::sort(startRow, endRow,
418 // Assert no equal elements
419 STORM_LOG_ASSERT(std::is_sorted(startRow, endRow,
421 return a.getColumn() < b.getColumn();
422 }),
423 "Columns not sorted.");
424 }
425 }
426
427 highestColumn = maxColumn;
428 lastColumn = columnsAndValues.empty() ? 0 : columnsAndValues.back().getColumn();
429}
430
431template<typename ValueType>
433 STORM_LOG_THROW(row >= lastRow, storm::exceptions::InvalidArgumentException,
434 "Adding a diagonal element in row " << row << ", but an element in row " << lastRow << " has already been added.");
435 if (pendingDiagonalEntry) {
436 if (row == lastRow) {
437 // Add the two diagonal entries, nothing else to be done.
438 pendingDiagonalEntry.get() += value;
439 return;
440 } else {
441 // add the pending entry
442 index_type column = hasCustomRowGrouping ? currentRowGroupCount - 1 : lastRow;
443 ValueType diagValue = std::move(pendingDiagonalEntry.get());
444 pendingDiagonalEntry = boost::none; // clear now, so addNextValue works properly
445 addNextValue(lastRow, column, diagValue);
446 }
447 }
448 pendingDiagonalEntry = value;
449 if (lastRow != row) {
450 assert(rowIndications.size() == lastRow + 1);
451 rowIndications.resize(row + 1, currentEntryCount);
452 lastRow = row;
453 lastColumn = 0;
454 }
455}
456
457template<typename ValueType>
458SparseMatrix<ValueType>::rows::rows(iterator begin, index_type entryCount) : beginIterator(begin), entryCount(entryCount) {
459 // Intentionally left empty.
460}
461
462template<typename ValueType>
464 return beginIterator;
465}
466
467template<typename ValueType>
469 return beginIterator + entryCount;
470}
471
472template<typename ValueType>
474 return this->entryCount;
475}
476
477template<typename ValueType>
478SparseMatrix<ValueType>::const_rows::const_rows(const_iterator begin, index_type entryCount) : beginIterator(begin), entryCount(entryCount) {
479 // Intentionally left empty.
480}
481
482template<typename ValueType>
486
487template<typename ValueType>
489 return beginIterator + entryCount;
490}
491
492template<typename ValueType>
496
497template<typename ValueType>
499 : rowCount(0), columnCount(0), entryCount(0), nonzeroEntryCount(0), columnsAndValues(), rowIndications(), rowGroupIndices() {
500 // Intentionally left empty.
501}
502
503template<typename ValueType>
505 : rowCount(other.rowCount),
506 columnCount(other.columnCount),
507 entryCount(other.entryCount),
508 nonzeroEntryCount(other.nonzeroEntryCount),
509 columnsAndValues(other.columnsAndValues),
510 rowIndications(other.rowIndications),
511 trivialRowGrouping(other.trivialRowGrouping),
512 rowGroupIndices(other.rowGroupIndices) {
513 // Intentionally left empty.
514}
516template<typename ValueType>
517SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<value_type> const& other, bool insertDiagonalElements) {
518 storm::storage::BitVector rowConstraint(other.getRowCount(), true);
519 storm::storage::BitVector columnConstraint(other.getColumnCount(), true);
520 *this = other.getSubmatrix(false, rowConstraint, columnConstraint, insertDiagonalElements);
521}
523template<typename ValueType>
525 : rowCount(other.rowCount),
526 columnCount(other.columnCount),
527 entryCount(other.entryCount),
528 nonzeroEntryCount(other.nonzeroEntryCount),
529 columnsAndValues(std::move(other.columnsAndValues)),
530 rowIndications(std::move(other.rowIndications)),
531 trivialRowGrouping(other.trivialRowGrouping),
532 rowGroupIndices(std::move(other.rowGroupIndices)) {
533 // Now update the source matrix
534 other.rowCount = 0;
535 other.columnCount = 0;
536 other.entryCount = 0;
537}
538
539template<typename ValueType>
540SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type> const& rowIndications,
541 std::vector<MatrixEntry<index_type, ValueType>> const& columnsAndValues,
542 boost::optional<std::vector<index_type>> const& rowGroupIndices)
543 : rowCount(rowIndications.size() - 1),
544 columnCount(columnCount),
545 entryCount(columnsAndValues.size()),
546 nonzeroEntryCount(0),
547 columnsAndValues(columnsAndValues),
548 rowIndications(rowIndications),
549 trivialRowGrouping(!rowGroupIndices),
550 rowGroupIndices(rowGroupIndices) {
551 this->updateNonzeroEntryCount();
552}
553
554template<typename ValueType>
555SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications,
556 std::vector<MatrixEntry<index_type, ValueType>>&& columnsAndValues,
557 boost::optional<std::vector<index_type>>&& rowGroupIndices)
558 : columnCount(columnCount),
559 nonzeroEntryCount(0),
560 columnsAndValues(std::move(columnsAndValues)),
561 rowIndications(std::move(rowIndications)),
562 rowGroupIndices(std::move(rowGroupIndices)) {
563 // Initialize some variables here which depend on other variables
564 // This way we are more robust against different initialization orders
565 this->rowCount = this->rowIndications.size() - 1;
566 this->entryCount = this->columnsAndValues.size();
567 this->trivialRowGrouping = !this->rowGroupIndices;
568 this->updateNonzeroEntryCount();
570
571template<typename ValueType>
573 // Only perform assignment if source and target are not the same.
574 if (this != &other) {
575 rowCount = other.rowCount;
576 columnCount = other.columnCount;
577 entryCount = other.entryCount;
578 nonzeroEntryCount = other.nonzeroEntryCount;
579
580 columnsAndValues = other.columnsAndValues;
581 rowIndications = other.rowIndications;
582 rowGroupIndices = other.rowGroupIndices;
583 trivialRowGrouping = other.trivialRowGrouping;
584 }
585 return *this;
586}
588template<typename ValueType>
590 // Only perform assignment if source and target are not the same.
591 if (this != &other) {
592 rowCount = other.rowCount;
593 columnCount = other.columnCount;
594 entryCount = other.entryCount;
595 nonzeroEntryCount = other.nonzeroEntryCount;
596
597 columnsAndValues = std::move(other.columnsAndValues);
598 rowIndications = std::move(other.rowIndications);
599 rowGroupIndices = std::move(other.rowGroupIndices);
600 trivialRowGrouping = other.trivialRowGrouping;
601 }
602 return *this;
603}
604
605template<typename ValueType>
607 if (this == &other) {
608 return true;
609 }
610
611 bool equalityResult = true;
612
613 equalityResult &= this->getRowCount() == other.getRowCount();
614 if (!equalityResult) {
615 return false;
616 }
617 equalityResult &= this->getColumnCount() == other.getColumnCount();
618 if (!equalityResult) {
619 return false;
620 }
622 equalityResult &= this->getRowGroupIndices() == other.getRowGroupIndices();
623 } else {
624 equalityResult &= this->hasTrivialRowGrouping() && other.hasTrivialRowGrouping();
625 }
626 if (!equalityResult) {
627 return false;
628 }
629
630 // For the actual contents, we need to do a little bit more work, because we want to ignore elements that
631 // are set to zero, please they may be represented implicitly in the other matrix.
632 for (index_type row = 0; row < this->getRowCount(); ++row) {
633 for (const_iterator it1 = this->begin(row), ite1 = this->end(row), it2 = other.begin(row), ite2 = other.end(row); it1 != ite1 && it2 != ite2;
634 ++it1, ++it2) {
635 // Skip over all zero entries in both matrices.
636 while (it1 != ite1 && storm::utility::isZero(it1->getValue())) {
637 ++it1;
638 }
639 while (it2 != ite2 && storm::utility::isZero(it2->getValue())) {
640 ++it2;
641 }
642 if ((it1 == ite1) || (it2 == ite2)) {
643 equalityResult = (it1 == ite1) ^ (it2 == ite2);
644 break;
645 } else {
646 if (it1->getColumn() != it2->getColumn() || it1->getValue() != it2->getValue()) {
647 equalityResult = false;
648 break;
649 }
650 }
651 }
652 if (!equalityResult) {
653 return false;
654 }
655 }
656
657 return equalityResult;
658}
659
660template<typename ValueType>
664
665template<typename ValueType>
669
670template<typename ValueType>
674
675template<typename ValueType>
677 index_type result = 0;
678 if (!this->hasTrivialRowGrouping()) {
679 for (auto row : this->getRowGroupIndices(group)) {
680 result += (this->rowIndications[row + 1] - this->rowIndications[row]);
681 }
682 } else {
683 result += (this->rowIndications[group + 1] - this->rowIndications[group]);
684 }
685 return result;
687
688template<typename ValueType>
690 return nonzeroEntryCount;
691}
692
693template<typename ValueType>
695 this->nonzeroEntryCount = 0;
696 for (auto const& element : *this) {
697 if (element.getValue() != storm::utility::zero<ValueType>()) {
698 ++this->nonzeroEntryCount;
699 }
700 }
701}
703template<typename ValueType>
704void SparseMatrix<ValueType>::updateNonzeroEntryCount(std::make_signed<index_type>::type difference) {
705 this->nonzeroEntryCount += difference;
706}
707
708template<typename ValueType>
710 this->nonzeroEntryCount = 0;
711 this->columnCount = 0;
712 for (auto const& element : *this) {
713 if (element.getValue() != storm::utility::zero<ValueType>()) {
714 ++this->nonzeroEntryCount;
715 this->columnCount = std::max(element.getColumn() + 1, this->columnCount);
716 }
717 }
718}
719
720template<typename ValueType>
722 if (!this->hasTrivialRowGrouping()) {
723 return rowGroupIndices.get().size() - 1;
724 } else {
725 return rowCount;
726 }
727}
728
729template<typename ValueType>
731 return this->getRowGroupIndices()[group + 1] - this->getRowGroupIndices()[group];
732}
733
734template<typename ValueType>
736 if (this->hasTrivialRowGrouping()) {
737 return 1;
738 }
739 index_type res = 0;
740 index_type previousGroupStart = 0;
741 for (auto const& i : rowGroupIndices.get()) {
742 res = std::max(res, i - previousGroupStart);
743 previousGroupStart = i;
744 }
745 return res;
746}
747
748template<typename ValueType>
750 if (this->hasTrivialRowGrouping()) {
751 return groupConstraint.getNumberOfSetBits();
752 }
753 index_type numRows = 0;
754 index_type rowGroupIndex = groupConstraint.getNextSetIndex(0);
755 while (rowGroupIndex < this->getRowGroupCount()) {
756 index_type start = this->getRowGroupIndices()[rowGroupIndex];
757 rowGroupIndex = groupConstraint.getNextUnsetIndex(rowGroupIndex + 1);
758 index_type end = this->getRowGroupIndices()[rowGroupIndex];
759 // All rows with index in [start,end) are selected.
760 numRows += end - start;
761 rowGroupIndex = groupConstraint.getNextSetIndex(rowGroupIndex + 1);
762 }
763 return numRows;
764}
765
766template<typename ValueType>
767std::vector<typename SparseMatrix<ValueType>::index_type> const& SparseMatrix<ValueType>::getRowGroupIndices() const {
768 // If there is no current row grouping, we need to create it.
769 if (!this->rowGroupIndices) {
770 STORM_LOG_ASSERT(trivialRowGrouping, "Only trivial row-groupings can be constructed on-the-fly.");
771 this->rowGroupIndices = storm::utility::vector::buildVectorForRange(static_cast<index_type>(0), this->getRowGroupCount() + 1);
773 return rowGroupIndices.get();
774}
775
776template<typename ValueType>
777boost::integer_range<typename SparseMatrix<ValueType>::index_type> SparseMatrix<ValueType>::getRowGroupIndices(index_type group) const {
778 STORM_LOG_ASSERT(group < this->getRowGroupCount(),
779 "Invalid row group index:" << group << ". Only " << this->getRowGroupCount() << " row groups available.");
780 if (this->rowGroupIndices) {
781 return boost::irange(rowGroupIndices.get()[group], rowGroupIndices.get()[group + 1]);
782 } else {
783 return boost::irange(group, group + 1);
784 }
785}
787template<typename ValueType>
788std::vector<typename SparseMatrix<ValueType>::index_type> SparseMatrix<ValueType>::swapRowGroupIndices(std::vector<index_type>&& newRowGrouping) {
789 std::vector<index_type> result;
790 if (this->rowGroupIndices) {
791 result = std::move(rowGroupIndices.get());
792 rowGroupIndices = std::move(newRowGrouping);
793 }
794 return result;
795}
796
797template<typename ValueType>
798void SparseMatrix<ValueType>::setRowGroupIndices(std::vector<index_type> const& newRowGroupIndices) {
799 trivialRowGrouping = false;
800 rowGroupIndices = newRowGroupIndices;
801}
802
803template<typename ValueType>
805 return trivialRowGrouping;
807
808template<typename ValueType>
810 if (trivialRowGrouping) {
812 !rowGroupIndices || rowGroupIndices.get() == storm::utility::vector::buildVectorForRange(static_cast<index_type>(0), this->getRowGroupCount() + 1),
813 "Row grouping is supposed to be trivial but actually it is not.");
814 } else {
815 trivialRowGrouping = true;
816 rowGroupIndices = boost::none;
817 }
818}
819
820template<typename ValueType>
822 storm::storage::BitVector res(this->getRowCount(), false);
823 for (auto group : groupConstraint) {
824 res.setMultiple(getRowGroupIndices()[group], getRowGroupSize(group));
825 }
826 return res;
827}
828
829template<typename ValueType>
831 storm::storage::BitVector const& columnConstraint) const {
832 storm::storage::BitVector result(this->getRowCount(), false);
833 for (auto group : groupConstraint) {
834 for (auto row : this->getRowGroupIndices(group)) {
835 bool choiceSatisfiesColumnConstraint = true;
836 for (auto const& entry : this->getRow(row)) {
837 if (!columnConstraint.get(entry.getColumn())) {
838 choiceSatisfiesColumnConstraint = false;
839 break;
840 }
841 }
842 if (choiceSatisfiesColumnConstraint) {
843 result.set(row, true);
844 }
845 }
847 return result;
848}
849
850template<typename ValueType>
852 STORM_LOG_ASSERT(!this->hasTrivialRowGrouping(), "Tried to get a row group filter but this matrix does not have row groups");
853 storm::storage::BitVector result(this->getRowGroupCount(), false);
854 auto const& groupIndices = this->getRowGroupIndices();
855 if (setIfForAllRowsInGroup) {
856 for (uint64_t group = 0; group < this->getRowGroupCount(); ++group) {
857 if (rowConstraint.getNextUnsetIndex(groupIndices[group]) >= groupIndices[group + 1]) {
858 // All rows within this group are set
859 result.set(group, true);
860 }
861 }
862 } else {
863 for (uint64_t group = 0; group < this->getRowGroupCount(); ++group) {
864 if (rowConstraint.getNextSetIndex(groupIndices[group]) < groupIndices[group + 1]) {
865 // Some row is set
866 result.set(group, true);
867 }
868 }
870 return result;
871}
872
873template<typename ValueType>
875 // First transform ALL rows without dropping zero entries, then drop zero entries once
876 // This prevents iteration over the whole matrix every time an entry is set to zero.
877 for (auto row : rows) {
878 makeRowDirac(row, row, false);
879 }
880 if (dropZeroEntries) {
881 this->dropZeroEntries();
882 }
883}
884
885template<typename ValueType>
886void SparseMatrix<ValueType>::makeRowGroupsAbsorbing(storm::storage::BitVector const& rowGroupConstraint, bool dropZeroEntries) {
887 // First transform ALL rows without dropping zero entries, then drop zero entries once.
888 // This prevents iteration over the whole matrix every time an entry is set to zero.
889 if (!this->hasTrivialRowGrouping()) {
890 for (auto rowGroup : rowGroupConstraint) {
891 for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) {
892 makeRowDirac(row, rowGroup, false);
893 }
894 }
895 } else {
896 for (auto rowGroup : rowGroupConstraint) {
897 makeRowDirac(rowGroup, rowGroup, false);
898 }
899 }
900 if (dropZeroEntries) {
901 this->dropZeroEntries();
902 }
903}
904
905template<typename ValueType>
906void SparseMatrix<ValueType>::makeRowDirac(index_type row, index_type column, bool dropZeroEntries) {
907 iterator columnValuePtr = this->begin(row);
908 iterator columnValuePtrEnd = this->end(row);
909
910 // If the row has no elements in it, we cannot make it absorbing, because we would need to move all elements
911 // in the vector of nonzeros otherwise.
912 if (columnValuePtr >= columnValuePtrEnd) {
913 throw storm::exceptions::InvalidStateException()
914 << "Illegal call to SparseMatrix::makeRowDirac: cannot make row " << row << " absorbing, because there is no entry in this row.";
916 iterator lastColumnValuePtr = this->end(row) - 1;
917
918 // If there is at least one entry in this row, we can set it to one, modify its column value to the
919 // one given by the parameter and set all subsequent elements of this row to zero.
920 // However, we want to preserve that column indices within a row are ascending, so we pick an entry that is close to the desired column index
921 while (columnValuePtr->getColumn() < column && columnValuePtr != lastColumnValuePtr) {
922 if (!storm::utility::isZero(columnValuePtr->getValue())) {
923 --this->nonzeroEntryCount;
924 }
925 columnValuePtr->setValue(storm::utility::zero<ValueType>());
926 ++columnValuePtr;
927 }
928 // At this point, we have found the first entry whose column is >= the desired column (or the last entry of the row, if no such column exist)
929 if (storm::utility::isZero(columnValuePtr->getValue())) {
930 ++this->nonzeroEntryCount;
931 }
932 columnValuePtr->setValue(storm::utility::one<ValueType>());
933 columnValuePtr->setColumn(column);
934 for (++columnValuePtr; columnValuePtr != columnValuePtrEnd; ++columnValuePtr) {
935 if (!storm::utility::isZero(columnValuePtr->getValue())) {
936 --this->nonzeroEntryCount;
937 }
938 columnValuePtr->setValue(storm::utility::zero<ValueType>());
940 if (dropZeroEntries) {
941 this->dropZeroEntries();
942 }
944
945template<typename ValueType>
947 const_iterator end1 = this->end(i1);
948 const_iterator end2 = this->end(i2);
949 const_iterator it1 = this->begin(i1);
950 const_iterator it2 = this->begin(i2);
951 for (; it1 != end1 && it2 != end2; ++it1, ++it2) {
952 if (*it1 != *it2) {
953 return false;
954 }
955 }
956 if (it1 == end1 && it2 == end2) {
957 return true;
958 }
959 return false;
960}
961
962template<typename ValueType>
964 BitVector bv(this->getRowCount());
965 for (size_t rowgroup = 0; rowgroup < this->getRowGroupCount(); ++rowgroup) {
966 for (size_t row1 = this->getRowGroupIndices().at(rowgroup); row1 < this->getRowGroupIndices().at(rowgroup + 1); ++row1) {
967 for (size_t row2 = row1; row2 < this->getRowGroupIndices().at(rowgroup + 1); ++row2) {
968 if (compareRows(row1, row2)) {
969 bv.set(row2);
970 }
971 }
972 }
973 }
974 return bv;
975}
976
977template<typename ValueType>
979 if (row1 == row2) {
980 return;
981 }
982
983 // Get the index of the row that has more / less entries than the other.
984 index_type largerRow = getRow(row1).getNumberOfEntries() > getRow(row2).getNumberOfEntries() ? row1 : row2;
985 index_type smallerRow = largerRow == row1 ? row2 : row1;
986 index_type rowSizeDifference = getRow(largerRow).getNumberOfEntries() - getRow(smallerRow).getNumberOfEntries();
987
988 // Save contents of larger row.
989 auto copyRow = getRow(largerRow);
990 std::vector<MatrixEntry<index_type, value_type>> largerRowContents(copyRow.begin(), copyRow.end());
991
992 if (largerRow < smallerRow) {
993 auto writeIt = getRows(largerRow, smallerRow + 1).begin();
994
995 // Write smaller row to its new position.
996 for (auto& smallerRowEntry : getRow(smallerRow)) {
997 *writeIt = std::move(smallerRowEntry);
998 ++writeIt;
999 }
1000
1001 // Write the intermediate rows into their correct position.
1002 if (!storm::utility::isZero(rowSizeDifference)) {
1003 for (auto& intermediateRowEntry : getRows(largerRow + 1, smallerRow)) {
1004 *writeIt = std::move(intermediateRowEntry);
1005 ++writeIt;
1006 }
1007 } else {
1008 // skip the intermediate rows
1009 writeIt = getRow(smallerRow).begin();
1010 }
1011
1012 // Write the larger row to its new position.
1013 for (auto& largerRowEntry : largerRowContents) {
1014 *writeIt = std::move(largerRowEntry);
1015 ++writeIt;
1016 }
1017
1018 STORM_LOG_ASSERT(writeIt == getRow(smallerRow).end(), "Unexpected position of write iterator.");
1019
1020 // Update the row indications to account for the shift of indices at where the rows now start.
1021 if (!storm::utility::isZero(rowSizeDifference)) {
1022 for (index_type row = largerRow + 1; row <= smallerRow; ++row) {
1023 rowIndications[row] -= rowSizeDifference;
1024 }
1025 }
1026 } else {
1027 auto writeIt = getRows(smallerRow, largerRow + 1).end() - 1;
1028
1029 // Write smaller row to its new position
1030 auto copyRow = getRow(smallerRow);
1031 for (auto smallerRowEntryIt = copyRow.end() - 1; smallerRowEntryIt != copyRow.begin() - 1; --smallerRowEntryIt) {
1032 *writeIt = std::move(*smallerRowEntryIt);
1033 --writeIt;
1034 }
1035
1036 // Write the intermediate rows into their correct position.
1037 if (!storm::utility::isZero(rowSizeDifference)) {
1038 for (auto intermediateRowEntryIt = getRows(smallerRow + 1, largerRow).end() - 1;
1039 intermediateRowEntryIt != getRows(smallerRow + 1, largerRow).begin() - 1; --intermediateRowEntryIt) {
1040 *writeIt = std::move(*intermediateRowEntryIt);
1041 --writeIt;
1043 } else {
1044 // skip the intermediate rows
1045 writeIt = getRow(smallerRow).end() - 1;
1046 }
1047
1048 // Write the larger row to its new position.
1049 for (auto largerRowEntryIt = largerRowContents.rbegin(); largerRowEntryIt != largerRowContents.rend(); ++largerRowEntryIt) {
1050 *writeIt = std::move(*largerRowEntryIt);
1051 --writeIt;
1053
1054 STORM_LOG_ASSERT(writeIt == getRow(smallerRow).begin() - 1, "Unexpected position of write iterator.");
1056 // Update row indications.
1057 // Update the row indications to account for the shift of indices at where the rows now start.
1058 if (!storm::utility::isZero(rowSizeDifference)) {
1059 for (index_type row = smallerRow + 1; row <= largerRow; ++row) {
1060 rowIndications[row] += rowSizeDifference;
1061 }
1062 }
1064}
1065
1066template<typename ValueType>
1067std::vector<ValueType> SparseMatrix<ValueType>::getRowSumVector() const {
1068 std::vector<ValueType> result(this->getRowCount());
1069
1070 index_type row = 0;
1071 for (auto resultIt = result.begin(), resultIte = result.end(); resultIt != resultIte; ++resultIt, ++row) {
1072 *resultIt = getRowSum(row);
1073 }
1074
1075 return result;
1076}
1077
1078template<typename ValueType>
1080 ValueType result = storm::utility::zero<ValueType>();
1081 for (const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) {
1082 if (constraint.get(it->getColumn())) {
1083 result += it->getValue();
1084 }
1085 }
1086 return result;
1088
1089template<typename ValueType>
1091 storm::storage::BitVector const& columnConstraint) const {
1092 std::vector<ValueType> result(rowConstraint.getNumberOfSetBits());
1093 index_type currentRowCount = 0;
1094 for (auto row : rowConstraint) {
1095 result[currentRowCount++] = getConstrainedRowSum(row, columnConstraint);
1097 return result;
1098}
1099
1100template<typename ValueType>
1102 storm::storage::BitVector const& columnConstraint) const {
1103 std::vector<ValueType> result;
1104 result.reserve(this->getNumRowsInRowGroups(rowGroupConstraint));
1105 if (!this->hasTrivialRowGrouping()) {
1106 for (auto rowGroup : rowGroupConstraint) {
1107 for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) {
1108 result.push_back(getConstrainedRowSum(row, columnConstraint));
1109 }
1110 }
1111 } else {
1112 for (auto rowGroup : rowGroupConstraint) {
1113 result.push_back(getConstrainedRowSum(rowGroup, columnConstraint));
1114 }
1115 }
1116 return result;
1117}
1118
1119template<typename ValueType>
1121 storm::storage::BitVector const& columnConstraint, bool insertDiagonalElements,
1122 storm::storage::BitVector const& makeZeroColumns) const {
1123 if (useGroups) {
1124 return getSubmatrix(rowConstraint, columnConstraint, this->getRowGroupIndices(), insertDiagonalElements, makeZeroColumns);
1125 } else {
1126 // Create a fake row grouping to reduce this to a call to a more general method.
1127 std::vector<index_type> fakeRowGroupIndices(rowCount + 1);
1129 for (std::vector<index_type>::iterator it = fakeRowGroupIndices.begin(); it != fakeRowGroupIndices.end(); ++it, ++i) {
1130 *it = i;
1131 }
1132 auto res = getSubmatrix(rowConstraint, columnConstraint, fakeRowGroupIndices, insertDiagonalElements, makeZeroColumns);
1133
1134 // Create a new row grouping that reflects the new sizes of the row groups if the current matrix has a
1135 // non trivial row-grouping.
1136 if (!this->hasTrivialRowGrouping()) {
1137 std::vector<index_type> newRowGroupIndices;
1138 newRowGroupIndices.push_back(0);
1139 auto selectedRowIt = rowConstraint.begin();
1140
1141 // For this, we need to count how many rows were preserved in every group.
1142 for (index_type group = 0; group < this->getRowGroupCount(); ++group) {
1143 index_type newRowCount = 0;
1144 while (*selectedRowIt < this->getRowGroupIndices()[group + 1]) {
1145 ++selectedRowIt;
1146 ++newRowCount;
1147 }
1148 if (newRowCount > 0) {
1149 newRowGroupIndices.push_back(newRowGroupIndices.back() + newRowCount);
1150 }
1151 }
1153 res.trivialRowGrouping = false;
1154 res.rowGroupIndices = newRowGroupIndices;
1155 }
1156
1157 return res;
1158 }
1159}
1161template<typename ValueType>
1163 storm::storage::BitVector const& columnConstraint, std::vector<index_type> const& rowGroupIndices,
1164 bool insertDiagonalEntries, storm::storage::BitVector const& makeZeroColumns) const {
1165 STORM_LOG_THROW(!rowGroupConstraint.empty() && !columnConstraint.empty(), storm::exceptions::InvalidArgumentException, "Cannot build empty submatrix.");
1166 index_type submatrixColumnCount = columnConstraint.getNumberOfSetBits();
1168 // Start by creating a temporary vector that stores for each index whose bit is set to true the number of
1169 // bits that were set before that particular index.
1170 std::vector<index_type> columnBitsSetBeforeIndex = columnConstraint.getNumberOfSetBitsBeforeIndices();
1171 std::unique_ptr<std::vector<index_type>> tmp;
1172 if (rowGroupConstraint != columnConstraint) {
1173 tmp = std::make_unique<std::vector<index_type>>(rowGroupConstraint.getNumberOfSetBitsBeforeIndices());
1175 std::vector<index_type> const& rowBitsSetBeforeIndex = tmp ? *tmp : columnBitsSetBeforeIndex;
1176
1177 // Then, we need to determine the number of entries and the number of rows of the submatrix.
1178 index_type subEntries = 0;
1179 index_type subRows = 0;
1180 index_type rowGroupCount = 0;
1181 for (auto index : rowGroupConstraint) {
1182 subRows += rowGroupIndices[index + 1] - rowGroupIndices[index];
1183 for (index_type i = rowGroupIndices[index]; i < rowGroupIndices[index + 1]; ++i) {
1184 bool foundDiagonalElement = false;
1185
1186 for (const_iterator it = this->begin(i), ite = this->end(i); it != ite; ++it) {
1187 if (columnConstraint.get(it->getColumn()) && (makeZeroColumns.size() == 0 || !makeZeroColumns.get(it->getColumn()))) {
1188 ++subEntries;
1189
1190 if (columnBitsSetBeforeIndex[it->getColumn()] == rowBitsSetBeforeIndex[index]) {
1191 foundDiagonalElement = true;
1192 }
1193 }
1194 }
1195
1196 // If requested, we need to reserve one entry more for inserting the diagonal zero entry.
1197 if (insertDiagonalEntries && !foundDiagonalElement && rowGroupCount < submatrixColumnCount) {
1198 ++subEntries;
1199 }
1200 }
1201 ++rowGroupCount;
1202 }
1203
1204 // Create and initialize resulting matrix.
1205 SparseMatrixBuilder<ValueType> matrixBuilder(subRows, submatrixColumnCount, subEntries, true, !this->hasTrivialRowGrouping());
1206
1207 // Copy over selected entries.
1208 rowGroupCount = 0;
1209 index_type rowCount = 0;
1210 subEntries = 0;
1211 for (auto index : rowGroupConstraint) {
1212 if (!this->hasTrivialRowGrouping()) {
1213 matrixBuilder.newRowGroup(rowCount);
1214 }
1215 for (index_type i = rowGroupIndices[index]; i < rowGroupIndices[index + 1]; ++i) {
1216 bool insertedDiagonalElement = false;
1217
1218 for (const_iterator it = this->begin(i), ite = this->end(i); it != ite; ++it) {
1219 if (columnConstraint.get(it->getColumn()) && (makeZeroColumns.size() == 0 || !makeZeroColumns.get(it->getColumn()))) {
1220 if (columnBitsSetBeforeIndex[it->getColumn()] == rowBitsSetBeforeIndex[index]) {
1221 insertedDiagonalElement = true;
1222 } else if (insertDiagonalEntries && !insertedDiagonalElement && columnBitsSetBeforeIndex[it->getColumn()] > rowBitsSetBeforeIndex[index]) {
1223 matrixBuilder.addNextValue(rowCount, rowGroupCount, storm::utility::zero<ValueType>());
1224 insertedDiagonalElement = true;
1225 }
1226 ++subEntries;
1227 matrixBuilder.addNextValue(rowCount, columnBitsSetBeforeIndex[it->getColumn()], it->getValue());
1228 }
1229 }
1230 if (insertDiagonalEntries && !insertedDiagonalElement && rowGroupCount < submatrixColumnCount) {
1231 matrixBuilder.addNextValue(rowCount, rowGroupCount, storm::utility::zero<ValueType>());
1232 }
1233 ++rowCount;
1234 }
1235 ++rowGroupCount;
1236 }
1237
1238 return matrixBuilder.build();
1239}
1240
1241template<typename ValueType>
1243 STORM_LOG_ASSERT(rowsToKeep.size() == this->getRowCount(), "Dimensions mismatch.");
1244
1245 // Count the number of entries of the resulting matrix
1246 index_type entryCount = 0;
1247 for (auto row : rowsToKeep) {
1248 entryCount += this->getRow(row).getNumberOfEntries();
1249 }
1250
1251 // Get the smallest row group index such that all row groups with at least this index are empty.
1252 index_type firstTrailingEmptyRowGroup = this->getRowGroupCount();
1253 for (auto groupIndexIt = this->getRowGroupIndices().rbegin() + 1; groupIndexIt != this->getRowGroupIndices().rend(); ++groupIndexIt) {
1254 if (rowsToKeep.getNextSetIndex(*groupIndexIt) != rowsToKeep.size()) {
1255 break;
1256 }
1257 --firstTrailingEmptyRowGroup;
1258 }
1259 STORM_LOG_THROW(allowEmptyRowGroups || firstTrailingEmptyRowGroup == this->getRowGroupCount(), storm::exceptions::InvalidArgumentException,
1260 "Empty rows are not allowed, but row group " << firstTrailingEmptyRowGroup << " is empty.");
1261
1262 // build the matrix. The row grouping will always be considered as nontrivial.
1263 SparseMatrixBuilder<ValueType> builder(rowsToKeep.getNumberOfSetBits(), this->getColumnCount(), entryCount, true, true, this->getRowGroupCount());
1264 index_type newRow = 0;
1265 for (index_type rowGroup = 0; rowGroup < firstTrailingEmptyRowGroup; ++rowGroup) {
1266 // Add a new row group
1267 builder.newRowGroup(newRow);
1268 bool rowGroupEmpty = true;
1269 for (index_type row = rowsToKeep.getNextSetIndex(this->getRowGroupIndices()[rowGroup]); row < this->getRowGroupIndices()[rowGroup + 1];
1270 row = rowsToKeep.getNextSetIndex(row + 1)) {
1271 rowGroupEmpty = false;
1272 for (auto const& entry : this->getRow(row)) {
1273 builder.addNextValue(newRow, entry.getColumn(), entry.getValue());
1274 }
1275 ++newRow;
1276 }
1277 STORM_LOG_THROW(allowEmptyRowGroups || !rowGroupEmpty, storm::exceptions::InvalidArgumentException,
1278 "Empty rows are not allowed, but row group " << rowGroup << " is empty.");
1279 }
1280
1281 // The all remaining row groups will be empty. Note that it is not allowed to call builder.addNewGroup(...) if there are no more rows afterwards.
1282 SparseMatrix<ValueType> res = builder.build();
1283 return res;
1284}
1285
1286template<typename ValueType>
1288 // Count the number of entries in the resulting matrix.
1289 index_type entryCount = 0;
1290 for (auto row : rowFilter) {
1291 entryCount += getRow(row).getNumberOfEntries();
1292 }
1293
1294 // Build the resulting matrix.
1295 SparseMatrixBuilder<ValueType> builder(getRowCount(), getColumnCount(), entryCount);
1296 for (auto row : rowFilter) {
1297 for (auto const& entry : getRow(row)) {
1298 builder.addNextValue(row, entry.getColumn(), entry.getValue());
1299 }
1300 }
1301 SparseMatrix<ValueType> result = builder.build();
1302
1303 // Add a row grouping if necessary.
1304 if (!hasTrivialRowGrouping()) {
1305 result.setRowGroupIndices(getRowGroupIndices());
1306 }
1307 return result;
1308}
1309
1310template<typename ValueType>
1312 updateNonzeroEntryCount();
1313 if (getNonzeroEntryCount() != getEntryCount()) {
1314 SparseMatrixBuilder<ValueType> builder(getRowCount(), getColumnCount(), getNonzeroEntryCount(), true);
1315 for (index_type row = 0; row < getRowCount(); ++row) {
1316 for (auto const& entry : getRow(row)) {
1317 if (!storm::utility::isZero(entry.getValue())) {
1318 builder.addNextValue(row, entry.getColumn(), entry.getValue());
1319 }
1320 }
1321 }
1322 SparseMatrix<ValueType> result = builder.build();
1323 // Add a row grouping if necessary.
1324 if (!hasTrivialRowGrouping()) {
1325 result.setRowGroupIndices(getRowGroupIndices());
1326 }
1327 *this = std::move(result);
1328 }
1329}
1330
1331template<typename ValueType>
1332SparseMatrix<ValueType> SparseMatrix<ValueType>::selectRowsFromRowGroups(std::vector<index_type> const& rowGroupToRowIndexMapping,
1333 bool insertDiagonalEntries) const {
1334 // First, we need to count how many non-zero entries the resulting matrix will have and reserve space for
1335 // diagonal entries if requested.
1336 index_type subEntries = 0;
1337 for (index_type rowGroupIndex = 0, rowGroupIndexEnd = rowGroupToRowIndexMapping.size(); rowGroupIndex < rowGroupIndexEnd; ++rowGroupIndex) {
1338 // Determine which row we need to select from the current row group.
1339 STORM_LOG_ASSERT(rowGroupToRowIndexMapping[rowGroupIndex] < this->getRowGroupSize(rowGroupIndex),
1340 "Cannot point to row offset " << rowGroupToRowIndexMapping[rowGroupIndex] << " for rowGroup " << rowGroupIndex << " which starts at "
1341 << this->getRowGroupIndices()[rowGroupIndex] << " and ends at "
1342 << this->getRowGroupIndices()[rowGroupIndex + 1] << ".");
1343 index_type rowToCopy = this->getRowGroupIndices()[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex];
1344
1345 // Iterate through that row and count the number of slots we have to reserve for copying.
1346 bool foundDiagonalElement = false;
1347 for (const_iterator it = this->begin(rowToCopy), ite = this->end(rowToCopy); it != ite; ++it) {
1348 if (it->getColumn() == rowGroupIndex) {
1349 foundDiagonalElement = true;
1350 }
1351 ++subEntries;
1352 }
1353 if (insertDiagonalEntries && !foundDiagonalElement) {
1354 ++subEntries;
1355 }
1356 }
1357
1358 // Now create the matrix to be returned with the appropriate size.
1359 SparseMatrixBuilder<ValueType> matrixBuilder(rowGroupIndices.get().size() - 1, columnCount, subEntries);
1360
1361 // Copy over the selected lines from the source matrix.
1362 for (index_type rowGroupIndex = 0, rowGroupIndexEnd = rowGroupToRowIndexMapping.size(); rowGroupIndex < rowGroupIndexEnd; ++rowGroupIndex) {
1363 // Determine which row we need to select from the current row group.
1364 index_type rowToCopy = this->getRowGroupIndices()[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex];
1365
1366 // Iterate through that row and copy the entries. This also inserts a zero element on the diagonal if
1367 // there is no entry yet.
1368 bool insertedDiagonalElement = false;
1369 for (const_iterator it = this->begin(rowToCopy), ite = this->end(rowToCopy); it != ite; ++it) {
1370 if (it->getColumn() == rowGroupIndex) {
1371 insertedDiagonalElement = true;
1372 } else if (insertDiagonalEntries && !insertedDiagonalElement && it->getColumn() > rowGroupIndex) {
1373 matrixBuilder.addNextValue(rowGroupIndex, rowGroupIndex, storm::utility::zero<ValueType>());
1374 insertedDiagonalElement = true;
1375 }
1376 matrixBuilder.addNextValue(rowGroupIndex, it->getColumn(), it->getValue());
1377 }
1378 if (insertDiagonalEntries && !insertedDiagonalElement) {
1379 matrixBuilder.addNextValue(rowGroupIndex, rowGroupIndex, storm::utility::zero<ValueType>());
1380 }
1381 }
1382
1383 // Finalize created matrix and return result.
1384 return matrixBuilder.build();
1385}
1386
1387template<typename ValueType>
1389 bool insertDiagonalEntries) const {
1390 // First, we need to count how many non-zero entries the resulting matrix will have and reserve space for
1391 // diagonal entries if requested.
1392 index_type newEntries = 0;
1393 for (index_type row = 0, rowEnd = rowIndexSequence.size(); row < rowEnd; ++row) {
1394 bool foundDiagonalElement = false;
1395 for (const_iterator it = this->begin(rowIndexSequence[row]), ite = this->end(rowIndexSequence[row]); it != ite; ++it) {
1396 if (it->getColumn() == row) {
1397 foundDiagonalElement = true;
1398 }
1399 ++newEntries;
1400 }
1401 if (insertDiagonalEntries && !foundDiagonalElement) {
1402 ++newEntries;
1403 }
1404 }
1405
1406 // Now create the matrix to be returned with the appropriate size.
1407 SparseMatrixBuilder<ValueType> matrixBuilder(rowIndexSequence.size(), columnCount, newEntries);
1408
1409 // Copy over the selected rows from the source matrix.
1410 for (index_type row = 0, rowEnd = rowIndexSequence.size(); row < rowEnd; ++row) {
1411 bool insertedDiagonalElement = false;
1412 for (const_iterator it = this->begin(rowIndexSequence[row]), ite = this->end(rowIndexSequence[row]); it != ite; ++it) {
1413 if (it->getColumn() == row) {
1414 insertedDiagonalElement = true;
1415 } else if (insertDiagonalEntries && !insertedDiagonalElement && it->getColumn() > row) {
1416 matrixBuilder.addNextValue(row, row, storm::utility::zero<ValueType>());
1417 insertedDiagonalElement = true;
1418 }
1419 matrixBuilder.addNextValue(row, it->getColumn(), it->getValue());
1420 }
1421 if (insertDiagonalEntries && !insertedDiagonalElement) {
1422 matrixBuilder.addNextValue(row, row, storm::utility::zero<ValueType>());
1423 }
1424 }
1425
1426 // Finally create matrix and return result.
1427 return matrixBuilder.build();
1428}
1429
1430template<typename ValueType>
1431SparseMatrix<ValueType> SparseMatrix<ValueType>::permuteRows(std::vector<index_type> const& inversePermutation) const {
1432 // Now create the matrix to be returned with the appropriate size.
1433 // The entry size is only adequate if this is indeed a permutation.
1434 SparseMatrixBuilder<ValueType> matrixBuilder(inversePermutation.size(), columnCount, entryCount);
1435
1436 // Copy over the selected rows from the source matrix.
1437
1438 for (index_type writeTo = 0; writeTo < inversePermutation.size(); ++writeTo) {
1439 index_type const& readFrom = inversePermutation[writeTo];
1440 auto row = this->getRow(readFrom);
1441 for (auto const& entry : row) {
1442 matrixBuilder.addNextValue(writeTo, entry.getColumn(), entry.getValue());
1443 }
1444 }
1445 // Finally create matrix and return result.
1446 auto result = matrixBuilder.build();
1447 if (this->rowGroupIndices) {
1448 result.setRowGroupIndices(this->rowGroupIndices.get());
1449 }
1450 return result;
1451}
1452
1453template<typename ValueType>
1454SparseMatrix<ValueType> SparseMatrix<ValueType>::permuteRowGroupsAndColumns(std::vector<index_type> const& inverseRowGroupPermutation,
1455 std::vector<index_type> const& columnPermutation) const {
1456 STORM_LOG_ASSERT(storm::utility::permutation::isValidPermutation(inverseRowGroupPermutation), "Row group permutation is not a permutation.");
1457 STORM_LOG_ASSERT(storm::utility::permutation::isValidPermutation(columnPermutation), "Column permutation is not a permutation.");
1458 index_type const rowCount = getRowCount();
1459 SparseMatrixBuilder<ValueType> matrixBuilder(rowCount, getColumnCount(), getEntryCount(), true, !hasTrivialRowGrouping(), getRowGroupCount());
1460 auto oldGroupIt = inverseRowGroupPermutation.cbegin();
1461 index_type newRowIndex = 0;
1462 while (newRowIndex < rowCount) {
1463 if (!hasTrivialRowGrouping()) {
1464 matrixBuilder.newRowGroup(newRowIndex);
1465 }
1466 for (auto oldRowIndex : getRowGroupIndices(*oldGroupIt)) {
1467 for (auto const& oldEntry : getRow(oldRowIndex)) {
1468 matrixBuilder.addNextValue(newRowIndex, columnPermutation[oldEntry.getColumn()], oldEntry.getValue());
1469 }
1470 ++newRowIndex;
1471 }
1472 ++oldGroupIt;
1473 }
1474 return matrixBuilder.build();
1475}
1476
1477template<typename ValueType>
1478SparseMatrix<ValueType> SparseMatrix<ValueType>::transpose(bool joinGroups, bool keepZeros) const {
1479 index_type rowCount = this->getColumnCount();
1480 index_type columnCount = joinGroups ? this->getRowGroupCount() : this->getRowCount();
1481 index_type entryCount;
1482 if (keepZeros) {
1483 entryCount = this->getEntryCount();
1484 } else {
1485 this->updateNonzeroEntryCount();
1486 entryCount = this->getNonzeroEntryCount();
1487 }
1488
1489 std::vector<index_type> rowIndications(rowCount + 1);
1490 std::vector<MatrixEntry<index_type, ValueType>> columnsAndValues(entryCount);
1491
1492 // First, we need to count how many entries each column has.
1493 for (index_type group = 0; group < columnCount; ++group) {
1494 for (auto const& transition : joinGroups ? this->getRowGroup(group) : this->getRow(group)) {
1495 if (transition.getValue() != storm::utility::zero<ValueType>() || keepZeros) {
1496 ++rowIndications[transition.getColumn() + 1];
1497 }
1498 }
1499 }
1500
1501 // Now compute the accumulated offsets.
1502 for (index_type i = 1; i < rowCount + 1; ++i) {
1503 rowIndications[i] = rowIndications[i - 1] + rowIndications[i];
1504 }
1505
1506 // Create an array that stores the index for the next value to be added for
1507 // each row in the transposed matrix. Initially this corresponds to the previously
1508 // computed accumulated offsets.
1509 std::vector<index_type> nextIndices = rowIndications;
1510
1511 // Now we are ready to actually fill in the values of the transposed matrix.
1512 for (index_type group = 0; group < columnCount; ++group) {
1513 for (auto const& transition : joinGroups ? this->getRowGroup(group) : this->getRow(group)) {
1514 if (transition.getValue() != storm::utility::zero<ValueType>() || keepZeros) {
1515 columnsAndValues[nextIndices[transition.getColumn()]] = std::make_pair(group, transition.getValue());
1516 nextIndices[transition.getColumn()]++;
1517 }
1518 }
1519 }
1520
1521 storm::storage::SparseMatrix<ValueType> transposedMatrix(columnCount, std::move(rowIndications), std::move(columnsAndValues), boost::none);
1522
1523 return transposedMatrix;
1524}
1525
1526template<typename ValueType>
1527SparseMatrix<ValueType> SparseMatrix<ValueType>::transposeSelectedRowsFromRowGroups(std::vector<uint64_t> const& rowGroupChoices, bool keepZeros) const {
1528 index_type rowCount = this->getColumnCount();
1529 index_type columnCount = this->getRowGroupCount();
1530
1531 // Get the overall entry count as well as the number of entries of each column
1532 index_type entryCount = 0;
1533 std::vector<index_type> rowIndications(columnCount + 1);
1534 auto rowGroupChoiceIt = rowGroupChoices.begin();
1535 for (index_type rowGroup = 0; rowGroup < columnCount; ++rowGroup, ++rowGroupChoiceIt) {
1536 for (auto const& entry : this->getRow(rowGroup, *rowGroupChoiceIt)) {
1537 if (keepZeros || !storm::utility::isZero(entry.getValue())) {
1538 ++entryCount;
1539 ++rowIndications[entry.getColumn() + 1];
1540 }
1541 }
1542 }
1543
1544 // Now compute the accumulated offsets.
1545 for (index_type i = 1; i < rowCount + 1; ++i) {
1546 rowIndications[i] = rowIndications[i - 1] + rowIndications[i];
1547 }
1548
1549 std::vector<MatrixEntry<index_type, ValueType>> columnsAndValues(entryCount);
1550
1551 // Create an array that stores the index for the next value to be added for
1552 // each row in the transposed matrix. Initially this corresponds to the previously
1553 // computed accumulated offsets.
1554 std::vector<index_type> nextIndices = rowIndications;
1555
1556 // Now we are ready to actually fill in the values of the transposed matrix.
1557 rowGroupChoiceIt = rowGroupChoices.begin();
1558 for (index_type rowGroup = 0; rowGroup < columnCount; ++rowGroup, ++rowGroupChoiceIt) {
1559 for (auto const& entry : this->getRow(rowGroup, *rowGroupChoiceIt)) {
1560 if (keepZeros || !storm::utility::isZero(entry.getValue())) {
1561 columnsAndValues[nextIndices[entry.getColumn()]] = std::make_pair(rowGroup, entry.getValue());
1562 ++nextIndices[entry.getColumn()];
1563 }
1564 }
1565 }
1566
1567 return storm::storage::SparseMatrix<ValueType>(std::move(columnCount), std::move(rowIndications), std::move(columnsAndValues), boost::none);
1568}
1569
1570template<typename ValueType>
1572 invertDiagonal();
1573 negateAllNonDiagonalEntries();
1574}
1575
1576template<typename ValueType>
1578 // Now iterate over all row groups and set the diagonal elements to the inverted value.
1579 // If there is a row without the diagonal element, an exception is thrown.
1580 ValueType one = storm::utility::one<ValueType>();
1581 ValueType zero = storm::utility::zero<ValueType>();
1582 bool foundDiagonalElement = false;
1583 for (index_type group = 0; group < this->getRowGroupCount(); ++group) {
1584 for (auto& entry : this->getRowGroup(group)) {
1585 if (entry.getColumn() == group) {
1586 if (entry.getValue() == one) {
1587 --this->nonzeroEntryCount;
1588 entry.setValue(zero);
1589 } else if (entry.getValue() == zero) {
1590 ++this->nonzeroEntryCount;
1591 entry.setValue(one);
1592 } else {
1593 entry.setValue(one - entry.getValue());
1594 }
1595 foundDiagonalElement = true;
1596 }
1597 }
1598
1599 // Throw an exception if a row did not have an element on the diagonal.
1600 if (!foundDiagonalElement) {
1601 throw storm::exceptions::InvalidArgumentException() << "Illegal call to SparseMatrix::invertDiagonal: matrix is missing diagonal entries.";
1602 }
1603 }
1604}
1605
1606template<typename ValueType>
1608 // Iterate over all row groups and negate all the elements that are not on the diagonal.
1609 for (index_type group = 0; group < this->getRowGroupCount(); ++group) {
1610 for (auto& entry : this->getRowGroup(group)) {
1611 if (entry.getColumn() != group) {
1612 entry.setValue(-entry.getValue());
1613 }
1614 }
1615 }
1616}
1617
1618template<typename ValueType>
1620 // Iterate over all rows and negate all the elements that are not on the diagonal.
1621 for (index_type group = 0; group < this->getRowGroupCount(); ++group) {
1622 for (auto& entry : this->getRowGroup(group)) {
1623 if (entry.getColumn() == group) {
1624 --this->nonzeroEntryCount;
1625 entry.setValue(storm::utility::zero<ValueType>());
1626 }
1627 }
1628 }
1629 if (dropZeroEntries) {
1630 this->dropZeroEntries();
1631 }
1632}
1633
1634template<typename ValueType>
1635typename std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> SparseMatrix<ValueType>::getJacobiDecomposition() const {
1636 STORM_LOG_THROW(this->getRowCount() == this->getColumnCount(), storm::exceptions::InvalidArgumentException,
1637 "Canno compute Jacobi decomposition of non-square matrix.");
1638
1639 // Prepare the resulting data structures.
1640 SparseMatrixBuilder<ValueType> luBuilder(this->getRowCount(), this->getColumnCount());
1641 std::vector<ValueType> invertedDiagonal(rowCount);
1642
1643 // Copy entries to the appropriate matrices.
1644 for (index_type rowNumber = 0; rowNumber < rowCount; ++rowNumber) {
1645 for (const_iterator it = this->begin(rowNumber), ite = this->end(rowNumber); it != ite; ++it) {
1646 if (it->getColumn() == rowNumber) {
1647 invertedDiagonal[rowNumber] = storm::utility::one<ValueType>() / it->getValue();
1648 } else {
1649 luBuilder.addNextValue(rowNumber, it->getColumn(), it->getValue());
1650 }
1651 }
1652 }
1653
1654 return std::make_pair(luBuilder.build(), std::move(invertedDiagonal));
1655}
1656
1657#ifdef STORM_HAVE_CARL
1658template<>
1659typename std::pair<storm::storage::SparseMatrix<Interval>, std::vector<Interval>> SparseMatrix<Interval>::getJacobiDecomposition() const {
1660 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This operation is not supported.");
1661}
1662
1663template<>
1664typename std::pair<storm::storage::SparseMatrix<RationalFunction>, std::vector<RationalFunction>> SparseMatrix<RationalFunction>::getJacobiDecomposition()
1665 const {
1666 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This operation is not supported.");
1667}
1668#endif
1669
1670template<typename ValueType>
1671template<typename OtherValueType, typename ResultValueType>
1673 index_type const& row) const {
1674 typename storm::storage::SparseMatrix<ValueType>::const_iterator it1 = this->begin(row);
1675 typename storm::storage::SparseMatrix<ValueType>::const_iterator ite1 = this->end(row);
1678
1679 ResultValueType result = storm::utility::zero<ResultValueType>();
1680 for (; it1 != ite1 && it2 != ite2; ++it1) {
1681 if (it1->getColumn() < it2->getColumn()) {
1682 continue;
1683 } else {
1684 // If the precondition of this method (i.e. that the given matrix is a submatrix
1685 // of the current one) was fulfilled, we know now that the two elements are in
1686 // the same column, so we can multiply and add them to the row sum vector.
1687 STORM_LOG_ASSERT(it1->getColumn() == it2->getColumn(), "The given matrix is not a submatrix of this one.");
1688 result += it2->getValue() * OtherValueType(it1->getValue());
1689 ++it2;
1690 }
1691 }
1692 return result;
1693}
1694
1695template<typename ValueType>
1696template<typename OtherValueType, typename ResultValueType>
1698 std::vector<ResultValueType> result;
1699 result.reserve(rowCount);
1700 for (index_type row = 0; row < rowCount && row < otherMatrix.getRowCount(); ++row) {
1701 result.push_back(getPointwiseProductRowSum<OtherValueType, ResultValueType>(otherMatrix, row));
1702 }
1703 return result;
1704}
1705
1706template<typename ValueType>
1707void SparseMatrix<ValueType>::multiplyWithVector(std::vector<ValueType> const& vector, std::vector<ValueType>& result,
1708 std::vector<value_type> const* summand) const {
1709 // If the vector and the result are aliases and this is not set to be allowed, we need and temporary vector.
1710 std::vector<ValueType>* target;
1711 std::vector<ValueType> temporary;
1712 if (&vector == &result) {
1713 STORM_LOG_WARN("Vectors are aliased. Using temporary, which is potentially slow.");
1714 temporary = std::vector<ValueType>(vector.size());
1715 target = &temporary;
1716 } else {
1717 target = &result;
1718 }
1719
1720 this->multiplyWithVectorForward(vector, *target, summand);
1721
1722 if (target == &temporary) {
1723 std::swap(result, *target);
1724 }
1725}
1726
1727template<typename ValueType>
1728void SparseMatrix<ValueType>::multiplyWithVectorForward(std::vector<ValueType> const& vector, std::vector<ValueType>& result,
1729 std::vector<value_type> const* summand) const {
1730 const_iterator it = this->begin();
1731 const_iterator ite;
1732 std::vector<index_type>::const_iterator rowIterator = rowIndications.begin();
1733 typename std::vector<ValueType>::iterator resultIterator = result.begin();
1734 typename std::vector<ValueType>::iterator resultIteratorEnd = result.end();
1735 typename std::vector<ValueType>::const_iterator summandIterator;
1736 if (summand) {
1737 summandIterator = summand->begin();
1738 }
1739
1740 for (; resultIterator != resultIteratorEnd; ++rowIterator, ++resultIterator, ++summandIterator) {
1741 ValueType newValue;
1742 if (summand) {
1743 newValue = *summandIterator;
1744 } else {
1745 newValue = storm::utility::zero<ValueType>();
1746 }
1747
1748 for (ite = this->begin() + *(rowIterator + 1); it != ite; ++it) {
1749 newValue += it->getValue() * vector[it->getColumn()];
1750 }
1751
1752 *resultIterator = newValue;
1753 }
1754}
1755
1756template<typename ValueType>
1757void SparseMatrix<ValueType>::multiplyWithVectorBackward(std::vector<ValueType> const& vector, std::vector<ValueType>& result,
1758 std::vector<value_type> const* summand) const {
1759 const_iterator it = this->end() - 1;
1760 const_iterator ite;
1761 std::vector<index_type>::const_iterator rowIterator = rowIndications.end() - 2;
1762 typename std::vector<ValueType>::iterator resultIterator = result.end() - 1;
1763 typename std::vector<ValueType>::iterator resultIteratorEnd = result.begin() - 1;
1764 typename std::vector<ValueType>::const_iterator summandIterator;
1765 if (summand) {
1766 summandIterator = summand->end() - 1;
1767 }
1768
1769 for (; resultIterator != resultIteratorEnd; --rowIterator, --resultIterator, --summandIterator) {
1770 ValueType newValue;
1771 if (summand) {
1772 newValue = *summandIterator;
1773 } else {
1774 newValue = storm::utility::zero<ValueType>();
1775 }
1776
1777 for (ite = this->begin() + *rowIterator - 1; it != ite; --it) {
1778 newValue += (it->getValue() * vector[it->getColumn()]);
1779 }
1780
1781 *resultIterator = newValue;
1782 }
1783}
1784
1785#ifdef STORM_HAVE_INTELTBB
1786template<typename ValueType>
1787class TbbMultAddFunctor {
1788 public:
1789 typedef typename storm::storage::SparseMatrix<ValueType>::index_type index_type;
1790 typedef typename storm::storage::SparseMatrix<ValueType>::value_type value_type;
1791 typedef typename storm::storage::SparseMatrix<ValueType>::const_iterator const_iterator;
1792
1793 TbbMultAddFunctor(std::vector<MatrixEntry<index_type, value_type>> const& columnsAndEntries, std::vector<uint64_t> const& rowIndications,
1794 std::vector<ValueType> const& x, std::vector<ValueType>& result, std::vector<value_type> const* summand)
1795 : columnsAndEntries(columnsAndEntries), rowIndications(rowIndications), x(x), result(result), summand(summand) {
1796 // Intentionally left empty.
1797 }
1798
1799 void operator()(tbb::blocked_range<index_type> const& range) const {
1800 index_type startRow = range.begin();
1801 index_type endRow = range.end();
1802 typename std::vector<index_type>::const_iterator rowIterator = rowIndications.begin() + startRow;
1803 const_iterator it = columnsAndEntries.begin() + *rowIterator;
1804 const_iterator ite;
1805 typename std::vector<ValueType>::iterator resultIterator = result.begin() + startRow;
1806 typename std::vector<ValueType>::iterator resultIteratorEnd = result.begin() + endRow;
1807 typename std::vector<ValueType>::const_iterator summandIterator;
1808 if (summand) {
1809 summandIterator = summand->begin() + startRow;
1810 }
1811
1812 for (; resultIterator != resultIteratorEnd; ++rowIterator, ++resultIterator, ++summandIterator) {
1813 ValueType newValue = summand ? *summandIterator : storm::utility::zero<ValueType>();
1814
1815 for (ite = columnsAndEntries.begin() + *(rowIterator + 1); it != ite; ++it) {
1816 newValue += it->getValue() * x[it->getColumn()];
1817 }
1818
1819 *resultIterator = newValue;
1820 }
1821 }
1822
1823 private:
1824 std::vector<MatrixEntry<index_type, value_type>> const& columnsAndEntries;
1825 std::vector<uint64_t> const& rowIndications;
1826 std::vector<ValueType> const& x;
1827 std::vector<ValueType>& result;
1828 std::vector<value_type> const* summand;
1829};
1830
1831template<typename ValueType>
1832void SparseMatrix<ValueType>::multiplyWithVectorParallel(std::vector<ValueType> const& vector, std::vector<ValueType>& result,
1833 std::vector<value_type> const* summand) const {
1834 if (&vector == &result) {
1836 "Matrix-vector-multiplication invoked but the target vector uses the same memory as the input vector. This requires to allocate auxiliary memory.");
1837 std::vector<ValueType> tmpVector(this->getRowCount());
1838 multiplyWithVectorParallel(vector, tmpVector);
1839 result = std::move(tmpVector);
1840 } else {
1841 tbb::parallel_for(tbb::blocked_range<index_type>(0, result.size(), 100),
1842 TbbMultAddFunctor<ValueType>(columnsAndValues, rowIndications, vector, result, summand));
1843 }
1844}
1845#endif
1846
1847template<typename ValueType>
1848ValueType SparseMatrix<ValueType>::multiplyRowWithVector(index_type row, std::vector<ValueType> const& vector) const {
1849 ValueType result = storm::utility::zero<ValueType>();
1850
1851 for (auto const& entry : this->getRow(row)) {
1852 result += entry.getValue() * vector[entry.getColumn()];
1853 }
1854 return result;
1855}
1856
1857template<typename ValueType>
1858void SparseMatrix<ValueType>::performSuccessiveOverRelaxationStep(ValueType omega, std::vector<ValueType>& x, std::vector<ValueType> const& b) const {
1859 const_iterator it = this->end() - 1;
1860 const_iterator ite;
1861 std::vector<index_type>::const_iterator rowIterator = rowIndications.end() - 2;
1862 typename std::vector<ValueType>::const_iterator bIt = b.end() - 1;
1863 typename std::vector<ValueType>::iterator resultIterator = x.end() - 1;
1864 typename std::vector<ValueType>::iterator resultIteratorEnd = x.begin() - 1;
1865
1866 index_type currentRow = getRowCount();
1867 for (; resultIterator != resultIteratorEnd; --rowIterator, --resultIterator, --bIt) {
1868 --currentRow;
1869 ValueType tmpValue = storm::utility::zero<ValueType>();
1870 ValueType diagonalElement = storm::utility::zero<ValueType>();
1871
1872 for (ite = this->begin() + *rowIterator - 1; it != ite; --it) {
1873 if (it->getColumn() != currentRow) {
1874 tmpValue += it->getValue() * x[it->getColumn()];
1875 } else {
1876 diagonalElement += it->getValue();
1877 }
1878 }
1879 assert(!storm::utility::isZero(diagonalElement));
1880 *resultIterator = ((storm::utility::one<ValueType>() - omega) * *resultIterator) + (omega / diagonalElement) * (*bIt - tmpValue);
1881 }
1882}
1883
1884#ifdef STORM_HAVE_CARL
1885template<>
1886void SparseMatrix<Interval>::performSuccessiveOverRelaxationStep(Interval, std::vector<Interval>&, std::vector<Interval> const&) const {
1887 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported.");
1888}
1889#endif
1890
1891template<typename ValueType>
1892void SparseMatrix<ValueType>::performWalkerChaeStep(std::vector<ValueType> const& x, std::vector<ValueType> const& columnSums, std::vector<ValueType> const& b,
1893 std::vector<ValueType> const& ax, std::vector<ValueType>& result) const {
1894 const_iterator it = this->begin();
1895 const_iterator ite;
1896 std::vector<index_type>::const_iterator rowIterator = rowIndications.begin();
1897
1898 // Clear all previous entries.
1899 ValueType zero = storm::utility::zero<ValueType>();
1900 for (auto& entry : result) {
1901 entry = zero;
1902 }
1903
1904 for (index_type row = 0; row < rowCount; ++row, ++rowIterator) {
1905 for (ite = this->begin() + *(rowIterator + 1); it != ite; ++it) {
1906 result[it->getColumn()] += it->getValue() * (b[row] / ax[row]);
1907 }
1908 }
1909
1910 auto xIterator = x.begin();
1911 auto sumsIterator = columnSums.begin();
1912 for (auto& entry : result) {
1913 entry *= *xIterator / *sumsIterator;
1914 ++xIterator;
1915 ++sumsIterator;
1916 }
1917}
1918
1919#ifdef STORM_HAVE_CARL
1920template<>
1921void SparseMatrix<Interval>::performWalkerChaeStep(std::vector<Interval> const& x, std::vector<Interval> const& rowSums, std::vector<Interval> const& b,
1922 std::vector<Interval> const& ax, std::vector<Interval>& result) const {
1923 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported.");
1924}
1925#endif
1926
1927template<typename ValueType>
1928void SparseMatrix<ValueType>::multiplyAndReduceForward(OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices,
1929 std::vector<ValueType> const& vector, std::vector<ValueType> const* summand,
1930 std::vector<ValueType>& result, std::vector<uint64_t>* choices) const {
1931 if (dir == OptimizationDirection::Minimize) {
1932 multiplyAndReduceForward<storm::utility::ElementLess<ValueType>>(rowGroupIndices, vector, summand, result, choices);
1933 } else {
1934 multiplyAndReduceForward<storm::utility::ElementGreater<ValueType>>(rowGroupIndices, vector, summand, result, choices);
1935 }
1936}
1937
1938template<typename ValueType>
1939template<typename Compare>
1940void SparseMatrix<ValueType>::multiplyAndReduceForward(std::vector<uint64_t> const& rowGroupIndices, std::vector<ValueType> const& vector,
1941 std::vector<ValueType> const* summand, std::vector<ValueType>& result,
1942 std::vector<uint64_t>* choices) const {
1943 Compare compare;
1944 auto elementIt = this->begin();
1945 auto rowGroupIt = rowGroupIndices.begin();
1946 auto rowIt = rowIndications.begin();
1947 typename std::vector<ValueType>::const_iterator summandIt;
1948 if (summand) {
1949 summandIt = summand->begin();
1950 }
1951 typename std::vector<uint64_t>::iterator choiceIt;
1952 if (choices) {
1953 choiceIt = choices->begin();
1954 }
1955
1956 // Variables for correctly tracking choices (only update if new choice is strictly better).
1957 ValueType oldSelectedChoiceValue;
1958 uint64_t selectedChoice;
1959
1960 uint64_t currentRow = 0;
1961 for (auto resultIt = result.begin(), resultIte = result.end(); resultIt != resultIte; ++resultIt, ++choiceIt, ++rowGroupIt) {
1962 ValueType currentValue = storm::utility::zero<ValueType>();
1963
1964 // Only multiply and reduce if there is at least one row in the group.
1965 if (*rowGroupIt < *(rowGroupIt + 1)) {
1966 if (summand) {
1967 currentValue = *summandIt;
1968 ++summandIt;
1969 }
1970
1971 for (auto elementIte = this->begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) {
1972 currentValue += elementIt->getValue() * vector[elementIt->getColumn()];
1973 }
1974
1975 if (choices) {
1976 selectedChoice = 0;
1977 if (*choiceIt == 0) {
1978 oldSelectedChoiceValue = currentValue;
1979 }
1980 }
1981
1982 ++rowIt;
1983 ++currentRow;
1984
1985 for (; currentRow < *(rowGroupIt + 1); ++rowIt, ++currentRow) {
1986 ValueType newValue = summand ? *summandIt : storm::utility::zero<ValueType>();
1987 for (auto elementIte = this->begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) {
1988 newValue += elementIt->getValue() * vector[elementIt->getColumn()];
1989 }
1990
1991 if (choices && currentRow == *choiceIt + *rowGroupIt) {
1992 oldSelectedChoiceValue = newValue;
1993 }
1994
1995 if (compare(newValue, currentValue)) {
1996 currentValue = newValue;
1997 if (choices) {
1998 selectedChoice = currentRow - *rowGroupIt;
1999 }
2000 }
2001 if (summand) {
2002 ++summandIt;
2003 }
2004 }
2005
2006 // Finally write value to target vector.
2007 *resultIt = currentValue;
2008 if (choices && compare(currentValue, oldSelectedChoiceValue)) {
2009 *choiceIt = selectedChoice;
2010 }
2011 }
2012 }
2013}
2014
2015#ifdef STORM_HAVE_CARL
2016template<>
2017void SparseMatrix<storm::RationalFunction>::multiplyAndReduceForward(OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices,
2018 std::vector<storm::RationalFunction> const& vector,
2019 std::vector<storm::RationalFunction> const* b,
2020 std::vector<storm::RationalFunction>& result, std::vector<uint64_t>* choices) const {
2021 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported.");
2022}
2023#endif
2024
2025template<typename ValueType>
2026void SparseMatrix<ValueType>::multiplyAndReduceBackward(OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices,
2027 std::vector<ValueType> const& vector, std::vector<ValueType> const* summand,
2028 std::vector<ValueType>& result, std::vector<uint64_t>* choices) const {
2029 if (dir == storm::OptimizationDirection::Minimize) {
2030 multiplyAndReduceBackward<storm::utility::ElementLess<ValueType>>(rowGroupIndices, vector, summand, result, choices);
2031 } else {
2032 multiplyAndReduceBackward<storm::utility::ElementGreater<ValueType>>(rowGroupIndices, vector, summand, result, choices);
2033 }
2034}
2035
2036template<typename ValueType>
2037template<typename Compare>
2038void SparseMatrix<ValueType>::multiplyAndReduceBackward(std::vector<uint64_t> const& rowGroupIndices, std::vector<ValueType> const& vector,
2039 std::vector<ValueType> const* summand, std::vector<ValueType>& result,
2040 std::vector<uint64_t>* choices) const {
2041 Compare compare;
2042 auto elementIt = this->end() - 1;
2043 auto rowGroupIt = rowGroupIndices.end() - 2;
2044 auto rowIt = rowIndications.end() - 2;
2045 typename std::vector<ValueType>::const_iterator summandIt;
2046 if (summand) {
2047 summandIt = summand->end() - 1;
2048 }
2049 typename std::vector<uint64_t>::iterator choiceIt;
2050 if (choices) {
2051 choiceIt = choices->end() - 1;
2052 }
2053
2054 // Variables for correctly tracking choices (only update if new choice is strictly better).
2055 ValueType oldSelectedChoiceValue;
2056 uint64_t selectedChoice;
2057
2058 uint64_t currentRow = this->getRowCount() - 1;
2059 for (auto resultIt = result.end() - 1, resultIte = result.begin() - 1; resultIt != resultIte; --resultIt, --choiceIt, --rowGroupIt) {
2060 ValueType currentValue = storm::utility::zero<ValueType>();
2061
2062 // Only multiply and reduce if there is at least one row in the group.
2063 if (*rowGroupIt < *(rowGroupIt + 1)) {
2064 if (summand) {
2065 currentValue = *summandIt;
2066 --summandIt;
2067 }
2068
2069 for (auto elementIte = this->begin() + *rowIt - 1; elementIt != elementIte; --elementIt) {
2070 currentValue += elementIt->getValue() * vector[elementIt->getColumn()];
2071 }
2072 if (choices) {
2073 selectedChoice = currentRow - *rowGroupIt;
2074 if (*choiceIt == selectedChoice) {
2075 oldSelectedChoiceValue = currentValue;
2076 }
2077 }
2078 --rowIt;
2079 --currentRow;
2080
2081 for (uint64_t i = *rowGroupIt + 1, end = *(rowGroupIt + 1); i < end; --rowIt, --currentRow, ++i, --summandIt) {
2082 ValueType newValue = summand ? *summandIt : storm::utility::zero<ValueType>();
2083 for (auto elementIte = this->begin() + *rowIt - 1; elementIt != elementIte; --elementIt) {
2084 newValue += elementIt->getValue() * vector[elementIt->getColumn()];
2085 }
2086
2087 if (choices && currentRow == *choiceIt + *rowGroupIt) {
2088 oldSelectedChoiceValue = newValue;
2089 }
2090
2091 if (compare(newValue, currentValue)) {
2092 currentValue = newValue;
2093 if (choices) {
2094 selectedChoice = currentRow - *rowGroupIt;
2095 }
2096 }
2097 }
2098
2099 // Finally write value to target vector.
2100 *resultIt = currentValue;
2101 if (choices && compare(currentValue, oldSelectedChoiceValue)) {
2102 *choiceIt = selectedChoice;
2103 }
2104 }
2105 }
2106}
2107
2108#ifdef STORM_HAVE_CARL
2109template<>
2110void SparseMatrix<storm::RationalFunction>::multiplyAndReduceBackward(OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices,
2111 std::vector<storm::RationalFunction> const& vector,
2112 std::vector<storm::RationalFunction> const* b,
2113 std::vector<storm::RationalFunction>& result, std::vector<uint64_t>* choices) const {
2114 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported.");
2115}
2116#endif
2117
2118#ifdef STORM_HAVE_INTELTBB
2119template<typename ValueType, typename Compare>
2120class TbbMultAddReduceFunctor {
2121 public:
2122 typedef typename storm::storage::SparseMatrix<ValueType>::index_type index_type;
2123 typedef typename storm::storage::SparseMatrix<ValueType>::value_type value_type;
2124 typedef typename storm::storage::SparseMatrix<ValueType>::const_iterator const_iterator;
2125
2126 TbbMultAddReduceFunctor(std::vector<uint64_t> const& rowGroupIndices, std::vector<MatrixEntry<index_type, value_type>> const& columnsAndEntries,
2127 std::vector<uint64_t> const& rowIndications, std::vector<ValueType> const& x, std::vector<ValueType>& result,
2128 std::vector<value_type> const* summand, std::vector<uint64_t>* choices)
2129 : rowGroupIndices(rowGroupIndices),
2130 columnsAndEntries(columnsAndEntries),
2131 rowIndications(rowIndications),
2132 x(x),
2133 result(result),
2134 summand(summand),
2135 choices(choices) {
2136 // Intentionally left empty.
2137 }
2138
2139 void operator()(tbb::blocked_range<index_type> const& range) const {
2140 auto groupIt = rowGroupIndices.begin() + range.begin();
2141 auto groupIte = rowGroupIndices.begin() + range.end();
2142
2143 auto rowIt = rowIndications.begin() + *groupIt;
2144 auto elementIt = columnsAndEntries.begin() + *rowIt;
2145 typename std::vector<ValueType>::const_iterator summandIt;
2146 if (summand) {
2147 summandIt = summand->begin() + *groupIt;
2148 }
2149 typename std::vector<uint64_t>::iterator choiceIt;
2150 if (choices) {
2151 choiceIt = choices->begin() + range.begin();
2152 }
2153
2154 auto resultIt = result.begin() + range.begin();
2155
2156 // Variables for correctly tracking choices (only update if new choice is strictly better).
2157 ValueType oldSelectedChoiceValue;
2158 uint64_t selectedChoice;
2159
2160 uint64_t currentRow = *groupIt;
2161 for (; groupIt != groupIte; ++groupIt, ++resultIt, ++choiceIt) {
2162 ValueType currentValue = storm::utility::zero<ValueType>();
2163
2164 // Only multiply and reduce if there is at least one row in the group.
2165 if (*groupIt < *(groupIt + 1)) {
2166 if (summand) {
2167 currentValue = *summandIt;
2168 ++summandIt;
2169 }
2170
2171 for (auto elementIte = columnsAndEntries.begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) {
2172 currentValue += elementIt->getValue() * x[elementIt->getColumn()];
2173 }
2174
2175 if (choices) {
2176 selectedChoice = 0;
2177 if (*choiceIt == 0) {
2178 oldSelectedChoiceValue = currentValue;
2179 }
2180 }
2181
2182 ++rowIt;
2183 ++currentRow;
2184
2185 for (; currentRow < *(groupIt + 1); ++rowIt, ++currentRow, ++summandIt) {
2186 ValueType newValue = summand ? *summandIt : storm::utility::zero<ValueType>();
2187 for (auto elementIte = columnsAndEntries.begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) {
2188 newValue += elementIt->getValue() * x[elementIt->getColumn()];
2189 }
2190
2191 if (choices && currentRow == *choiceIt + *groupIt) {
2192 oldSelectedChoiceValue = newValue;
2193 }
2194
2195 if (compare(newValue, currentValue)) {
2196 currentValue = newValue;
2197 if (choices) {
2198 selectedChoice = currentRow - *groupIt;
2199 }
2200 }
2201 }
2202
2203 // Finally write value to target vector.
2204 *resultIt = currentValue;
2205 if (choices && compare(currentValue, oldSelectedChoiceValue)) {
2206 *choiceIt = selectedChoice;
2207 }
2208 }
2209 }
2210 }
2211
2212 private:
2213 Compare compare;
2214 std::vector<uint64_t> const& rowGroupIndices;
2215 std::vector<MatrixEntry<index_type, value_type>> const& columnsAndEntries;
2216 std::vector<uint64_t> const& rowIndications;
2217 std::vector<ValueType> const& x;
2218 std::vector<ValueType>& result;
2219 std::vector<value_type> const* summand;
2220 std::vector<uint64_t>* choices;
2221};
2222
2223template<typename ValueType>
2224void SparseMatrix<ValueType>::multiplyAndReduceParallel(OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices,
2225 std::vector<ValueType> const& vector, std::vector<ValueType> const* summand,
2226 std::vector<ValueType>& result, std::vector<uint64_t>* choices) const {
2227 if (dir == storm::OptimizationDirection::Minimize) {
2228 tbb::parallel_for(tbb::blocked_range<index_type>(0, rowGroupIndices.size() - 1, 100),
2229 TbbMultAddReduceFunctor<ValueType, storm::utility::ElementLess<ValueType>>(rowGroupIndices, columnsAndValues, rowIndications, vector,
2230 result, summand, choices));
2231 } else {
2232 tbb::parallel_for(tbb::blocked_range<index_type>(0, rowGroupIndices.size() - 1, 100),
2233 TbbMultAddReduceFunctor<ValueType, storm::utility::ElementGreater<ValueType>>(rowGroupIndices, columnsAndValues, rowIndications,
2234 vector, result, summand, choices));
2235 }
2236}
2237
2238#ifdef STORM_HAVE_CARL
2239template<>
2240void SparseMatrix<storm::RationalFunction>::multiplyAndReduceParallel(OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices,
2241 std::vector<storm::RationalFunction> const& vector,
2242 std::vector<storm::RationalFunction> const* summand,
2243 std::vector<storm::RationalFunction>& result, std::vector<uint64_t>* choices) const {
2244 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported.");
2245}
2246#endif
2247#endif
2248
2249template<typename ValueType>
2250void SparseMatrix<ValueType>::multiplyAndReduce(OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices,
2251 std::vector<ValueType> const& vector, std::vector<ValueType> const* summand, std::vector<ValueType>& result,
2252 std::vector<uint64_t>* choices) const {
2253 // If the vector and the result are aliases, we need and temporary vector.
2254 std::vector<ValueType>* target;
2255 std::vector<ValueType> temporary;
2256 if (&vector == &result) {
2257 STORM_LOG_WARN("Vectors are aliased but are not allowed to be. Using temporary, which is potentially slow.");
2258 temporary = std::vector<ValueType>(vector.size());
2259 target = &temporary;
2260 } else {
2261 target = &result;
2262 }
2263
2264 this->multiplyAndReduceForward(dir, rowGroupIndices, vector, summand, *target, choices);
2265
2266 if (target == &temporary) {
2267 std::swap(temporary, result);
2268 }
2269}
2270
2271template<typename ValueType>
2272void SparseMatrix<ValueType>::multiplyVectorWithMatrix(std::vector<value_type> const& vector, std::vector<value_type>& result) const {
2273 const_iterator it = this->begin();
2274 const_iterator ite;
2275 std::vector<index_type>::const_iterator rowIterator = rowIndications.begin();
2276 std::vector<index_type>::const_iterator rowIteratorEnd = rowIndications.end();
2277
2278 index_type currentRow = 0;
2279 for (; rowIterator != rowIteratorEnd - 1; ++rowIterator) {
2280 for (ite = this->begin() + *(rowIterator + 1); it != ite; ++it) {
2281 result[it->getColumn()] += it->getValue() * vector[currentRow];
2282 }
2283 ++currentRow;
2284 }
2285}
2286
2287template<typename ValueType>
2288void SparseMatrix<ValueType>::scaleRowsInPlace(std::vector<ValueType> const& factors) {
2289 STORM_LOG_ASSERT(factors.size() == this->getRowCount(), "Can not scale rows: Number of rows and number of scaling factors do not match.");
2290 index_type row = 0;
2291 for (auto const& factor : factors) {
2292 for (auto& entry : getRow(row)) {
2293 entry.setValue(entry.getValue() * factor);
2294 }
2295 ++row;
2296 }
2297}
2298
2299template<typename ValueType>
2300void SparseMatrix<ValueType>::divideRowsInPlace(std::vector<ValueType> const& divisors) {
2301 STORM_LOG_ASSERT(divisors.size() == this->getRowCount(), "Can not divide rows: Number of rows and number of divisors do not match.");
2302 index_type row = 0;
2303 for (auto const& divisor : divisors) {
2304 STORM_LOG_ASSERT(!storm::utility::isZero(divisor), "Can not divide row " << row << " by 0.");
2305 for (auto& entry : getRow(row)) {
2306 entry.setValue(entry.getValue() / divisor);
2307 }
2308 ++row;
2309 }
2310}
2311
2312#ifdef STORM_HAVE_CARL
2313template<>
2314void SparseMatrix<Interval>::divideRowsInPlace(std::vector<Interval> const&) {
2315 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This operation is not supported.");
2316}
2317#endif
2318
2319template<typename ValueType>
2321 return const_rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow] - this->rowIndications[startRow]);
2322}
2323
2324template<typename ValueType>
2326 return rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow] - this->rowIndications[startRow]);
2327}
2328
2329template<typename ValueType>
2331 return getRows(row, row + 1);
2332}
2333
2334template<typename ValueType>
2336 return getRows(row, row + 1);
2337}
2338
2339template<typename ValueType>
2341 STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds.");
2342 STORM_LOG_ASSERT(offset < this->getRowGroupSize(rowGroup), "Row offset in row-group is out-of-bounds.");
2343 if (!this->hasTrivialRowGrouping()) {
2344 return getRow(this->getRowGroupIndices()[rowGroup] + offset);
2345 } else {
2346 return getRow(this->getRowGroupIndices()[rowGroup] + offset);
2347 }
2348}
2349
2350template<typename ValueType>
2352 STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds.");
2353 STORM_LOG_ASSERT(offset < this->getRowGroupSize(rowGroup), "Row offset in row-group is out-of-bounds.");
2354 if (!this->hasTrivialRowGrouping()) {
2355 return getRow(this->getRowGroupIndices()[rowGroup] + offset);
2356 } else {
2357 STORM_LOG_ASSERT(offset == 0, "Invalid offset.");
2358 return getRow(rowGroup + offset);
2359 }
2360}
2361
2362template<typename ValueType>
2364 STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds.");
2365 if (!this->hasTrivialRowGrouping()) {
2366 return getRows(this->getRowGroupIndices()[rowGroup], this->getRowGroupIndices()[rowGroup + 1]);
2367 } else {
2368 return getRows(rowGroup, rowGroup + 1);
2369 }
2370}
2371
2372template<typename ValueType>
2374 STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds.");
2375 if (!this->hasTrivialRowGrouping()) {
2376 return getRows(this->getRowGroupIndices()[rowGroup], this->getRowGroupIndices()[rowGroup + 1]);
2377 } else {
2378 return getRows(rowGroup, rowGroup + 1);
2379 }
2380}
2381
2382template<typename ValueType>
2384 STORM_LOG_ASSERT(row < this->getRowCount(), "Row " << row << " exceeds row count " << this->getRowCount() << ".");
2385 return this->columnsAndValues.begin() + this->rowIndications[row];
2386}
2387
2388template<typename ValueType>
2390 STORM_LOG_ASSERT(row < this->getRowCount(), "Row " << row << " exceeds row count " << this->getRowCount() << ".");
2391 return this->columnsAndValues.begin() + this->rowIndications[row];
2392}
2393
2394template<typename ValueType>
2396 return this->columnsAndValues.begin();
2397}
2398
2399template<typename ValueType>
2401 return this->columnsAndValues.begin();
2402}
2403
2404template<typename ValueType>
2406 STORM_LOG_ASSERT(row < this->getRowCount(), "Row " << row << " exceeds row count " << this->getRowCount() << ".");
2407 return this->columnsAndValues.begin() + this->rowIndications[row + 1];
2408}
2409
2410template<typename ValueType>
2412 STORM_LOG_ASSERT(row < this->getRowCount(), "Row " << row << " exceeds row count " << this->getRowCount() << ".");
2413 return this->columnsAndValues.begin() + this->rowIndications[row + 1];
2414}
2415
2416template<typename ValueType>
2418 return this->columnsAndValues.begin() + this->rowIndications[rowCount];
2419}
2420
2421template<typename ValueType>
2423 return this->columnsAndValues.begin() + this->rowIndications[rowCount];
2424}
2425
2426template<typename ValueType>
2428 ValueType sum = storm::utility::zero<ValueType>();
2429 for (const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) {
2430 sum += it->getValue();
2431 }
2432 return sum;
2433}
2434
2435template<typename ValueType>
2437 index_type nonConstEntries = 0;
2438 for (auto const& entry : *this) {
2439 if (!storm::utility::isConstant(entry.getValue())) {
2440 ++nonConstEntries;
2441 }
2442 }
2443 return nonConstEntries;
2444}
2445
2446template<typename ValueType>
2448 index_type nonConstRowGroups = 0;
2449 for (index_type rowGroup = 0; rowGroup < this->getRowGroupCount(); ++rowGroup) {
2450 for (auto const& entry : this->getRowGroup(rowGroup)) {
2451 if (!storm::utility::isConstant(entry.getValue())) {
2452 ++nonConstRowGroups;
2453 break;
2454 }
2455 }
2456 }
2457 return nonConstRowGroups;
2458}
2459
2460template<typename ValueType>
2463 for (index_type row = 0; row < this->rowCount; ++row) {
2464 auto rowSum = getRowSum(row);
2465 if (!comparator.isOne(rowSum)) {
2466 return false;
2467 }
2468 }
2469 for (auto const& entry : *this) {
2470 if (comparator.isConstant(entry.getValue())) {
2471 if (comparator.isLess(entry.getValue(), storm::utility::zero<ValueType>())) {
2472 return false;
2473 }
2474 }
2475 }
2476 return true;
2477}
2478
2479template<typename ValueType>
2482 for (auto const& entry : *this) {
2483 if (!comparator.isLess(storm::utility::zero<ValueType>(), entry.getValue())) {
2484 return false;
2485 }
2486 }
2487 return true;
2488}
2489
2490template<typename ValueType>
2491template<typename OtherValueType>
2493 // Check for matching sizes.
2494 if (this->getRowCount() != matrix.getRowCount())
2495 return false;
2496 if (this->getColumnCount() != matrix.getColumnCount())
2497 return false;
2498 if (this->hasTrivialRowGrouping() && !matrix.hasTrivialRowGrouping())
2499 return false;
2500 if (!this->hasTrivialRowGrouping() && matrix.hasTrivialRowGrouping())
2501 return false;
2502 if (!this->hasTrivialRowGrouping() && !matrix.hasTrivialRowGrouping() && this->getRowGroupIndices() != matrix.getRowGroupIndices())
2503 return false;
2504 if (this->getRowGroupIndices() != matrix.getRowGroupIndices())
2505 return false;
2506
2507 // Check the subset property for all rows individually.
2508 for (index_type row = 0; row < this->getRowCount(); ++row) {
2509 auto it2 = matrix.begin(row);
2510 auto ite2 = matrix.end(row);
2511 for (const_iterator it1 = this->begin(row), ite1 = this->end(row); it1 != ite1; ++it1) {
2512 // Skip over all entries of the other matrix that are before the current entry in the current matrix.
2513 while (it2 != ite2 && it2->getColumn() < it1->getColumn()) {
2514 ++it2;
2515 }
2516 if (it2 == ite2 || it1->getColumn() != it2->getColumn()) {
2517 return false;
2518 }
2519 }
2520 }
2521 return true;
2522}
2523
2524template<typename ValueType>
2526 if (this->getRowCount() != this->getColumnCount()) {
2527 return false;
2528 }
2529 if (this->getNonzeroEntryCount() != this->getRowCount()) {
2530 return false;
2531 }
2532 for (uint64_t row = 0; row < this->getRowCount(); ++row) {
2533 bool rowHasEntry = false;
2534 for (auto const& entry : this->getRow(row)) {
2535 if (entry.getColumn() == row) {
2536 if (!storm::utility::isOne(entry.getValue())) {
2537 return false;
2538 }
2539 rowHasEntry = true;
2540 } else {
2541 if (!storm::utility::isZero(entry.getValue())) {
2542 return false;
2543 }
2544 }
2545 }
2546 if (!rowHasEntry) {
2547 return false;
2548 }
2549 }
2550 return true;
2551}
2552
2553template<typename ValueType>
2555 std::string result =
2556 std::to_string(getRowCount()) + "x" + std::to_string(getColumnCount()) + " matrix (" + std::to_string(getNonzeroEntryCount()) + " non-zeroes";
2557 if (!hasTrivialRowGrouping()) {
2558 result += ", " + std::to_string(getRowGroupCount()) + " groups";
2559 }
2560 result += ")";
2561 return result;
2562}
2563
2564template<typename ValueType>
2565std::ostream& operator<<(std::ostream& out, SparseMatrix<ValueType> const& matrix) {
2566 // Print column numbers in header.
2567 out << "\t\t";
2568 for (typename SparseMatrix<ValueType>::index_type i = 0; i < matrix.getColumnCount(); ++i) {
2569 out << i << "\t";
2570 }
2571 out << '\n';
2572
2573 // Iterate over all row groups.
2574 for (typename SparseMatrix<ValueType>::index_type group = 0; group < matrix.getRowGroupCount(); ++group) {
2575 out << "\t---- group " << group << "/" << (matrix.getRowGroupCount() - 1) << " ---- \n";
2576 typename SparseMatrix<ValueType>::index_type start = matrix.hasTrivialRowGrouping() ? group : matrix.getRowGroupIndices()[group];
2577 typename SparseMatrix<ValueType>::index_type end = matrix.hasTrivialRowGrouping() ? group + 1 : matrix.getRowGroupIndices()[group + 1];
2578
2579 for (typename SparseMatrix<ValueType>::index_type i = start; i < end; ++i) {
2580 typename SparseMatrix<ValueType>::index_type nextIndex = matrix.rowIndications[i];
2581
2582 // Print the actual row.
2583 out << i << "\t(\t";
2584 typename SparseMatrix<ValueType>::index_type currentRealIndex = 0;
2585 while (currentRealIndex < matrix.columnCount) {
2586 if (nextIndex < matrix.rowIndications[i + 1] && currentRealIndex == matrix.columnsAndValues[nextIndex].getColumn()) {
2587 out << matrix.columnsAndValues[nextIndex].getValue() << "\t";
2588 ++nextIndex;
2589 } else {
2590 out << "0\t";
2591 }
2592 ++currentRealIndex;
2593 }
2594 out << "\t)\t" << i << '\n';
2595 }
2596 }
2597
2598 // Print column numbers in footer.
2599 out << "\t\t";
2600 for (typename SparseMatrix<ValueType>::index_type i = 0; i < matrix.getColumnCount(); ++i) {
2601 out << i << "\t";
2602 }
2603 out << '\n';
2604
2605 return out;
2606}
2607
2608template<typename ValueType>
2610 // Iterate over all row groups.
2611 for (typename SparseMatrix<ValueType>::index_type group = 0; group < this->getRowGroupCount(); ++group) {
2612 STORM_LOG_ASSERT(this->getRowGroupSize(group) == 1, "Incorrect row group size.");
2613 for (typename SparseMatrix<ValueType>::index_type i = this->getRowGroupIndices()[group]; i < this->getRowGroupIndices()[group + 1]; ++i) {
2614 typename SparseMatrix<ValueType>::index_type nextIndex = this->rowIndications[i];
2615
2616 // Print the actual row.
2617 out << i << "\t(";
2618 typename SparseMatrix<ValueType>::index_type currentRealIndex = 0;
2619 while (currentRealIndex < this->columnCount) {
2620 if (nextIndex < this->rowIndications[i + 1] && currentRealIndex == this->columnsAndValues[nextIndex].getColumn()) {
2621 out << this->columnsAndValues[nextIndex].getValue() << " ";
2622 ++nextIndex;
2623 } else {
2624 out << "0 ";
2625 }
2626 ++currentRealIndex;
2627 }
2628 out << ";\n";
2629 }
2630 }
2631}
2632
2633template<typename ValueType>
2635 std::size_t result = 0;
2636
2637 boost::hash_combine(result, this->getRowCount());
2638 boost::hash_combine(result, this->getColumnCount());
2639 boost::hash_combine(result, this->getEntryCount());
2640 boost::hash_combine(result, boost::hash_range(columnsAndValues.begin(), columnsAndValues.end()));
2641 boost::hash_combine(result, boost::hash_range(rowIndications.begin(), rowIndications.end()));
2642 if (!this->hasTrivialRowGrouping()) {
2643 boost::hash_combine(result, boost::hash_range(rowGroupIndices.get().begin(), rowGroupIndices.get().end()));
2644 }
2645
2646 return result;
2647}
2648
2649// Explicitly instantiate the entry, builder and the matrix.
2650// double
2652template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<double>::index_type, double> const& entry);
2653template class SparseMatrixBuilder<double>;
2654template class SparseMatrix<double>;
2655template std::ostream& operator<<(std::ostream& out, SparseMatrix<double> const& matrix);
2657 typename SparseMatrix<double>::index_type const& row) const;
2658template std::vector<double> SparseMatrix<double>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<double> const& otherMatrix) const;
2659template bool SparseMatrix<double>::isSubmatrixOf(SparseMatrix<double> const& matrix) const;
2660
2661template class MatrixEntry<uint32_t, double>;
2662template std::ostream& operator<<(std::ostream& out, MatrixEntry<uint32_t, double> const& entry);
2663
2664// int
2666template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<int>::index_type, int> const& entry);
2667template class SparseMatrixBuilder<int>;
2668template class SparseMatrix<int>;
2669template std::ostream& operator<<(std::ostream& out, SparseMatrix<int> const& matrix);
2670template bool SparseMatrix<int>::isSubmatrixOf(SparseMatrix<int> const& matrix) const;
2671
2672// state_type
2674template std::ostream& operator<<(
2678template std::ostream& operator<<(std::ostream& out, SparseMatrix<storm::storage::sparse::state_type> const& matrix);
2680
2681#ifdef STORM_HAVE_CARL
2682// Rational Numbers
2683
2684#if defined(STORM_HAVE_CLN)
2686template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<ClnRationalNumber>::index_type, ClnRationalNumber> const& entry);
2688template class SparseMatrix<ClnRationalNumber>;
2689template std::ostream& operator<<(std::ostream& out, SparseMatrix<ClnRationalNumber> const& matrix);
2692template std::vector<storm::ClnRationalNumber> SparseMatrix<ClnRationalNumber>::getPointwiseProductRowSumVector(
2695#endif
2696
2697#if defined(STORM_HAVE_GMP)
2699template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<GmpRationalNumber>::index_type, GmpRationalNumber> const& entry);
2701template class SparseMatrix<GmpRationalNumber>;
2702template std::ostream& operator<<(std::ostream& out, SparseMatrix<GmpRationalNumber> const& matrix);
2705template std::vector<storm::GmpRationalNumber> SparseMatrix<GmpRationalNumber>::getPointwiseProductRowSumVector(
2708#endif
2709
2710// Rational Function
2712template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<RationalFunction>::index_type, RationalFunction> const& entry);
2714template class SparseMatrix<RationalFunction>;
2715template std::ostream& operator<<(std::ostream& out, SparseMatrix<RationalFunction> const& matrix);
2719 typename SparseMatrix<storm::RationalFunction>::index_type const& row) const;
2721 typename SparseMatrix<storm::RationalFunction>::index_type const& row) const;
2722template std::vector<storm::RationalFunction> SparseMatrix<RationalFunction>::getPointwiseProductRowSumVector(
2724template std::vector<storm::RationalFunction> SparseMatrix<double>::getPointwiseProductRowSumVector(
2726template std::vector<storm::RationalFunction> SparseMatrix<int>::getPointwiseProductRowSumVector(
2729
2730// Intervals
2731template std::vector<storm::Interval> SparseMatrix<double>::getPointwiseProductRowSumVector(
2732 storm::storage::SparseMatrix<storm::Interval> const& otherMatrix) const;
2734template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<Interval>::index_type, Interval> const& entry);
2735template class SparseMatrixBuilder<Interval>;
2736template class SparseMatrix<Interval>;
2737template std::ostream& operator<<(std::ostream& out, SparseMatrix<Interval> const& matrix);
2738template std::vector<storm::Interval> SparseMatrix<Interval>::getPointwiseProductRowSumVector(
2739 storm::storage::SparseMatrix<storm::Interval> const& otherMatrix) const;
2741
2743#endif
2744
2745} // namespace storage
2746} // namespace storm
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:18
void setMultiple(uint64_t bitIndex, uint64_t nrOfBits, bool newValue=true)
Sets multiple bits to the given value.
uint_fast64_t getNextSetIndex(uint_fast64_t startingIndex) const
Retrieves the index of the bit that is the next bit set to true in the bit vector.
bool empty() const
Retrieves whether no bits are set to true in this bit vector.
const_iterator begin() const
Returns an iterator to the indices of the set bits in the bit vector.
void set(uint_fast64_t index, bool value=true)
Sets the given truth value at the given index.
size_t size() const
Retrieves the number of bits this bit vector can store.
uint_fast64_t getNextUnsetIndex(uint_fast64_t startingIndex) const
Retrieves the index of the bit that is the next bit set to false in the bit vector.
uint_fast64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
std::vector< uint_fast64_t > getNumberOfSetBitsBeforeIndices() const
Retrieves a vector that holds at position i the number of bits set before index i.
bool get(uint_fast64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
MatrixEntry operator*(value_type factor) const
Multiplies the entry with the given factor and returns the result.
value_type const & getValue() const
Retrieves the value of the matrix entry.
std::pair< index_type, value_type > const & getColumnValuePair() const
Retrieves a pair of column and value that characterizes this entry.
void setColumn(index_type const &column)
Sets the column of the current entry.
MatrixEntry()=default
index_type const & getColumn() const
Retrieves the column of the matrix entry.
bool operator!=(MatrixEntry const &other) const
void setValue(value_type const &value)
Sets the value of the entry in the matrix.
ValueType value_type
bool operator==(MatrixEntry const &other) const
This class represents a number of consecutive rows of the matrix.
const_rows(const_iterator begin, index_type entryCount)
Constructs an object that represents the rows defined by the value of the first entry,...
const_iterator end() const
Retrieves an iterator that points past the last entry of the rows.
index_type getNumberOfEntries() const
Retrieves the number of entries in the rows.
const_iterator begin() const
Retrieves an iterator that points to the beginning of the rows.
This class represents a number of consecutive rows of the matrix.
iterator end()
Retrieves an iterator that points past the last entry of the rows.
iterator begin()
Retrieves an iterator that points to the beginning of the rows.
index_type getNumberOfEntries() const
Retrieves the number of entries in the rows.
rows(iterator begin, index_type entryCount)
Constructs an object that represents the rows defined by the value of the first entry,...
A class that can be used to build a sparse matrix by adding value by value.
index_type getCurrentRowGroupCount() const
Retrieves the current row group count.
index_type getLastRow() const
Retrieves the most recently used row.
void addNextValue(index_type row, index_type column, value_type const &value)
Sets the matrix entry at the given row and column to the given value.
void replaceColumns(std::vector< index_type > const &replacements, index_type offset)
Replaces all columns with id > offset according to replacements.
SparseMatrixBuilder(index_type rows=0, index_type columns=0, index_type entries=0, bool forceDimensions=true, bool hasCustomRowGrouping=false, index_type rowGroups=0)
Constructs a sparse matrix builder producing a matrix with the given number of rows,...
void newRowGroup(index_type startingRow)
Starts a new row group in the matrix.
index_type getLastColumn() const
Retrieves the most recently used row.
void addDiagonalEntry(index_type row, ValueType const &value)
Makes sure that a diagonal entry will be inserted at the given row.
SparseMatrix< value_type > build(index_type overriddenRowCount=0, index_type overriddenColumnCount=0, index_type overriddenRowGroupCount=0)
A class that holds a possibly non-square matrix in the compressed row storage format.
void divideRowsInPlace(std::vector< value_type > const &divisors)
Divides each row of the matrix, i.e., divides each element in row i with divisors[i].
void convertToEquationSystem()
Transforms the matrix into an equation system.
SparseMatrix()
Constructs an empty sparse matrix.
void swapRows(index_type const &row1, index_type const &row2)
Swaps the two rows.
bool operator==(SparseMatrix< value_type > const &other) const
Determines whether the current and the given matrix are semantically equal.
const_rows getRow(index_type row) const
Returns an object representing the given row.
index_type getSizeOfLargestRowGroup() const
Returns the size of the largest row group of the matrix.
SparseMatrix selectRowsFromRowGroups(std::vector< index_type > const &rowGroupToRowIndexMapping, bool insertDiagonalEntries=true) const
Selects exactly one row from each row group of this matrix and returns the resulting matrix.
void multiplyWithVectorForward(std::vector< value_type > const &vector, std::vector< value_type > &result, std::vector< value_type > const *summand=nullptr) const
index_type getEntryCount() const
Returns the number of entries in the matrix.
const_rows getRows(index_type startRow, index_type endRow) const
Returns an object representing the consecutive rows given by the parameters.
index_type getNonconstantEntryCount() const
Returns the number of non-constant entries.
void multiplyVectorWithMatrix(std::vector< value_type > const &vector, std::vector< value_type > &result) const
Multiplies the vector to the matrix from the left and writes the result to the given result vector.
void multiplyAndReduceBackward(storm::solver::OptimizationDirection const &dir, std::vector< uint64_t > const &rowGroupIndices, std::vector< ValueType > const &vector, std::vector< ValueType > const *b, std::vector< ValueType > &result, std::vector< uint64_t > *choices) const
index_type getNumRowsInRowGroups(storm::storage::BitVector const &groupConstraint) const
Returns the total number of rows that are in one of the specified row groups.
void makeRowsAbsorbing(storm::storage::BitVector const &rows, bool dropZeroEntries=false)
This function makes the given rows absorbing.
std::vector< ResultValueType > getPointwiseProductRowSumVector(storm::storage::SparseMatrix< OtherValueType > const &otherMatrix) const
Performs a pointwise matrix multiplication of the matrix with the given matrix and returns a vector c...
void multiplyWithVector(std::vector< value_type > const &vector, std::vector< value_type > &result, std::vector< value_type > const *summand=nullptr) const
Multiplies the matrix with the given vector and writes the result to the given result vector.
void updateNonzeroEntryCount() const
Recompute the nonzero entry count.
bool isProbabilistic() const
Checks for each row whether it sums to one.
void multiplyWithVectorBackward(std::vector< value_type > const &vector, std::vector< value_type > &result, std::vector< value_type > const *summand=nullptr) const
SparseMatrix getSubmatrix(bool useGroups, storm::storage::BitVector const &rowConstraint, storm::storage::BitVector const &columnConstraint, bool insertDiagonalEntries=false, storm::storage::BitVector const &makeZeroColumns=storm::storage::BitVector()) const
Creates a submatrix of the current matrix by dropping all rows and columns whose bits are not set to ...
void performWalkerChaeStep(std::vector< ValueType > const &x, std::vector< ValueType > const &columnSums, std::vector< ValueType > const &b, std::vector< ValueType > const &ax, std::vector< ValueType > &result) const
Performs one step of the Walker-Chae technique.
void updateDimensions() const
Recomputes the number of columns and the number of non-zero entries.
const_iterator begin(index_type row) const
Retrieves an iterator that points to the beginning of the given row.
void printAsMatlabMatrix(std::ostream &out) const
Prints the matrix in a dense format, as also used by e.g.
void performSuccessiveOverRelaxationStep(ValueType omega, std::vector< ValueType > &x, std::vector< ValueType > const &b) const
Performs one step of the successive over-relaxation technique.
std::vector< value_type > getConstrainedRowSumVector(storm::storage::BitVector const &rowConstraint, storm::storage::BitVector const &columnConstraint) const
Computes a vector whose i-th entry is the sum of the entries in the i-th selected row where only thos...
BitVector duplicateRowsInRowgroups() const
Finds duplicate rows in a rowgroup.
bool compareRows(index_type i1, index_type i2) const
Compares two rows.
const_rows getRowGroup(index_type rowGroup) const
Returns an object representing the given row group.
SparseMatrix permuteRows(std::vector< index_type > const &inversePermutation) const
Permute rows of the matrix according to the vector.
void setRowGroupIndices(std::vector< index_type > const &newRowGroupIndices)
Sets the row grouping to the given one.
void negateAllNonDiagonalEntries()
Negates (w.r.t.
const_iterator begin() const
Retrieves an iterator that points to the beginning of the first row of the matrix.
std::vector< index_type > swapRowGroupIndices(std::vector< index_type > &&newRowGrouping)
Swaps the grouping of rows of this matrix.
SparseMatrix restrictRows(storm::storage::BitVector const &rowsToKeep, bool allowEmptyRowGroups=false) const
Restrict rows in grouped rows matrix.
std::vector< ValueType > getRowSumVector() const
Sums the entries in all rows.
value_type multiplyRowWithVector(index_type row, std::vector< value_type > const &vector) const
Multiplies a single row of the matrix with the given vector and returns the result.
SparseMatrix< ValueType > transposeSelectedRowsFromRowGroups(std::vector< uint64_t > const &rowGroupChoices, bool keepZeros=false) const
Transposes the matrix w.r.t.
void multiplyAndReduceForward(storm::solver::OptimizationDirection const &dir, std::vector< uint64_t > const &rowGroupIndices, std::vector< ValueType > const &vector, std::vector< ValueType > const *b, std::vector< ValueType > &result, std::vector< uint64_t > *choices) const
value_type getRowSum(index_type row) const
Computes the sum of the entries in a given row.
const_iterator end(index_type row) const
Retrieves an iterator that points past the end of the given row.
SparseMatrix permuteRowGroupsAndColumns(std::vector< index_type > const &inverseRowGroupPermutation, std::vector< index_type > const &columnPermutation) const
Permutes row groups and columns of the matrix according to the given permutations.
void multiplyAndReduce(storm::solver::OptimizationDirection const &dir, std::vector< uint64_t > const &rowGroupIndices, std::vector< ValueType > const &vector, std::vector< ValueType > const *summand, std::vector< ValueType > &result, std::vector< uint64_t > *choices) const
Multiplies the matrix with the given vector, reduces it according to the given direction and and writ...
index_type getRowGroupCount() const
Returns the number of row groups in the matrix.
void dropZeroEntries()
Removes all zero entries from this.
bool isSubmatrixOf(SparseMatrix< OtherValueType > const &matrix) const
Checks if the current matrix is a submatrix of the given matrix, where a matrix A is called a submatr...
ResultValueType getPointwiseProductRowSum(storm::storage::SparseMatrix< OtherValueType > const &otherMatrix, index_type const &row) const
Performs a pointwise multiplication of the entries in the given row of this matrix and the entries of...
SparseMatrix< value_type > & operator=(SparseMatrix< value_type > const &other)
Assigns the contents of the given matrix to the current one by deep-copying its contents.
void makeRowGroupsAbsorbing(storm::storage::BitVector const &rowGroupConstraint, bool dropZeroEntries=false)
This function makes the groups of rows given by the bit vector absorbing.
std::string getDimensionsAsString() const
Returns a string describing the dimensions of the matrix.
index_type getColumnCount() const
Returns the number of columns of the matrix.
std::pair< storm::storage::SparseMatrix< value_type >, std::vector< value_type > > getJacobiDecomposition() const
Calculates the Jacobi decomposition of this sparse matrix.
void makeRowDirac(index_type row, index_type column, bool dropZeroEntries=false)
This function makes the given row Dirac.
std::vector< MatrixEntry< index_type, value_type > >::const_iterator const_iterator
value_type getConstrainedRowSum(index_type row, storm::storage::BitVector const &columns) const
Sums the entries in the given row and columns.
void deleteDiagonalEntries(bool dropZeroEntries=false)
Sets all diagonal elements to zero.
bool hasTrivialRowGrouping() const
Retrieves whether the matrix has a trivial row grouping.
void invertDiagonal()
Inverts all entries on the diagonal, i.e.
storm::storage::BitVector getRowGroupFilter(storm::storage::BitVector const &rowConstraint, bool setIfForAllRowsInGroup) const
Returns the indices of all row groups selected by the row constraints.
void makeRowGroupingTrivial()
Makes the row grouping of this matrix trivial.
SparseMatrix selectRowsFromRowIndexSequence(std::vector< index_type > const &rowIndexSequence, bool insertDiagonalEntries=true) const
Selects the rows that are given by the sequence of row indices, allowing to select rows arbitrarily o...
std::size_t hash() const
Calculates a hash value over all values contained in the matrix.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
std::vector< MatrixEntry< index_type, value_type > >::iterator iterator
index_type getRowGroupSize(index_type group) const
Returns the size of the given row group.
std::vector< value_type > getConstrainedRowGroupSumVector(storm::storage::BitVector const &rowGroupConstraint, storm::storage::BitVector const &columnConstraint) const
Computes a vector whose entries represent the sums of selected columns for all rows in selected row g...
storm::storage::SparseMatrix< value_type > transpose(bool joinGroups=false, bool keepZeros=false) const
Transposes the matrix.
bool hasOnlyPositiveEntries() const
Checks whether each present entry is strictly positive (omitted entries are not considered).
index_type getRowCount() const
Returns the number of rows of the matrix.
SparseMatrixIndexType index_type
index_type getNonzeroEntryCount() const
Returns the cached number of nonzero entries in the matrix.
const_iterator end() const
Retrieves an iterator that points past the end of the last row of the matrix.
index_type getNonconstantRowGroupCount() const
Returns the number of rowGroups that contain a non-constant value.
void scaleRowsInPlace(std::vector< value_type > const &factors)
Scales each row of the matrix, i.e., multiplies each element in row i with factors[i].
index_type getRowGroupEntryCount(index_type const group) const
Returns the number of entries in the given row group of the matrix.
storm::storage::BitVector getRowFilter(storm::storage::BitVector const &groupConstraint) const
Returns a bitvector representing the set of rows, with all indices set that correspond to one of the ...
SparseMatrix filterEntries(storm::storage::BitVector const &rowFilter) const
Returns a copy of this matrix that only considers entries in the selected rows.
bool isOne(ValueType const &value) const
bool isConstant(ValueType const &value) const
bool isLess(ValueType const &value1, ValueType const &value2) const
#define STORM_LOG_WARN(message)
Definition logging.h:30
#define STORM_LOG_TRACE(message)
Definition logging.h:17
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
SFTBDDChecker::ValueType ValueType
void print(std::vector< typename SparseMatrix< ValueType >::index_type > const &rowGroupIndices, std::vector< MatrixEntry< typename SparseMatrix< ValueType >::index_type, typename SparseMatrix< ValueType >::value_type > > const &columnsAndValues, std::vector< typename SparseMatrix< ValueType >::index_type > const &rowIndications)
std::ostream & operator<<(std::ostream &out, ParameterRegion< ParametricType > const &region)
bool isValidPermutation(std::vector< index_type > const &permutation)
Returns true if the given vector is a permutation of the numbers 0, 1, ..., n-1 for n = permutation....
std::vector< T > buildVectorForRange(T min, T max)
Constructs a vector [min, min+1, ...., max-1].
Definition vector.h:134
bool isOne(ValueType const &a)
Definition constants.cpp:36
bool isConstant(ValueType const &)
Definition constants.cpp:66
bool isZero(ValueType const &a)
Definition constants.cpp:41
typename detail::ElementLess< ValueType >::type ElementLess
Definition constants.h:69
typename detail::ElementGreater< ValueType >::type ElementGreater
Definition constants.h:72
LabParser.cpp.
Definition cli.cpp:18
solver::OptimizationDirection OptimizationDirection