Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SparseMatrixTest.cpp
Go to the documentation of this file.
1#include <map>
2#include <random>
3#include <utility>
4#include <vector>
5
6#include "storm-config.h"
7#include "test/storm_gtest.h"
8
15
16TEST(SparseMatrixBuilder, CreationEmpty) {
19 ASSERT_NO_THROW(matrix = matrixBuilder.build());
20
21 ASSERT_EQ(0ul, matrix.getRowCount());
22 ASSERT_EQ(0ul, matrix.getColumnCount());
23 ASSERT_EQ(0ul, matrix.getEntryCount());
24}
25
26TEST(SparseMatrixBuilder, CreationWithDimensions) {
28 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
29 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
30 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
31 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
32 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 3, 0.2));
33
35 ASSERT_NO_THROW(matrix = matrixBuilder.build());
36
37 ASSERT_EQ(3ul, matrix.getRowCount());
38 ASSERT_EQ(4ul, matrix.getColumnCount());
39 ASSERT_EQ(5ul, matrix.getEntryCount());
40}
41
42TEST(SparseMatrixBuilder, CreationWithoutNumberOfEntries) {
44 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
45 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
46 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
47 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
48 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 3, 0.2));
49
51 ASSERT_NO_THROW(matrix = matrixBuilder.build());
52
53 ASSERT_EQ(3ul, matrix.getRowCount());
54 ASSERT_EQ(4ul, matrix.getColumnCount());
55 ASSERT_EQ(5ul, matrix.getEntryCount());
56}
57
58TEST(SparseMatrixBuilder, CreationWithNumberOfRows) {
60 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
61 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
62 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
63 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
64 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 3, 0.2));
65
67 ASSERT_NO_THROW(matrix = matrixBuilder.build());
68
69 ASSERT_EQ(3ul, matrix.getRowCount());
70 ASSERT_EQ(4ul, matrix.getColumnCount());
71 ASSERT_EQ(5ul, matrix.getEntryCount());
72}
73
74TEST(SparseMatrixBuilder, CreationWithoutDimensions) {
76 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
77 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 3, 1.2));
78 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
79 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
80 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 2, 0.2));
81
83 ASSERT_NO_THROW(matrix = matrixBuilder.build());
84
85 ASSERT_EQ(2ul, matrix.getRowCount());
86 ASSERT_EQ(4ul, matrix.getColumnCount());
87 ASSERT_EQ(5ul, matrix.getEntryCount());
88}
89
90TEST(SparseMatrixBuilder, AddNextValue) {
91 storm::storage::SparseMatrixBuilder<double> matrixBuilder1(3, 4, 5);
92 ASSERT_NO_THROW(matrixBuilder1.addNextValue(0, 1, 1.0));
93 ASSERT_NO_THROW(matrixBuilder1.addNextValue(0, 2, 1.2));
94 STORM_SILENT_ASSERT_THROW(matrixBuilder1.addNextValue(0, 4, 0.5), storm::exceptions::OutOfRangeException);
95 STORM_SILENT_ASSERT_THROW(matrixBuilder1.addNextValue(3, 1, 0.5), storm::exceptions::OutOfRangeException);
96
98 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 1, 1.0));
99 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 2, 1.2));
100 STORM_SILENT_ASSERT_THROW(matrixBuilder2.addNextValue(0, 4, 0.5), storm::exceptions::OutOfRangeException);
101 STORM_SILENT_ASSERT_THROW(matrixBuilder2.addNextValue(3, 1, 0.5), storm::exceptions::OutOfRangeException);
102
104 ASSERT_NO_THROW(matrixBuilder3.addNextValue(0, 1, 1.0));
105 ASSERT_NO_THROW(matrixBuilder3.addNextValue(1, 2, 1.2));
106 ASSERT_NO_THROW(matrixBuilder3.addNextValue(2, 4, 0.5));
107 STORM_SILENT_ASSERT_THROW(matrixBuilder3.addNextValue(3, 1, 0.2), storm::exceptions::OutOfRangeException);
108
110 ASSERT_NO_THROW(matrixBuilder4.addNextValue(0, 1, 1.0));
111 ASSERT_NO_THROW(matrixBuilder4.addNextValue(1, 2, 1.2));
112 ASSERT_NO_THROW(matrixBuilder4.addNextValue(2, 4, 0.5));
113 ASSERT_NO_THROW(matrixBuilder4.addNextValue(3, 1, 0.2));
114}
115
116namespace {
117using RowEntries = std::vector<std::pair<uint64_t, double>>;
119
120RowEntries getRowEntries(storm::storage::SparseMatrix<double> const& matrix, uint64_t row) {
121 RowEntries result;
122 for (auto const& entry : matrix.getRow(row)) {
123 result.emplace_back(entry.getColumn(), entry.getValue());
124 }
125 return result;
126}
127} // namespace
128
129TEST(SparseMatrixBuilder, AccumulationModeSetterGetter) {
131 EXPECT_EQ(AccumulationMode::Sum, builder.getAccumulationMode());
132 builder.setAccumulationMode(AccumulationMode::ExpectSame);
133 EXPECT_EQ(AccumulationMode::ExpectSame, builder.getAccumulationMode());
134 builder.setAccumulationMode(AccumulationMode::ExpectNone);
135 EXPECT_EQ(AccumulationMode::ExpectNone, builder.getAccumulationMode());
136 builder.setAccumulationMode(AccumulationMode::Sum);
137 EXPECT_EQ(AccumulationMode::Sum, builder.getAccumulationMode());
138}
139
140TEST(SparseMatrixBuilder, AccumulationSum) {
142 // Duplicates that are added consecutively
143 ASSERT_NO_THROW(builder.addNextValue(0, 1, 0.25));
144 ASSERT_NO_THROW(builder.addNextValue(0, 1, 0.25));
145 ASSERT_NO_THROW(builder.addNextValue(0, 2, 0.5));
146 // Duplicates that are added out of order
147 ASSERT_NO_THROW(builder.addNextValue(1, 2, 0.25));
148 ASSERT_NO_THROW(builder.addNextValue(1, 0, 0.5));
149 ASSERT_NO_THROW(builder.addNextValue(1, 2, 0.125));
150 ASSERT_NO_THROW(builder.addNextValue(1, 0, 0.25));
151
153 ASSERT_NO_THROW(matrix = builder.build());
154 ASSERT_EQ(2ul, matrix.getRowCount());
155 ASSERT_EQ(3ul, matrix.getColumnCount());
156 ASSERT_EQ(4ul, matrix.getEntryCount());
157 EXPECT_EQ((RowEntries{{1, 0.5}, {2, 0.5}}), getRowEntries(matrix, 0));
158 EXPECT_EQ((RowEntries{{0, 0.75}, {2, 0.375}}), getRowEntries(matrix, 1));
159}
160
161TEST(SparseMatrixBuilder, AccumulationExpectSame) {
163 builder.setAccumulationMode(AccumulationMode::ExpectSame);
164 ASSERT_NO_THROW(builder.addNextValue(0, 1, 0.25));
165 // Same entry again (consecutive)
166 ASSERT_NO_THROW(builder.addNextValue(0, 1, 0.25));
167 ASSERT_NO_THROW(builder.addNextValue(0, 2, 0.5));
168 // Same entry again (out of order)
169 ASSERT_NO_THROW(builder.addNextValue(0, 1, 0.25));
170 ASSERT_NO_THROW(builder.addNextValue(0, 2, 0.5));
171 // Different values for the same entry
172 STORM_SILENT_ASSERT_THROW(builder.addNextValue(0, 2, 0.25), storm::exceptions::InvalidArgumentException);
173 STORM_SILENT_ASSERT_THROW(builder.addNextValue(0, 1, 0.5), storm::exceptions::InvalidArgumentException);
174 ASSERT_NO_THROW(builder.addNextValue(1, 0, 1.0));
175
177 ASSERT_NO_THROW(matrix = builder.build());
178 ASSERT_EQ(2ul, matrix.getRowCount());
179 ASSERT_EQ(3ul, matrix.getColumnCount());
180 ASSERT_EQ(3ul, matrix.getEntryCount());
181 // The values must not have been summed up
182 EXPECT_EQ((RowEntries{{1, 0.25}, {2, 0.5}}), getRowEntries(matrix, 0));
183 EXPECT_EQ((RowEntries{{0, 1.0}}), getRowEntries(matrix, 1));
184}
185
186TEST(SparseMatrixBuilder, AccumulationExpectNone) {
188 builder.setAccumulationMode(AccumulationMode::ExpectNone);
189 // Out of order insertion is fine as long as there are no duplicates
190 ASSERT_NO_THROW(builder.addNextValue(0, 2, 0.5));
191 ASSERT_NO_THROW(builder.addNextValue(0, 0, 0.25));
192 ASSERT_NO_THROW(builder.addNextValue(0, 1, 0.25));
193 // Duplicates are not fine, even if the values are the same
194 STORM_SILENT_ASSERT_THROW(builder.addNextValue(0, 1, 0.25), storm::exceptions::InvalidArgumentException);
195 STORM_SILENT_ASSERT_THROW(builder.addNextValue(0, 2, 0.5), storm::exceptions::InvalidArgumentException);
196 STORM_SILENT_ASSERT_THROW(builder.addNextValue(0, 0, 0.25), storm::exceptions::InvalidArgumentException);
197 ASSERT_NO_THROW(builder.addNextValue(1, 1, 1.0));
198 STORM_SILENT_ASSERT_THROW(builder.addNextValue(1, 1, 1.0), storm::exceptions::InvalidArgumentException);
199
201 ASSERT_NO_THROW(matrix = builder.build());
202 ASSERT_EQ(4ul, matrix.getEntryCount());
203 EXPECT_EQ((RowEntries{{0, 0.25}, {1, 0.25}, {2, 0.5}}), getRowEntries(matrix, 0));
204 EXPECT_EQ((RowEntries{{1, 1.0}}), getRowEntries(matrix, 1));
205}
206
207TEST(SparseMatrixBuilder, AccumulationDiagonalEntries) {
208 {
209 // Sum
211 ASSERT_NO_THROW(builder.addDiagonalEntry(0, 0.25));
212 ASSERT_NO_THROW(builder.addDiagonalEntry(0, 0.25));
213 ASSERT_NO_THROW(builder.addNextValue(0, 0, 0.125));
214 ASSERT_NO_THROW(builder.addNextValue(0, 1, 0.5));
215 auto matrix = builder.build();
216 EXPECT_EQ((RowEntries{{0, 0.625}, {1, 0.5}}), getRowEntries(matrix, 0));
217 }
218 {
219 // ExpectSame
221 builder.setAccumulationMode(AccumulationMode::ExpectSame);
222 ASSERT_NO_THROW(builder.addDiagonalEntry(0, 0.5));
223 ASSERT_NO_THROW(builder.addNextValue(0, 0, 0.5));
224 ASSERT_NO_THROW(builder.addNextValue(0, 1, 0.5));
225 ASSERT_NO_THROW(builder.addDiagonalEntry(1, 0.5));
226 ASSERT_NO_THROW(builder.addDiagonalEntry(1, 0.5));
227 auto matrix = builder.build();
228 EXPECT_EQ((RowEntries{{0, 0.5}, {1, 0.5}}), getRowEntries(matrix, 0));
229 EXPECT_EQ((RowEntries{{1, 0.5}}), getRowEntries(matrix, 1));
230
232 failingBuilder1.setAccumulationMode(AccumulationMode::ExpectSame);
233 ASSERT_NO_THROW(failingBuilder1.addDiagonalEntry(0, 0.5));
234 STORM_SILENT_ASSERT_THROW(failingBuilder1.addNextValue(0, 0, 0.25), storm::exceptions::InvalidArgumentException);
235
237 failingBuilder2.setAccumulationMode(AccumulationMode::ExpectSame);
238 ASSERT_NO_THROW(failingBuilder2.addDiagonalEntry(0, 0.5));
239 STORM_SILENT_ASSERT_THROW(failingBuilder2.addDiagonalEntry(0, 0.25), storm::exceptions::InvalidArgumentException);
240 }
241 {
242 // ExpectNone
244 builder.setAccumulationMode(AccumulationMode::ExpectNone);
245 ASSERT_NO_THROW(builder.addDiagonalEntry(0, 0.5));
246 ASSERT_NO_THROW(builder.addNextValue(0, 1, 0.5));
247 auto matrix = builder.build();
248 EXPECT_EQ((RowEntries{{0, 0.5}, {1, 0.5}}), getRowEntries(matrix, 0));
249
251 failingBuilder1.setAccumulationMode(AccumulationMode::ExpectNone);
252 ASSERT_NO_THROW(failingBuilder1.addDiagonalEntry(0, 0.5));
253 STORM_SILENT_ASSERT_THROW(failingBuilder1.addNextValue(0, 0, 0.5), storm::exceptions::InvalidArgumentException);
254
256 failingBuilder2.setAccumulationMode(AccumulationMode::ExpectNone);
257 ASSERT_NO_THROW(failingBuilder2.addDiagonalEntry(0, 0.5));
258 STORM_SILENT_ASSERT_THROW(failingBuilder2.addDiagonalEntry(0, 0.5), storm::exceptions::InvalidArgumentException);
259 }
260}
261
262TEST(SparseMatrixBuilder, DuplicateEntriesWithoutForcedEntryCount) {
263 // The announced number of entries is only a hint if we do not force the dimensions.
264 storm::storage::SparseMatrixBuilder<double> builder(2, 2, 4, false);
265 ASSERT_NO_THROW(builder.addNextValue(0, 0, 0.25));
266 ASSERT_NO_THROW(builder.addNextValue(0, 0, 0.25));
267 ASSERT_NO_THROW(builder.addNextValue(1, 1, 0.5));
268 ASSERT_NO_THROW(builder.addNextValue(1, 1, 0.5));
270 ASSERT_NO_THROW(matrix = builder.build(2, 2));
271 EXPECT_EQ(2ul, matrix.getRowCount());
272 EXPECT_EQ(2ul, matrix.getColumnCount());
273 EXPECT_EQ(2ul, matrix.getEntryCount());
274
275 storm::storage::SparseMatrixBuilder<double> forcingBuilder(2, 2, 4, true);
276 ASSERT_NO_THROW(forcingBuilder.addNextValue(0, 0, 0.25));
277 ASSERT_NO_THROW(forcingBuilder.addNextValue(0, 0, 0.25));
278 ASSERT_NO_THROW(forcingBuilder.addNextValue(1, 1, 0.5));
279 ASSERT_NO_THROW(forcingBuilder.addNextValue(1, 1, 0.5));
280 STORM_SILENT_ASSERT_THROW(forcingBuilder.build(), storm::exceptions::InvalidStateException);
281}
282
283TEST(SparseMatrixBuilder, OutOfOrderInsertion) {
284 {
285 // Rows are filled in descending or zig-zag order
288 for (uint64_t column = 10; column-- > 0;) {
289 ASSERT_NO_THROW(builder.addNextValue(0, column, column + 1.0));
290 ASSERT_NO_THROW(orderedBuilder.addNextValue(0, 9 - column, 10.0 - column));
291 }
292 for (uint64_t column : {5, 3, 7, 1, 9, 0, 4}) {
293 ASSERT_NO_THROW(builder.addNextValue(1, column, column + 1.0));
294 }
295 for (uint64_t column : {0, 1, 3, 4, 5, 7, 9}) {
296 ASSERT_NO_THROW(orderedBuilder.addNextValue(1, column, column + 1.0));
297 }
298 // Row 2 is empty
299 EXPECT_EQ(orderedBuilder.build(3, 10), builder.build(3, 10));
300 }
301 {
302 // The last column of the builder is the highest column of the current row
304 builder.addNextValue(0, 5, 1.0);
305 EXPECT_EQ(5ul, builder.getLastColumn());
306 builder.addNextValue(0, 3, 1.0);
307 EXPECT_EQ(5ul, builder.getLastColumn());
308 builder.addNextValue(0, 7, 1.0);
309 EXPECT_EQ(7ul, builder.getLastColumn());
310 builder.addNextValue(1, 2, 1.0);
311 EXPECT_EQ(2ul, builder.getLastColumn());
312 }
313 {
314 // With row groups and empty rows
315 storm::storage::SparseMatrixBuilder<double> builder(0, 0, 0, false, true);
316 builder.newRowGroup(0);
317 ASSERT_NO_THROW(builder.addNextValue(0, 3, 4.0));
318 ASSERT_NO_THROW(builder.addNextValue(0, 1, 2.0));
319 ASSERT_NO_THROW(builder.addNextValue(0, 2, 3.0));
320 builder.newRowGroup(2);
321 ASSERT_NO_THROW(builder.addNextValue(2, 2, 3.0));
322 ASSERT_NO_THROW(builder.addNextValue(2, 0, 1.0));
323 builder.newRowGroup(4);
324 ASSERT_NO_THROW(builder.addNextValue(4, 1, 2.0));
325 auto matrix = builder.build();
326
327 ASSERT_EQ(5ul, matrix.getRowCount());
328 ASSERT_EQ(4ul, matrix.getColumnCount());
329 ASSERT_EQ(3ul, matrix.getRowGroupCount());
330 EXPECT_EQ((RowEntries{{1, 2.0}, {2, 3.0}, {3, 4.0}}), getRowEntries(matrix, 0));
331 EXPECT_EQ((RowEntries{}), getRowEntries(matrix, 1));
332 EXPECT_EQ((RowEntries{{0, 1.0}, {2, 3.0}}), getRowEntries(matrix, 2));
333 EXPECT_EQ((RowEntries{}), getRowEntries(matrix, 3));
334 EXPECT_EQ((RowEntries{{1, 2.0}}), getRowEntries(matrix, 4));
335 }
336}
337
338TEST(SparseMatrixBuilder, OutOfOrderInsertionRandomized) {
339 std::mt19937 gen(42);
340 for (uint64_t iteration = 0; iteration < 50; ++iteration) {
341 uint64_t const numRows = 1 + gen() % 8;
342 uint64_t const numColumns = 1 + gen() % 50;
343 std::map<std::pair<uint64_t, uint64_t>, double> expectedEntries;
345 for (uint64_t row = 0; row < numRows; ++row) {
346 uint64_t const numInsertions = gen() % 120;
347 for (uint64_t i = 0; i < numInsertions; ++i) {
348 uint64_t const column = gen() % numColumns;
349 double const value = 1.0 + gen() % 8; // small integers, so sums are exact
350 expectedEntries[{row, column}] += value;
351 ASSERT_NO_THROW(builder.addNextValue(row, column, value));
352 }
353 }
355 for (auto const& [position, value] : expectedEntries) {
356 orderedBuilder.addNextValue(position.first, position.second, value);
357 }
358 auto const expectedMatrix = orderedBuilder.build(numRows, numColumns);
359 auto const matrix = builder.build(numRows, numColumns);
360 EXPECT_EQ(expectedMatrix, matrix) << "Matrices differ in iteration " << iteration;
361 EXPECT_EQ(expectedEntries.size(), matrix.getEntryCount()) << "Unexpected number of entries in iteration " << iteration;
362 }
363}
364
365TEST(SparseMatrixBuilder, OverriddenDimensionsTooSmall) {
366 auto createBuilder = []() {
367 // A matrix with 3 rows, 4 columns, and 2 row groups
368 storm::storage::SparseMatrixBuilder<double> builder(0, 0, 0, false, true);
369 builder.newRowGroup(0);
370 builder.addNextValue(0, 3, 1.0);
371 builder.newRowGroup(1);
372 builder.addNextValue(2, 0, 1.0);
373 return builder;
374 };
375 // rows
376 STORM_SILENT_ASSERT_THROW(createBuilder().build(2), storm::exceptions::InvalidStateException);
377 // columns
378 STORM_SILENT_ASSERT_THROW(createBuilder().build(0, 3), storm::exceptions::InvalidStateException);
379 // row groups
380 STORM_SILENT_ASSERT_THROW(createBuilder().build(0, 0, 1), storm::exceptions::InvalidStateException);
381
382 // Exact dimensions are fine
383 {
384 auto matrix = createBuilder().build(3, 4, 2);
385 EXPECT_EQ(3ul, matrix.getRowCount());
386 EXPECT_EQ(4ul, matrix.getColumnCount());
387 EXPECT_EQ(2ul, matrix.getRowGroupCount());
388 }
389 // Larger dimensions pad the matrix
390 {
391 auto matrix = createBuilder().build(5, 6, 4);
392 EXPECT_EQ(5ul, matrix.getRowCount());
393 EXPECT_EQ(6ul, matrix.getColumnCount());
394 EXPECT_EQ(4ul, matrix.getRowGroupCount());
395 EXPECT_EQ(2ul, matrix.getEntryCount());
396 }
397 // Zero means that the dimension is not overridden
398 {
399 auto matrix = createBuilder().build(0, 0, 0);
400 EXPECT_EQ(3ul, matrix.getRowCount());
401 EXPECT_EQ(4ul, matrix.getColumnCount());
402 EXPECT_EQ(2ul, matrix.getRowGroupCount());
403 }
404 // Also applies if the dimensions were announced (but not forced) upon construction
405 {
406 storm::storage::SparseMatrixBuilder<double> builder(2, 2, 2, false);
407 builder.addNextValue(0, 0, 1.0);
408 builder.addNextValue(1, 1, 1.0);
409 builder.addNextValue(2, 2, 1.0);
410 STORM_SILENT_ASSERT_THROW(builder.build(2, 2), storm::exceptions::InvalidStateException);
411 }
412}
413
414TEST(SparseMatrixBuilder, ContinueFromEmptyMatrix) {
415 // A matrix without any rows can be extended via a new builder
417 storm::storage::SparseMatrix<double> emptyMatrix = emptyBuilder.build();
418 storm::storage::SparseMatrixBuilder<double> builder(std::move(emptyMatrix));
419 ASSERT_NO_THROW(builder.addNextValue(0, 2, 0.5));
420 ASSERT_NO_THROW(builder.addNextValue(0, 1, 0.5));
421 ASSERT_NO_THROW(builder.addNextValue(1, 0, 1.0));
422 auto result = builder.build();
423 ASSERT_EQ(2ul, result.getRowCount());
424 ASSERT_EQ(3ul, result.getColumnCount());
425 EXPECT_EQ((RowEntries{{1, 0.5}, {2, 0.5}}), getRowEntries(result, 0));
426 EXPECT_EQ((RowEntries{{0, 1.0}}), getRowEntries(result, 1));
427}
428
429TEST(SparseMatrixBuilder, TrailingEmptyRowGroup) {
430 // A row group that is started but never filled still counts as one (empty) row.
431 auto createBuilder = []() {
432 storm::storage::SparseMatrixBuilder<double> builder(0, 0, 0, false, true);
433 builder.newRowGroup(0);
434 builder.addNextValue(0, 0, 1.0);
435 builder.newRowGroup(1);
436 return builder;
437 };
438 auto matrix = createBuilder().build();
439 EXPECT_EQ(2ul, matrix.getRowCount());
440 EXPECT_EQ(2ul, matrix.getRowGroupCount());
441 EXPECT_EQ(1ul, matrix.getEntryCount());
442 // Hence, the matrix does not fit into one row
443 STORM_SILENT_ASSERT_THROW(createBuilder().build(1), storm::exceptions::InvalidStateException);
444 EXPECT_EQ(2ul, createBuilder().build(2).getRowCount());
445}
446
447TEST(SparseMatrix, Build) {
448 storm::storage::SparseMatrixBuilder<double> matrixBuilder1(3, 4, 5);
449 ASSERT_NO_THROW(matrixBuilder1.addNextValue(0, 1, 1.0));
450 ASSERT_NO_THROW(matrixBuilder1.addNextValue(0, 2, 1.2));
451 ASSERT_NO_THROW(matrixBuilder1.addNextValue(1, 0, 0.5));
452 ASSERT_NO_THROW(matrixBuilder1.addNextValue(1, 1, 0.7));
453 ASSERT_NO_THROW(matrixBuilder1.addNextValue(1, 3, 0.2));
454 ASSERT_NO_THROW(matrixBuilder1.build());
455
456 storm::storage::SparseMatrixBuilder<double> matrixBuilder2(3, 4, 5);
457 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 1, 1.0));
458 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 2, 1.2));
459 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 0, 0.5));
460 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 1, 0.7));
461 STORM_SILENT_ASSERT_THROW(matrixBuilder2.build(), storm::exceptions::InvalidStateException);
462
464 ASSERT_NO_THROW(matrixBuilder3.addNextValue(0, 1, 1.0));
465 ASSERT_NO_THROW(matrixBuilder3.addNextValue(0, 2, 1.2));
466 ASSERT_NO_THROW(matrixBuilder3.addNextValue(1, 0, 0.5));
467 ASSERT_NO_THROW(matrixBuilder3.addNextValue(1, 1, 0.7));
468 ASSERT_NO_THROW(matrixBuilder3.addNextValue(1, 3, 0.2));
470 ASSERT_NO_THROW(matrix3 = matrixBuilder3.build());
471 ASSERT_EQ(2ul, matrix3.getRowCount());
472 ASSERT_EQ(4ul, matrix3.getColumnCount());
473 ASSERT_EQ(5ul, matrix3.getEntryCount());
474
476 ASSERT_NO_THROW(matrixBuilder4.addNextValue(0, 1, 1.0));
477 ASSERT_NO_THROW(matrixBuilder4.addNextValue(0, 2, 1.2));
478 ASSERT_NO_THROW(matrixBuilder4.addNextValue(1, 0, 0.5));
479 ASSERT_NO_THROW(matrixBuilder4.addNextValue(1, 1, 0.7));
480 ASSERT_NO_THROW(matrixBuilder4.addNextValue(1, 3, 0.2));
482 ASSERT_NO_THROW(matrix4 = matrixBuilder4.build(4));
483 ASSERT_EQ(4ul, matrix4.getRowCount());
484 ASSERT_EQ(4ul, matrix4.getColumnCount());
485 ASSERT_EQ(5ul, matrix4.getEntryCount());
486
488 ASSERT_NO_THROW(matrixBuilder5.addNextValue(0, 1, 1.0));
489 ASSERT_NO_THROW(matrixBuilder5.addNextValue(0, 2, 1.2));
490 ASSERT_NO_THROW(matrixBuilder5.addNextValue(1, 0, 0.5));
491 ASSERT_NO_THROW(matrixBuilder5.addNextValue(1, 1, 0.7));
492 ASSERT_NO_THROW(matrixBuilder5.addNextValue(1, 3, 0.2));
494 ASSERT_NO_THROW(matrix5 = matrixBuilder5.build(0, 6));
495 ASSERT_EQ(2ul, matrix5.getRowCount());
496 ASSERT_EQ(6ul, matrix5.getColumnCount());
497 ASSERT_EQ(5ul, matrix5.getEntryCount());
498}
499
500TEST(SparseMatrix, DiagonalEntries) {
501 {
502 // No row groupings
505 for (uint64_t i = 0; i < 4; ++i) {
506 ASSERT_NO_THROW(builder.addDiagonalEntry(i, i));
507 ASSERT_NO_THROW(builder.addNextValue(i, 2, 100.0 + i));
508 if (i < 2) {
509 ASSERT_NO_THROW(builderCmp.addNextValue(i, i, i));
510 ASSERT_NO_THROW(builderCmp.addNextValue(i, 2, 100.0 + i));
511 } else {
512 ASSERT_NO_THROW(builderCmp.addNextValue(i, 2, 100.0 + i));
513 ASSERT_NO_THROW(builderCmp.addNextValue(i, i, i));
514 }
515 }
516 auto matrix = builder.build();
517 auto matrixCmp = builderCmp.build();
518 EXPECT_EQ(matrix, matrixCmp);
519 }
520 {
521 // With row groupings (each row group has 3 rows)
522 storm::storage::SparseMatrixBuilder<double> builder(12, 4, 21, true, true, 4);
523 storm::storage::SparseMatrixBuilder<double> builderCmp(12, 4, 21, true, true, 4);
524 for (uint64_t i = 0; i < 4; ++i) {
525 uint64_t row = 3 * i;
526 builder.newRowGroup(row);
527 builderCmp.newRowGroup(row);
528 for (; row < 3 * (i + 1); ++row) {
529 ASSERT_NO_THROW(builder.addDiagonalEntry(row, row));
530 ASSERT_NO_THROW(builder.addNextValue(row, 2, 100 + row));
531 if (i < 2) {
532 ASSERT_NO_THROW(builderCmp.addNextValue(row, i, row));
533 ASSERT_NO_THROW(builderCmp.addNextValue(row, 2, 100.0 + row));
534 } else {
535 ASSERT_NO_THROW(builderCmp.addNextValue(row, 2, 100.0 + row));
536 ASSERT_NO_THROW(builderCmp.addNextValue(row, i, row));
537 }
538 }
539 }
540 auto matrix = builder.build();
541 auto matrixCmp = builderCmp.build();
542 EXPECT_EQ(matrix, matrixCmp);
543 }
544 {
545 // With row groupings (every second row is empty)
546 storm::storage::SparseMatrixBuilder<double> builder(12, 4, 10, true, true, 4);
547 storm::storage::SparseMatrixBuilder<double> builderCmp(12, 4, 10, true, true, 4);
548 for (uint64_t i = 0; i < 4; ++i) {
549 uint64_t row = 3 * i;
550 builder.newRowGroup(row);
551 builderCmp.newRowGroup(row);
552 for (; row < 3 * (i + 1); ++row) {
553 if (row % 2 == 1) {
554 continue;
555 }
556 ASSERT_NO_THROW(builder.addDiagonalEntry(row, row));
557 ASSERT_NO_THROW(builder.addNextValue(row, 2, 100 + row));
558 if (i < 2) {
559 ASSERT_NO_THROW(builderCmp.addNextValue(row, i, row));
560 ASSERT_NO_THROW(builderCmp.addNextValue(row, 2, 100.0 + row));
561 } else {
562 ASSERT_NO_THROW(builderCmp.addNextValue(row, i, row));
563 ASSERT_NO_THROW(builderCmp.addNextValue(row, 2, 100.0 + row));
564 }
565 }
566 }
567 auto matrix = builder.build();
568 auto matrixCmp = builderCmp.build();
569 EXPECT_EQ(matrix, matrixCmp);
570 }
571}
572
573TEST(SparseMatrix, CreationWithMovingContents) {
574 std::vector<storm::storage::MatrixEntry<uint_fast64_t, double>> columnsAndValues;
575 columnsAndValues.emplace_back(1, 1.0);
576 columnsAndValues.emplace_back(2, 1.2);
577 columnsAndValues.emplace_back(0, 0.5);
578 columnsAndValues.emplace_back(1, 0.7);
579 columnsAndValues.emplace_back(3, 0.2);
580
581 ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, columnsAndValues, boost::optional<std::vector<uint_fast64_t>>({0, 1, 2, 3})));
582 storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, columnsAndValues, boost::optional<std::vector<uint_fast64_t>>({0, 1, 2, 3}));
583 ASSERT_EQ(3ul, matrix.getRowCount());
584 ASSERT_EQ(4ul, matrix.getColumnCount());
585 ASSERT_EQ(5ul, matrix.getEntryCount());
586 ASSERT_EQ(3ul, matrix.getRowGroupCount());
587}
588
589TEST(SparseMatrix, CopyConstruct) {
591 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
592 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
593 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
594 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
595 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 3, 0.2));
596
598 ASSERT_NO_THROW(matrix = matrixBuilder.build());
599
600 ASSERT_NO_THROW(storm::storage::SparseMatrix<double> copy(matrix));
602 ASSERT_TRUE(matrix == copy);
603}
604
605TEST(SparseMatrix, CopyAssign) {
607 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
608 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
609 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
610 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
611 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 3, 0.2));
612
614 ASSERT_NO_THROW(matrix = matrixBuilder.build());
615
616 ASSERT_NO_THROW(storm::storage::SparseMatrix<double> copy = matrix);
618 ASSERT_TRUE(matrix == copy);
619}
620
621TEST(SparseMatrix, MakeAbsorbing) {
622 storm::storage::SparseMatrixBuilder<double> matrixBuilder(3, 4, 5);
623 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
624 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
625 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
626 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
627 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 3, 0.2));
629 ASSERT_NO_THROW(matrix = matrixBuilder.build());
630
631 storm::storage::BitVector absorbingRows(3);
632 absorbingRows.set(1);
633
634 ASSERT_NO_THROW(matrix.makeRowsAbsorbing(absorbingRows));
635
636 storm::storage::SparseMatrixBuilder<double> matrixBuilder2(3, 4, 3);
637 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 1, 1.0));
638 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 2, 1.2));
639 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 1, 1));
640
642 ASSERT_NO_THROW(matrix2 = matrixBuilder2.build());
643
644 ASSERT_TRUE(matrix == matrix2);
645}
646
647TEST(SparseMatrix, MakeRowGroupAbsorbing) {
648 storm::storage::SparseMatrixBuilder<double> matrixBuilder(5, 4, 9, true, true);
649 ASSERT_NO_THROW(matrixBuilder.newRowGroup(0));
650 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
651 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
652 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
653 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
654 ASSERT_NO_THROW(matrixBuilder.newRowGroup(2));
655 ASSERT_NO_THROW(matrixBuilder.addNextValue(2, 0, 0.5));
656 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 2, 1.1));
657 ASSERT_NO_THROW(matrixBuilder.newRowGroup(4));
658 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 0, 0.1));
659 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 1, 0.2));
660 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 3, 0.3));
662 ASSERT_NO_THROW(matrix = matrixBuilder.build());
663
664 storm::storage::BitVector absorbingRowGroups(3);
665 absorbingRowGroups.set(1);
666
667 ASSERT_NO_THROW(matrix.makeRowGroupsAbsorbing(absorbingRowGroups));
668
669 storm::storage::SparseMatrixBuilder<double> matrixBuilder2(0, 0, 0, false, true);
670 ASSERT_NO_THROW(matrixBuilder2.newRowGroup(0));
671 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 1, 1.0));
672 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 2, 1.2));
673 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 0, 0.5));
674 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 1, 0.7));
675 ASSERT_NO_THROW(matrixBuilder2.newRowGroup(2));
676 ASSERT_NO_THROW(matrixBuilder2.addNextValue(2, 1, 1));
677 ASSERT_NO_THROW(matrixBuilder2.addNextValue(3, 1, 1));
678 ASSERT_NO_THROW(matrixBuilder2.newRowGroup(4));
679 ASSERT_NO_THROW(matrixBuilder2.addNextValue(4, 0, 0.1));
680 ASSERT_NO_THROW(matrixBuilder2.addNextValue(4, 1, 0.2));
681 ASSERT_NO_THROW(matrixBuilder2.addNextValue(4, 3, 0.3));
683 ASSERT_NO_THROW(matrix2 = matrixBuilder2.build());
684
685 ASSERT_TRUE(matrix == matrix2);
686}
687
688TEST(SparseMatrix, rowGroupIndices) {
689 storm::storage::SparseMatrixBuilder<double> matrixBuilder(5, 4, 9, true, true, 4);
690 ASSERT_NO_THROW(matrixBuilder.newRowGroup(0));
691 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
692 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
693 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
694 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
695 ASSERT_NO_THROW(matrixBuilder.newRowGroup(2));
696 ASSERT_NO_THROW(matrixBuilder.addNextValue(2, 0, 0.5));
697 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 2, 1.1));
698 ASSERT_NO_THROW(matrixBuilder.newRowGroup(4));
699 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 0, 0.1));
700 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 1, 0.2));
701 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 3, 0.3));
703 ASSERT_NO_THROW(matrix = matrixBuilder.build());
704
705 EXPECT_EQ(4ul, matrix.getRowGroupCount());
706 std::vector<storm::storage::SparseMatrixIndexType> expected, actual;
707 expected.assign({0, 1});
708 auto indices = matrix.getRowGroupIndices(0);
709 actual.assign(indices.begin(), indices.end());
710 EXPECT_EQ(expected, actual);
711 expected.assign({2, 3});
712 indices = matrix.getRowGroupIndices(1);
713 actual.assign(indices.begin(), indices.end());
714 EXPECT_EQ(expected, actual);
715 expected.assign({4});
716 indices = matrix.getRowGroupIndices(2);
717 actual.assign(indices.begin(), indices.end());
718 EXPECT_EQ(expected, actual);
719 expected.assign({});
720 indices = matrix.getRowGroupIndices(3);
721 actual.assign(indices.begin(), indices.end());
722 EXPECT_EQ(expected, actual);
723}
724
725TEST(SparseMatrix, ConstrainedRowSumVector) {
726 storm::storage::SparseMatrixBuilder<double> matrixBuilder(5, 4, 9);
727 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
728 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
729 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
730 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
731 ASSERT_NO_THROW(matrixBuilder.addNextValue(2, 0, 0.5));
732 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 2, 1.1));
733 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 0, 0.1));
734 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 1, 0.2));
735 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 3, 0.3));
737 ASSERT_NO_THROW(matrix = matrixBuilder.build());
738
739 storm::storage::BitVector columnConstraint(4);
740 columnConstraint.set(1);
741 columnConstraint.set(3);
742
743 ASSERT_NO_THROW(std::vector<double> constrainedRowSum = matrix.getConstrainedRowSumVector(storm::storage::BitVector(5, true), columnConstraint));
744 std::vector<double> constrainedRowSum = matrix.getConstrainedRowSumVector(storm::storage::BitVector(5, true), columnConstraint);
745 ASSERT_TRUE(constrainedRowSum == std::vector<double>({1.0, 0.7, 0, 0, 0.5}));
746
747 storm::storage::SparseMatrixBuilder<double> matrixBuilder2(5, 4, 9, true, true);
748 ASSERT_NO_THROW(matrixBuilder2.newRowGroup(0));
749 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 1, 1.0));
750 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 2, 1.2));
751 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 0, 0.5));
752 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 1, 0.7));
753 ASSERT_NO_THROW(matrixBuilder2.newRowGroup(2));
754 ASSERT_NO_THROW(matrixBuilder2.addNextValue(2, 0, 0.5));
755 ASSERT_NO_THROW(matrixBuilder2.addNextValue(3, 2, 1.1));
756 ASSERT_NO_THROW(matrixBuilder2.addNextValue(3, 3, 1.2));
757 ASSERT_NO_THROW(matrixBuilder2.newRowGroup(4));
758 ASSERT_NO_THROW(matrixBuilder2.addNextValue(4, 0, 0.1));
759 ASSERT_NO_THROW(matrixBuilder2.addNextValue(4, 3, 0.3));
761 ASSERT_NO_THROW(matrix2 = matrixBuilder2.build());
762
763 storm::storage::BitVector rowGroupConstraint(3);
764 rowGroupConstraint.set(1);
765
766 storm::storage::BitVector columnConstraint2(4);
767 columnConstraint2.set(2);
768 columnConstraint2.set(3);
769
770 ASSERT_NO_THROW(std::vector<double> constrainedRowSum2 = matrix2.getConstrainedRowGroupSumVector(rowGroupConstraint, columnConstraint2));
771 std::vector<double> constrainedRowSum2 = matrix2.getConstrainedRowGroupSumVector(rowGroupConstraint, columnConstraint2);
772 ASSERT_TRUE(constrainedRowSum2 == std::vector<double>({0, 2.3}));
773}
774
775TEST(SparseMatrix, Submatrix) {
776 storm::storage::SparseMatrixBuilder<double> matrixBuilder(5, 4, 9, true, true);
777 ASSERT_NO_THROW(matrixBuilder.newRowGroup(0));
778 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
779 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
780 ASSERT_NO_THROW(matrixBuilder.newRowGroup(1));
781 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
782 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
783 ASSERT_NO_THROW(matrixBuilder.newRowGroup(2));
784 ASSERT_NO_THROW(matrixBuilder.addNextValue(2, 0, 0.5));
785 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 2, 1.1));
786 ASSERT_NO_THROW(matrixBuilder.newRowGroup(4));
787 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 0, 0.1));
788 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 1, 0.2));
789 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 3, 0.3));
791 ASSERT_NO_THROW(matrix = matrixBuilder.build());
792
793 storm::storage::BitVector rowGroupConstraint(4);
794 storm::storage::BitVector columnConstraint(4);
795
796 STORM_SILENT_ASSERT_THROW(matrix.getSubmatrix(true, rowGroupConstraint, columnConstraint), storm::exceptions::InvalidArgumentException);
797
798 std::vector<uint_fast64_t> rowGroupIndices = {0, 1, 2, 4, 5};
799
800 rowGroupConstraint.set(2);
801 rowGroupConstraint.set(3);
802 columnConstraint.set(0);
803 columnConstraint.set(3);
804
805 ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix2 = matrix.getSubmatrix(true, rowGroupConstraint, columnConstraint, false));
806 storm::storage::SparseMatrix<double> matrix2 = matrix.getSubmatrix(true, rowGroupConstraint, columnConstraint, false);
807
808 storm::storage::SparseMatrixBuilder<double> matrixBuilder3(3, 2, 3, true, true);
809 ASSERT_NO_THROW(matrixBuilder3.newRowGroup(0));
810 ASSERT_NO_THROW(matrixBuilder3.addNextValue(0, 0, 0.5));
811 ASSERT_NO_THROW(matrixBuilder3.newRowGroup(2));
812 ASSERT_NO_THROW(matrixBuilder3.addNextValue(2, 0, 0.1));
813 ASSERT_NO_THROW(matrixBuilder3.addNextValue(2, 1, 0.3));
815 ASSERT_NO_THROW(matrix3 = matrixBuilder3.build());
816
817 ASSERT_TRUE(matrix2 == matrix3);
818
819 std::vector<uint_fast64_t> rowGroupToIndexMapping = {0, 0, 1, 0};
820
821 ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix4 = matrix.selectRowsFromRowGroups(rowGroupToIndexMapping));
822 storm::storage::SparseMatrix<double> matrix4 = matrix.selectRowsFromRowGroups(rowGroupToIndexMapping);
823
824 storm::storage::SparseMatrixBuilder<double> matrixBuilder5(4, 4, 8);
825 ASSERT_NO_THROW(matrixBuilder5.addNextValue(0, 1, 1.0));
826 ASSERT_NO_THROW(matrixBuilder5.addNextValue(0, 2, 1.2));
827 ASSERT_NO_THROW(matrixBuilder5.addNextValue(1, 0, 0.5));
828 ASSERT_NO_THROW(matrixBuilder5.addNextValue(1, 1, 0.7));
829 ASSERT_NO_THROW(matrixBuilder5.addNextValue(2, 2, 1.1));
830 ASSERT_NO_THROW(matrixBuilder5.addNextValue(3, 0, 0.1));
831 ASSERT_NO_THROW(matrixBuilder5.addNextValue(3, 1, 0.2));
832 ASSERT_NO_THROW(matrixBuilder5.addNextValue(3, 3, 0.3));
834 ASSERT_NO_THROW(matrix5 = matrixBuilder5.build());
835
836 ASSERT_TRUE(matrix4 == matrix5);
837}
838
839TEST(SparseMatrix, RestrictRows) {
840 storm::storage::SparseMatrixBuilder<double> matrixBuilder1(7, 4, 9, true, true, 3);
841 ASSERT_NO_THROW(matrixBuilder1.newRowGroup(0));
842 ASSERT_NO_THROW(matrixBuilder1.addNextValue(0, 1, 1.0));
843 ASSERT_NO_THROW(matrixBuilder1.addNextValue(0, 2, 1.2));
844 ASSERT_NO_THROW(matrixBuilder1.addNextValue(1, 0, 0.5));
845 ASSERT_NO_THROW(matrixBuilder1.addNextValue(1, 1, 0.7));
846 ASSERT_NO_THROW(matrixBuilder1.newRowGroup(2));
847 ASSERT_NO_THROW(matrixBuilder1.addNextValue(2, 0, 0.5));
848 ASSERT_NO_THROW(matrixBuilder1.addNextValue(3, 2, 1.1));
849 ASSERT_NO_THROW(matrixBuilder1.newRowGroup(4));
850 ASSERT_NO_THROW(matrixBuilder1.addNextValue(4, 0, 0.1));
851 ASSERT_NO_THROW(matrixBuilder1.addNextValue(4, 1, 0.2));
852 ASSERT_NO_THROW(matrixBuilder1.addNextValue(6, 3, 0.3));
854 ASSERT_NO_THROW(matrix1 = matrixBuilder1.build());
855
856 storm::storage::BitVector constraint1(7);
857 constraint1.set(0);
858 constraint1.set(1);
859 constraint1.set(2);
860 constraint1.set(5);
861
863 ASSERT_NO_THROW(matrix1Prime = matrix1.restrictRows(constraint1));
864
865 storm::storage::SparseMatrixBuilder<double> matrixBuilder2(4, 4, 5, true, true, 3);
866 ASSERT_NO_THROW(matrixBuilder2.newRowGroup(0));
867 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 1, 1.0));
868 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 2, 1.2));
869 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 0, 0.5));
870 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 1, 0.7));
871 ASSERT_NO_THROW(matrixBuilder2.newRowGroup(2));
872 ASSERT_NO_THROW(matrixBuilder2.addNextValue(2, 0, 0.5));
873 ASSERT_NO_THROW(matrixBuilder2.newRowGroup(3));
875 ASSERT_NO_THROW(matrix2 = matrixBuilder2.build());
876
877 ASSERT_EQ(matrix2, matrix1Prime);
878
879 storm::storage::BitVector constraint2(4);
880 constraint2.set(1);
881 constraint2.set(2);
882
884 STORM_SILENT_ASSERT_THROW(matrix2Prime = matrix2.restrictRows(constraint2), storm::exceptions::InvalidArgumentException);
885 ASSERT_NO_THROW(matrix2Prime = matrix2.restrictRows(constraint2, true));
886
887 storm::storage::SparseMatrixBuilder<double> matrixBuilder3(2, 4, 3, true, true, 3);
888 ASSERT_NO_THROW(matrixBuilder3.newRowGroup(0));
889 ASSERT_NO_THROW(matrixBuilder3.addNextValue(0, 0, 0.5));
890 ASSERT_NO_THROW(matrixBuilder3.addNextValue(0, 1, 0.7));
891 ASSERT_NO_THROW(matrixBuilder3.newRowGroup(1));
892 ASSERT_NO_THROW(matrixBuilder3.addNextValue(1, 0, 0.5));
894 ASSERT_NO_THROW(matrix3 = matrixBuilder3.build());
895
896 ASSERT_EQ(matrix3, matrix2Prime);
897
898 matrix3.makeRowGroupingTrivial();
899 storm::storage::BitVector constraint3(2);
900 constraint3.set(1);
901
903 STORM_SILENT_ASSERT_THROW(matrix3Prime = matrix3.restrictRows(constraint3), storm::exceptions::InvalidArgumentException);
904 ASSERT_NO_THROW(matrix3Prime = matrix3.restrictRows(constraint3, true));
905
906 storm::storage::SparseMatrixBuilder<double> matrixBuilder4(1, 4, 1, true, true, 2);
907 ASSERT_NO_THROW(matrixBuilder4.newRowGroup(0));
908 ASSERT_NO_THROW(matrixBuilder4.newRowGroup(0));
909 ASSERT_NO_THROW(matrixBuilder4.addNextValue(0, 0, 0.5));
911 ASSERT_NO_THROW(matrix4 = matrixBuilder4.build());
912
913 ASSERT_EQ(matrix4, matrix3Prime);
914}
915
916TEST(SparseMatrix, Transpose) {
917 storm::storage::SparseMatrixBuilder<double> matrixBuilder(5, 4, 9);
918 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
919 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
920 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
921 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
922 ASSERT_NO_THROW(matrixBuilder.addNextValue(2, 0, 0.5));
923 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 2, 1.1));
924 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 0, 0.1));
925 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 1, 0.2));
926 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 3, 0.3));
928 ASSERT_NO_THROW(matrix = matrixBuilder.build());
929
930 ASSERT_NO_THROW(storm::storage::SparseMatrix<double> transposeResult = matrix.transpose());
931 storm::storage::SparseMatrix<double> transposeResult = matrix.transpose();
932
933 storm::storage::SparseMatrixBuilder<double> matrixBuilder2(4, 5, 9);
934 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 1, 0.5));
935 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 2, 0.5));
936 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 4, 0.1));
937 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 0, 1.0));
938 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 1, 0.7));
939 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 4, 0.2));
940 ASSERT_NO_THROW(matrixBuilder2.addNextValue(2, 0, 1.2));
941 ASSERT_NO_THROW(matrixBuilder2.addNextValue(2, 3, 1.1));
942 ASSERT_NO_THROW(matrixBuilder2.addNextValue(3, 4, 0.3));
944 ASSERT_NO_THROW(matrix2 = matrixBuilder2.build());
945
946 ASSERT_TRUE(transposeResult == matrix2);
947}
948
949TEST(SparseMatrix, EquationSystem) {
950 storm::storage::SparseMatrixBuilder<double> matrixBuilder(4, 4, 7);
951 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 0, 1.1));
952 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.2));
953 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.5));
954 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 3, 0.7));
955 ASSERT_NO_THROW(matrixBuilder.addNextValue(2, 0, 0.5));
956 ASSERT_NO_THROW(matrixBuilder.addNextValue(2, 2, 0.99));
957 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 3, 0.11));
959 ASSERT_NO_THROW(matrix = matrixBuilder.build());
960
961 ASSERT_NO_THROW(matrix.convertToEquationSystem());
962
963 storm::storage::SparseMatrixBuilder<double> matrixBuilder2(4, 4, 7);
964 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 0, 1 - 1.1));
965 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 1, -1.2));
966 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 1, 1 - 0.5));
967 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 3, -0.7));
968 ASSERT_NO_THROW(matrixBuilder2.addNextValue(2, 0, -0.5));
969 ASSERT_NO_THROW(matrixBuilder2.addNextValue(2, 2, 1 - 0.99));
970 ASSERT_NO_THROW(matrixBuilder2.addNextValue(3, 3, 1 - 0.11));
972 ASSERT_NO_THROW(matrix2 = matrixBuilder2.build());
973
974 ASSERT_TRUE(matrix == matrix2);
975}
976
977TEST(SparseMatrix, JacobiDecomposition) {
978 storm::storage::SparseMatrixBuilder<double> matrixBuilder(4, 4, 7);
979 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 0, 1.1));
980 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.2));
981 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.5));
982 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 3, 0.7));
983 ASSERT_NO_THROW(matrixBuilder.addNextValue(2, 0, 0.5));
984 ASSERT_NO_THROW(matrixBuilder.addNextValue(2, 2, 0.99));
985 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 3, 0.11));
987 ASSERT_NO_THROW(matrix = matrixBuilder.build());
988
989 ASSERT_NO_THROW(matrix.getJacobiDecomposition());
990 std::pair<storm::storage::SparseMatrix<double>, std::vector<double>> jacobiDecomposition = matrix.getJacobiDecomposition();
991
993 ASSERT_NO_THROW(luBuilder.addNextValue(0, 1, 1.2));
994 ASSERT_NO_THROW(luBuilder.addNextValue(1, 3, 0.7));
995 ASSERT_NO_THROW(luBuilder.addNextValue(2, 0, 0.5));
997 ASSERT_NO_THROW(lu = luBuilder.build());
998
999 std::vector<double> dinv = {1 / 1.1, 1 / 0.5, 1 / 0.99, 1 / 0.11};
1000 ASSERT_TRUE(lu == jacobiDecomposition.first);
1001 ASSERT_TRUE(dinv == jacobiDecomposition.second);
1002}
1003
1004TEST(SparseMatrix, PointwiseMultiplicationVector) {
1005 storm::storage::SparseMatrixBuilder<double> matrixBuilder(5, 4, 9);
1006 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
1007 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
1008 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
1009 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
1010 ASSERT_NO_THROW(matrixBuilder.addNextValue(2, 0, 0.5));
1011 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 2, 1.1));
1012 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 0, 0.1));
1013 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 1, 0.2));
1014 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 3, 0.3));
1016 ASSERT_NO_THROW(matrix = matrixBuilder.build());
1017
1018 storm::storage::SparseMatrixBuilder<double> matrixBuilder2(5, 4, 9);
1019 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 1, 1.0));
1020 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 2, 1.2));
1021 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 0, 0.5));
1022 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 1, 0.7));
1023 ASSERT_NO_THROW(matrixBuilder2.addNextValue(2, 0, 0.5));
1024 ASSERT_NO_THROW(matrixBuilder2.addNextValue(3, 2, 1.1));
1025 ASSERT_NO_THROW(matrixBuilder2.addNextValue(4, 0, 0.1));
1026 ASSERT_NO_THROW(matrixBuilder2.addNextValue(4, 1, 0.2));
1027 ASSERT_NO_THROW(matrixBuilder2.addNextValue(4, 3, 0.3));
1029 ASSERT_NO_THROW(matrix2 = matrixBuilder2.build());
1030
1031 ASSERT_NO_THROW(std::vector<double> pointwiseProductRowSums = matrix.getPointwiseProductRowSumVector(matrix2));
1032 std::vector<double> pointwiseProductRowSums = matrix.getPointwiseProductRowSumVector(matrix2);
1033
1034 std::vector<double> correctResult = {1.0 * 1.0 + 1.2 * 1.2, 0.5 * 0.5 + 0.7 * 0.7, 0.5 * 0.5, 1.1 * 1.1, 0.1 * 0.1 + 0.2 * 0.2 + 0.3 * 0.3};
1035 ASSERT_TRUE(pointwiseProductRowSums == correctResult);
1036}
1037
1038TEST(SparseMatrix, MatrixVectorMultiply) {
1039 storm::storage::SparseMatrixBuilder<double> matrixBuilder(5, 4, 9);
1040 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
1041 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
1042 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
1043 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
1044 ASSERT_NO_THROW(matrixBuilder.addNextValue(2, 0, 0.5));
1045 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 2, 1.1));
1046 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 0, 0.1));
1047 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 1, 0.2));
1048 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 3, 0.3));
1050 ASSERT_NO_THROW(matrix = matrixBuilder.build());
1051
1052 std::vector<double> x = {1, 0.3, 1.4, 7.1};
1053 std::vector<double> result(matrix.getRowCount());
1054
1055 ASSERT_NO_THROW(matrix.multiplyWithVector(x, result));
1056
1057 std::vector<double> correctResult = {1.0 * 0.3 + 1.2 * 1.4, 0.5 * 1 + 0.7 * 0.3, 0.5 * 1, 1.1 * 1.4, 0.1 * 1 + 0.2 * 0.3 + 0.3 * 7.1};
1058
1059 for (std::size_t index = 0; index < correctResult.size(); ++index) {
1060 ASSERT_NEAR(result[index], correctResult[index], 1e-12);
1061 }
1062}
1063
1064TEST(SparseMatrix, Iteration) {
1065 storm::storage::SparseMatrixBuilder<double> matrixBuilder(5, 4, 9);
1066 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
1067 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
1068 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
1069 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
1070 ASSERT_NO_THROW(matrixBuilder.addNextValue(2, 0, 0.5));
1071 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 2, 1.1));
1072 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 0, 0.1));
1073 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 1, 0.2));
1074 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 3, 0.3));
1076 ASSERT_NO_THROW(matrix = matrixBuilder.build());
1077
1078 for (auto const& entry : matrix.getRow(4)) {
1079 if (entry.getColumn() == 0) {
1080 ASSERT_EQ(0.1, entry.getValue());
1081 } else if (entry.getColumn() == 1) {
1082 ASSERT_EQ(0.2, entry.getValue());
1083 } else if (entry.getColumn() == 3) {
1084 ASSERT_EQ(0.3, entry.getValue());
1085 } else {
1086 ASSERT_TRUE(false);
1087 }
1088 }
1089
1090 for (storm::storage::SparseMatrix<double>::iterator it = matrix.begin(4), ite = matrix.end(4); it != ite; ++it) {
1091 if (it->getColumn() == 0) {
1092 ASSERT_EQ(0.1, it->getValue());
1093 } else if (it->getColumn() == 1) {
1094 ASSERT_EQ(0.2, it->getValue());
1095 } else if (it->getColumn() == 3) {
1096 ASSERT_EQ(0.3, it->getValue());
1097 } else {
1098 ASSERT_TRUE(false);
1099 }
1100 }
1101}
1102
1103TEST(SparseMatrix, RowSum) {
1104 storm::storage::SparseMatrixBuilder<double> matrixBuilder(5, 4, 8);
1105 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
1106 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
1107 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
1108 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
1109 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 2, 1.1));
1110 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 0, 0.1));
1111 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 1, 0.2));
1112 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 3, 0.3));
1114 ASSERT_NO_THROW(matrix = matrixBuilder.build());
1115
1116 ASSERT_EQ(0, matrix.getRowSum(2));
1117 ASSERT_EQ(0.1 + 0.2 + 0.3, matrix.getRowSum(4));
1118}
1119
1120TEST(SparseMatrix, IsSubmatrix) {
1121 storm::storage::SparseMatrixBuilder<double> matrixBuilder(5, 4, 8);
1122 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
1123 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
1124 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
1125 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
1126 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 2, 1.1));
1127 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 0, 0.1));
1128 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 1, 0.2));
1129 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 3, 0.3));
1131 ASSERT_NO_THROW(matrix = matrixBuilder.build());
1132
1133 storm::storage::SparseMatrixBuilder<double> matrixBuilder2(5, 4, 5);
1134 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 1, 1.0));
1135 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 0, 0.5));
1136 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 1, 0.7));
1137 ASSERT_NO_THROW(matrixBuilder2.addNextValue(4, 0, 0.1));
1138 ASSERT_NO_THROW(matrixBuilder2.addNextValue(4, 1, 0.2));
1140 ASSERT_NO_THROW(matrix2 = matrixBuilder2.build());
1141
1142 ASSERT_TRUE(matrix2.isSubmatrixOf(matrix));
1143
1144 storm::storage::SparseMatrixBuilder<double> matrixBuilder3(5, 4, 5);
1145 ASSERT_NO_THROW(matrixBuilder3.addNextValue(0, 3, 1.0));
1146 ASSERT_NO_THROW(matrixBuilder3.addNextValue(1, 0, 0.5));
1147 ASSERT_NO_THROW(matrixBuilder3.addNextValue(1, 1, 0.7));
1148 ASSERT_NO_THROW(matrixBuilder3.addNextValue(4, 0, 0.1));
1149 ASSERT_NO_THROW(matrixBuilder3.addNextValue(4, 1, 0.2));
1151 ASSERT_NO_THROW(matrix3 = matrixBuilder3.build());
1152
1153 ASSERT_FALSE(matrix3.isSubmatrixOf(matrix));
1154 ASSERT_FALSE(matrix3.isSubmatrixOf(matrix2));
1155}
1156
1157TEST(SparseMatrix, PermuteRows) {
1158 storm::storage::SparseMatrixBuilder<double> matrixBuilder(5, 4, 8);
1159 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
1160 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
1161 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
1162 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
1163 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 2, 1.1));
1164 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 0, 0.1));
1165 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 1, 0.2));
1166 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 3, 0.3));
1168 ASSERT_NO_THROW(matrix = matrixBuilder.build());
1169
1170 std::vector<uint64_t> inversePermutation = {1, 4, 0, 3, 2};
1171 storm::storage::SparseMatrix<double> matrixperm = matrix.permuteRows(inversePermutation);
1172 EXPECT_EQ(5ul, matrixperm.getRowCount());
1173 EXPECT_EQ(4ul, matrixperm.getColumnCount());
1174 EXPECT_EQ(8ul, matrixperm.getEntryCount());
1175 EXPECT_EQ(matrix.getRowSum(1), matrixperm.getRowSum(0));
1176 EXPECT_EQ(matrix.getRowSum(4), matrixperm.getRowSum(1));
1177 EXPECT_EQ(matrix.getRowSum(0), matrixperm.getRowSum(2));
1178 EXPECT_EQ(matrix.getRowSum(3), matrixperm.getRowSum(3));
1179 EXPECT_EQ(matrix.getRowSum(2), matrixperm.getRowSum(4));
1180}
1181
1182TEST(SparseMatrix, PermuteRowGroupsAndColumns) {
1183 storm::storage::SparseMatrixBuilder<double> matrixBuilder(5, 4, 9, true, true, 4);
1184 ASSERT_NO_THROW(matrixBuilder.newRowGroup(0));
1185 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0)); // Group 0
1186 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
1187 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
1188 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 0.7));
1189 ASSERT_NO_THROW(matrixBuilder.newRowGroup(2));
1190 ASSERT_NO_THROW(matrixBuilder.addNextValue(2, 0, 0.5)); // Group 1
1191 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 2, 1.1));
1192 ASSERT_NO_THROW(matrixBuilder.newRowGroup(4));
1193 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 0, 0.1)); // Group 2
1194 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 1, 0.2));
1195 ASSERT_NO_THROW(matrixBuilder.addNextValue(4, 3, 0.3));
1196 // Group 3 is empty
1198 ASSERT_NO_THROW(matrix = matrixBuilder.build());
1199
1200 std::vector<uint64_t> permutation = {3, 0, 2, 1};
1201 std::vector<uint64_t> invertedPermutation = {1, 3, 2, 0};
1202 EXPECT_EQ(invertedPermutation, storm::utility::permutation::invertPermutation(permutation));
1203 auto matrixPerm = matrix.permuteRowGroupsAndColumns(invertedPermutation, permutation);
1204
1205 storm::storage::SparseMatrixBuilder<double> expectedBuilder(5, 4, 9, true, true, 4);
1206 ASSERT_NO_THROW(expectedBuilder.newRowGroup(0));
1207 ASSERT_NO_THROW(expectedBuilder.addNextValue(0, 3, 0.5));
1208 ASSERT_NO_THROW(expectedBuilder.addNextValue(1, 2, 1.1));
1209 ASSERT_NO_THROW(expectedBuilder.newRowGroup(2));
1210 ASSERT_NO_THROW(expectedBuilder.newRowGroup(2));
1211 ASSERT_NO_THROW(expectedBuilder.addNextValue(2, 3, 0.1));
1212 ASSERT_NO_THROW(expectedBuilder.addNextValue(2, 0, 0.2));
1213 ASSERT_NO_THROW(expectedBuilder.addNextValue(2, 1, 0.3));
1214 ASSERT_NO_THROW(expectedBuilder.newRowGroup(3));
1215 ASSERT_NO_THROW(expectedBuilder.addNextValue(3, 0, 1.0));
1216 ASSERT_NO_THROW(expectedBuilder.addNextValue(3, 2, 1.2));
1217 ASSERT_NO_THROW(expectedBuilder.addNextValue(4, 3, 0.5));
1218 ASSERT_NO_THROW(expectedBuilder.addNextValue(4, 0, 0.7));
1220 ASSERT_NO_THROW(expectedMatrix = expectedBuilder.build());
1221 EXPECT_EQ(expectedMatrix, matrixPerm);
1222
1223 auto matrixPerm2 = matrixPerm.permuteRowGroupsAndColumns(permutation, invertedPermutation);
1224 EXPECT_EQ(matrix, matrixPerm2);
1225}
1226
1227TEST(SparseMatrix, DropZeroEntries) {
1228 storm::storage::SparseMatrixBuilder<double> matrixBuilder(4, 3, 8, true, true);
1229 ASSERT_NO_THROW(matrixBuilder.newRowGroup(0));
1230 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 1, 1.0));
1231 ASSERT_NO_THROW(matrixBuilder.addNextValue(0, 2, 1.2));
1232 ASSERT_NO_THROW(matrixBuilder.newRowGroup(1));
1233 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 0, 0.5));
1234 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 1, 1.1));
1235 ASSERT_NO_THROW(matrixBuilder.addNextValue(1, 2, 0.5));
1236 ASSERT_NO_THROW(matrixBuilder.newRowGroup(2));
1237 ASSERT_NO_THROW(matrixBuilder.addNextValue(2, 0, 0.1));
1238 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 1, 0.2));
1239 ASSERT_NO_THROW(matrixBuilder.addNextValue(3, 2, 0.3));
1241 ASSERT_NO_THROW(matrix = matrixBuilder.build());
1242
1243 storm::storage::BitVector absorbingRows(3);
1244 absorbingRows.set(0);
1245
1246 ASSERT_NO_THROW(matrix.makeRowsAbsorbing(absorbingRows, true));
1247
1248 storm::storage::SparseMatrixBuilder<double> matrixBuilderX(4, 3, 8, true, true);
1249 ASSERT_NO_THROW(matrixBuilderX.newRowGroup(0));
1250 ASSERT_NO_THROW(matrixBuilderX.addNextValue(0, 1, 1.0));
1251 ASSERT_NO_THROW(matrixBuilderX.addNextValue(0, 2, 1.2));
1252 ASSERT_NO_THROW(matrixBuilderX.newRowGroup(1));
1253 ASSERT_NO_THROW(matrixBuilderX.addNextValue(1, 0, 0.5));
1254 ASSERT_NO_THROW(matrixBuilderX.addNextValue(1, 1, 1.1));
1255 ASSERT_NO_THROW(matrixBuilderX.addNextValue(1, 2, 0.5));
1256 ASSERT_NO_THROW(matrixBuilderX.newRowGroup(2));
1257 ASSERT_NO_THROW(matrixBuilderX.addNextValue(2, 0, 0.1));
1258 ASSERT_NO_THROW(matrixBuilderX.addNextValue(3, 1, 0.2));
1259 ASSERT_NO_THROW(matrixBuilderX.addNextValue(3, 2, 0.3));
1261 ASSERT_NO_THROW(matrixX = matrixBuilderX.build());
1262
1263 ASSERT_NO_THROW(matrixX.makeRowsAbsorbing(absorbingRows, false));
1264
1265 storm::storage::SparseMatrixBuilder<double> matrixBuilder2(4, 3, 7, true, true);
1266 ASSERT_NO_THROW(matrixBuilder2.newRowGroup(0));
1267 ASSERT_NO_THROW(matrixBuilder2.addNextValue(0, 0, 1.0));
1268 ASSERT_NO_THROW(matrixBuilder2.newRowGroup(1));
1269 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 0, 0.5));
1270 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 1, 1.1));
1271 ASSERT_NO_THROW(matrixBuilder2.addNextValue(1, 2, 0.5));
1272 ASSERT_NO_THROW(matrixBuilder2.newRowGroup(2));
1273 ASSERT_NO_THROW(matrixBuilder2.addNextValue(2, 0, 0.1));
1274 ASSERT_NO_THROW(matrixBuilder2.addNextValue(3, 1, 0.2));
1275 ASSERT_NO_THROW(matrixBuilder2.addNextValue(3, 2, 0.3));
1277 ASSERT_NO_THROW(matrix2 = matrixBuilder2.build());
1278
1279 ASSERT_TRUE(matrix == matrix2);
1280 ASSERT_TRUE(matrix.getEntryCount() == matrix2.getEntryCount());
1281
1282 ASSERT_TRUE(matrixX == matrix2);
1283 ASSERT_FALSE(matrixX.getEntryCount() == matrix2.getEntryCount());
1284
1285 ASSERT_NO_THROW(matrix.makeRowDirac(1, 1, true));
1286 ASSERT_NO_THROW(matrixX.dropZeroEntries());
1287 ASSERT_NO_THROW(matrixX.makeRowDirac(1, 1, false));
1288
1289 storm::storage::SparseMatrixBuilder<double> matrixBuilder3(4, 3, 5, true, true);
1290 ASSERT_NO_THROW(matrixBuilder3.newRowGroup(0));
1291 ASSERT_NO_THROW(matrixBuilder3.addNextValue(0, 0, 1.0));
1292 ASSERT_NO_THROW(matrixBuilder3.newRowGroup(1));
1293 ASSERT_NO_THROW(matrixBuilder3.addNextValue(1, 1, 1.0));
1294 ASSERT_NO_THROW(matrixBuilder3.newRowGroup(2));
1295 ASSERT_NO_THROW(matrixBuilder3.addNextValue(2, 0, 0.1));
1296 ASSERT_NO_THROW(matrixBuilder3.addNextValue(3, 1, 0.2));
1297 ASSERT_NO_THROW(matrixBuilder3.addNextValue(3, 2, 0.3));
1299 ASSERT_NO_THROW(matrix3 = matrixBuilder3.build());
1300
1301 ASSERT_TRUE(matrix == matrix3);
1302 ASSERT_TRUE(matrix.getEntryCount() == matrix3.getEntryCount());
1303
1304 ASSERT_TRUE(matrixX == matrix3);
1305 ASSERT_FALSE(matrixX.getEntryCount() == matrix3.getEntryCount());
1306
1307 storm::storage::BitVector absorbingRowGroups(3);
1308 absorbingRowGroups.set(2);
1309
1310 ASSERT_NO_THROW(matrix.makeRowGroupsAbsorbing(absorbingRowGroups, true));
1311 ASSERT_NO_THROW(matrixX.dropZeroEntries());
1312 ASSERT_NO_THROW(matrixX.makeRowGroupsAbsorbing(absorbingRowGroups, false));
1313
1314 storm::storage::SparseMatrixBuilder<double> matrixBuilder4(4, 3, 4, true, true);
1315 ASSERT_NO_THROW(matrixBuilder4.newRowGroup(0));
1316 ASSERT_NO_THROW(matrixBuilder4.addNextValue(0, 0, 1.0));
1317 ASSERT_NO_THROW(matrixBuilder4.newRowGroup(1));
1318 ASSERT_NO_THROW(matrixBuilder4.addNextValue(1, 1, 1.0));
1319 ASSERT_NO_THROW(matrixBuilder4.newRowGroup(2));
1320 ASSERT_NO_THROW(matrixBuilder4.addNextValue(2, 2, 1.0));
1321 ASSERT_NO_THROW(matrixBuilder4.addNextValue(3, 2, 1.0));
1323 ASSERT_NO_THROW(matrix4 = matrixBuilder4.build());
1324
1325 ASSERT_TRUE(matrix == matrix4);
1326 ASSERT_TRUE(matrix.getEntryCount() == matrix4.getEntryCount());
1327
1328 ASSERT_TRUE(matrixX == matrix4);
1329 ASSERT_FALSE(matrixX.getEntryCount() == matrix4.getEntryCount());
1330}
1331
1332TEST(SparseMatrix, isProbabilistic) {
1333 storm::storage::SparseMatrixBuilder<double> builder(4, 4, 7, true);
1334 ASSERT_NO_THROW(builder.addNextValue(0, 1, storm::utility::sqrt(2.0)));
1335 ASSERT_NO_THROW(builder.addNextValue(0, 2, 1.0 - storm::utility::sqrt(2.0)));
1336 ASSERT_NO_THROW(builder.addNextValue(1, 2, storm::utility::sqrt(2.0)));
1337 ASSERT_NO_THROW(builder.addNextValue(1, 3, 1.0 - storm::utility::sqrt(2.0)));
1338 ASSERT_NO_THROW(builder.addNextValue(2, 0, storm::utility::sqrt(2.0)));
1339 ASSERT_NO_THROW(builder.addNextValue(2, 3, 1.0 - storm::utility::sqrt(2.0)));
1340 ASSERT_NO_THROW(builder.addNextValue(3, 3, 1.0));
1342 ASSERT_NO_THROW(matrix = builder.build());
1343 std::string reason;
1344 ASSERT_FALSE(matrix.isProbabilistic(0.0, reason)) << reason;
1345 ASSERT_TRUE(matrix.isProbabilistic(0.5, reason)) << reason;
1346 for (auto& entry : matrix) {
1347 entry.setValue(storm::utility::abs(entry.getValue()) / 2.0);
1348 }
1349 ASSERT_FALSE(matrix.isProbabilistic(0, reason)) << reason;
1350}
1351
1352TEST(SparseMatrix, EqualityIgnoresExplicitZeros) {
1354 builder1.addNextValue(0, 0, 0.5);
1355 builder1.addNextValue(0, 2, 0.0); // explicit trailing zero
1356 builder1.addNextValue(1, 1, 0.0); // row that only consists of a zero
1357 builder1.addNextValue(1, 2, 1.0);
1358 auto matrix1 = builder1.build();
1359
1361 builder2.addNextValue(0, 0, 0.5);
1362 builder2.addNextValue(1, 2, 1.0);
1363 auto matrix2 = builder2.build();
1364
1365 EXPECT_TRUE(matrix1 == matrix2);
1366 EXPECT_TRUE(matrix2 == matrix1);
1367 EXPECT_TRUE(matrix1 == matrix1);
1368
1370 builder3.addNextValue(0, 0, 0.5);
1371 builder3.addNextValue(1, 1, 0.25);
1372 builder3.addNextValue(1, 2, 1.0);
1373 auto matrix3 = builder3.build();
1374 EXPECT_FALSE(matrix1 == matrix3);
1375 EXPECT_FALSE(matrix3 == matrix2);
1376 // Different number of non-zero entries in a row
1378 builder4.addNextValue(0, 0, 0.5);
1379 auto matrix4 = builder4.build();
1380 EXPECT_FALSE(matrix4 == matrix2);
1381 EXPECT_FALSE(matrix2 == matrix4);
1382}
TEST(SparseMatrixBuilder, CreationEmpty)
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
A class that can be used to build a sparse matrix by adding value by value.
AccumulationMode
Specifies how values that are added for the same row and column are combined.
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 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.
void setAccumulationMode(AccumulationMode mode)
Sets how values that are added for the same row and column are combined.
SparseMatrix< value_type > build(index_type overriddenRowCount=0, index_type overriddenColumnCount=0, index_type overriddenRowGroupCount=0)
AccumulationMode getAccumulationMode() const
Retrieves how values that are added for the same row and column are combined.
A class that holds a possibly non-square matrix in the compressed row storage format.
void convertToEquationSystem()
Transforms the matrix into an equation system.
const_rows getRow(index_type row) const
Returns an object representing the given row.
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.
index_type getEntryCount() const
Returns the number of entries in the matrix.
bool isProbabilistic(ValueType const &tolerance, storm::OptionalRef< std::string > reason={}) const
Checks for each row whether (i) each entry is between zero and one and (ii) all entries sum to one.
void makeRowsAbsorbing(storm::storage::BitVector const &rows, bool dropZeroEntries=false)
This function makes the given rows absorbing.
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.
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 ...
const_iterator begin(index_type row) const
Retrieves an iterator that points to the beginning of the given row.
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...
SparseMatrix permuteRows(std::vector< index_type > const &inversePermutation) const
Permute rows of the matrix according to the vector.
SparseMatrix restrictRows(storm::storage::BitVector const &rowsToKeep, bool allowEmptyRowGroups=false) const
Restrict rows in grouped rows matrix.
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.
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...
void makeRowGroupsAbsorbing(storm::storage::BitVector const &rowGroupConstraint, bool dropZeroEntries=false)
This function makes the groups of rows given by the bit vector absorbing.
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< 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 makeRowGroupingTrivial()
Makes the row grouping of this matrix trivial.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
std::vector< MatrixEntry< index_type, value_type > >::iterator iterator
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.
index_type getRowCount() const
Returns the number of rows of the matrix.
typename storm::storage::SparseMatrixBuilder< ValueType >::AccumulationMode AccumulationMode
std::vector< index_type > invertPermutation(std::vector< index_type > const &permutation)
Inverts the given permutation.
ValueType abs(ValueType const &number)
ValueType sqrt(ValueType const &number)
#define STORM_SILENT_ASSERT_THROW(statement, expected_exception)
Definition storm_gtest.h:16