Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
EndComponentEliminatorTest.cpp
Go to the documentation of this file.
1#include "storm-config.h"
2#include "test/storm_gtest.h"
3
5
6TEST(NeutralECRemover, SimpleModelTest) {
7 storm::storage::SparseMatrixBuilder<double> builder(12, 5, 19, true, true, 5);
8 ASSERT_NO_THROW(builder.newRowGroup(0));
9 ASSERT_NO_THROW(builder.addNextValue(0, 0, 1.0));
10 ASSERT_NO_THROW(builder.addNextValue(1, 1, 0.3));
11 ASSERT_NO_THROW(builder.addNextValue(1, 2, 0.1));
12 ASSERT_NO_THROW(builder.addNextValue(1, 3, 0.4));
13 ASSERT_NO_THROW(builder.addNextValue(1, 4, 0.2));
14 ASSERT_NO_THROW(builder.newRowGroup(2));
15 ASSERT_NO_THROW(builder.addNextValue(2, 1, 0.7));
16 ASSERT_NO_THROW(builder.addNextValue(2, 3, 0.3));
17 ASSERT_NO_THROW(builder.addNextValue(3, 1, 0.1));
18 ASSERT_NO_THROW(builder.addNextValue(3, 4, 0.9));
19 ASSERT_NO_THROW(builder.addNextValue(4, 1, 0.2));
20 ASSERT_NO_THROW(builder.addNextValue(4, 4, 0.8));
21 ASSERT_NO_THROW(builder.newRowGroup(5));
22 ASSERT_NO_THROW(builder.addNextValue(5, 2, 1.0));
23 ASSERT_NO_THROW(builder.newRowGroup(6));
24 ASSERT_NO_THROW(builder.addNextValue(6, 1, 1.0));
25 ASSERT_NO_THROW(builder.addNextValue(7, 2, 1.0));
26 ASSERT_NO_THROW(builder.addNextValue(8, 3, 1.0));
27 ASSERT_NO_THROW(builder.newRowGroup(9));
28 ASSERT_NO_THROW(builder.addNextValue(9, 4, 1.0));
29 ASSERT_NO_THROW(builder.addNextValue(10, 1, 0.4));
30 ASSERT_NO_THROW(builder.addNextValue(10, 4, 0.6));
31 ASSERT_NO_THROW(builder.addNextValue(11, 3, 1));
33 ASSERT_NO_THROW(matrix = builder.build());
34
35 storm::storage::BitVector subsystem(5, true);
36 subsystem.set(2, false);
37
38 storm::storage::BitVector possibleEcRows(12, true);
39 possibleEcRows.set(3, false);
40 possibleEcRows.set(6, false);
41 possibleEcRows.set(7, false);
42 possibleEcRows.set(8, false);
43 possibleEcRows.set(11, false);
44
45 storm::storage::BitVector allowEmptyRows(5, true);
46 allowEmptyRows.set(1, false);
47 allowEmptyRows.set(4, false);
48
49 auto res = storm::transformer::EndComponentEliminator<double>::transform(matrix, subsystem, possibleEcRows, allowEmptyRows);
50
51 // Expected data
52 // State 0 is a singleton EC that is replaced by state 2
53 // States 1,4 build an EC that will be eliminated and replaced by state 1.
54 // State 2 is not part of the subsystem and thus disregarded
55 // State 3 is the only state that is kept as it is (except of the transition to 2) and will now be represented by state 0
56 storm::storage::SparseMatrixBuilder<double> expectedBuilder(8, 3, 8, true, true, 3);
57 ASSERT_NO_THROW(expectedBuilder.newRowGroup(0));
58 ASSERT_NO_THROW(expectedBuilder.addNextValue(0, 1, 1.0));
59 ASSERT_NO_THROW(expectedBuilder.addNextValue(2, 0, 1.0));
60 ASSERT_NO_THROW(expectedBuilder.newRowGroup(3));
61 ASSERT_NO_THROW(expectedBuilder.addNextValue(3, 0, 0.3));
62 ASSERT_NO_THROW(expectedBuilder.addNextValue(3, 1, 0.7));
63 ASSERT_NO_THROW(expectedBuilder.addNextValue(4, 1, 1.0));
64 ASSERT_NO_THROW(expectedBuilder.addNextValue(5, 0, 1.0));
65 ASSERT_NO_THROW(expectedBuilder.newRowGroup(6));
66 ASSERT_NO_THROW(expectedBuilder.addNextValue(6, 0, 0.4));
67 ASSERT_NO_THROW(expectedBuilder.addNextValue(6, 1, 0.5));
69 ASSERT_NO_THROW(expectedMatrix = expectedBuilder.build());
70 std::vector<uint_fast64_t> expectedNewToOldRowMapping = {6, 7, 8, 2, 3, 11, 1, 0};
71 std::vector<uint_fast64_t> expectedOldToNewStateMapping = {2, 1, std::numeric_limits<uint_fast64_t>::max(), 0, 1};
72
73 // std::cout << "Original matrix:\n" << matrix << "\n\nComputation Result: \n" << res.matrix
74 // << "\n\nexpected Matrix\n"<< expectedMatrix << '\n';
75
76 // Note that there are other possible solutions that yield equivalent matrices / vectors.
77 // In particular, the ordering within the row groups depends on the MEC decomposition implementation.
78 // Hence, we can not do this:
79 // EXPECT_EQ(expectedMatrix, res.matrix);
80 // EXPECT_EQ(expectedNewToOldRowMapping, res.newToOldRowMapping);
81 // EXPECT_EQ(expectedOldToNewStateMapping, res.oldToNewStateMapping);
82
83 // Instead, we try to find a mapping from the actual solution to the expected solution
84 EXPECT_EQ(expectedMatrix.getRowCount(), res.matrix.getRowCount());
85 EXPECT_EQ(expectedMatrix.getRowGroupCount(), res.matrix.getRowGroupCount());
86 EXPECT_EQ(expectedMatrix.getColumnCount(), res.matrix.getColumnCount());
87 EXPECT_EQ(expectedNewToOldRowMapping.size(), res.newToOldRowMapping.size());
88 EXPECT_EQ(expectedOldToNewStateMapping.size(), res.oldToNewStateMapping.size());
89
90 std::vector<uint64_t> actualToExpectedStateMapping(res.matrix.getRowGroupCount());
91 for (uint64_t oldState = 0; oldState < expectedOldToNewStateMapping.size(); ++oldState) {
92 uint64_t expectedNewState = expectedOldToNewStateMapping[oldState];
93 uint64_t actualNewState = res.oldToNewStateMapping[oldState];
94 if (actualNewState < std::numeric_limits<uint_fast64_t>::max()) {
95 ASSERT_LT(expectedNewState, std::numeric_limits<uint_fast64_t>::max()) << " Mapping does not match for oldState " << oldState;
96 actualToExpectedStateMapping[actualNewState] = expectedNewState;
97 } else {
98 ASSERT_EQ(expectedNewState, actualNewState) << " Mapping does not match for oldState " << oldState;
99 }
100 }
101 std::vector<uint64_t> actualToExpectedRowMapping;
102 for (uint64_t actualRow = 0; actualRow < res.matrix.getRowCount(); ++actualRow) {
103 bool found = false;
104 for (uint64_t expectedRow = 0; expectedRow < expectedMatrix.getRowCount(); ++expectedRow) {
105 if (res.newToOldRowMapping[actualRow] == expectedNewToOldRowMapping[expectedRow]) {
106 actualToExpectedRowMapping.push_back(expectedRow);
107 EXPECT_FALSE(found) << "Found multiple matching rows";
108 found = true;
109 }
110 }
111 EXPECT_TRUE(found) << "Could not find matching expected row for result row " << actualRow;
112 }
113
114 for (uint64_t oldState = 0; oldState < expectedOldToNewStateMapping.size(); ++oldState) {
115 uint64_t expectedNewState = expectedOldToNewStateMapping[oldState];
116 uint64_t actualNewState = res.oldToNewStateMapping[oldState];
117 if (actualNewState < std::numeric_limits<uint_fast64_t>::max()) {
118 for (uint64_t actualRow = res.matrix.getRowGroupIndices()[actualNewState]; actualRow < res.matrix.getRowGroupIndices()[actualNewState + 1];
119 ++actualRow) {
120 uint64_t expectedRow = actualToExpectedRowMapping[actualRow];
121 EXPECT_EQ(res.newToOldRowMapping[actualRow], expectedNewToOldRowMapping[expectedRow]);
122 // Check whether the expectedRow belongs to the row group of the expectedState
123 EXPECT_GE(expectedRow, expectedMatrix.getRowGroupIndices()[expectedNewState]);
124 EXPECT_LT(expectedRow, expectedMatrix.getRowGroupIndices()[expectedNewState + 1]);
125 // Check whether the two rows are equal
126 EXPECT_EQ(expectedMatrix.getRow(expectedRow).getNumberOfEntries(), res.matrix.getRow(actualRow).getNumberOfEntries());
127 for (auto const& expectedEntry : expectedMatrix.getRow(expectedRow)) {
128 bool foundEqualEntry = false;
129 for (auto const& actualEntry : res.matrix.getRow(actualRow)) {
130 if (expectedEntry.getValue() == actualEntry.getValue() &&
131 expectedEntry.getColumn() == actualToExpectedStateMapping[actualEntry.getColumn()]) {
132 EXPECT_FALSE(foundEqualEntry) << "Found multiple equal entries.";
133 foundEqualEntry = true;
134 }
135 }
136 EXPECT_TRUE(foundEqualEntry) << "Could not matching entry for expected entry'" << expectedEntry.getValue() << " (row " << expectedRow
137 << ", column " << expectedEntry.getColumn() << "). Was searching at row " << actualRow
138 << " of actual matrix \n"
139 << res.matrix << ".";
140 }
141 }
142 }
143 }
144}
TEST(NeutralECRemover, SimpleModelTest)
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.
index_type getNumberOfEntries() const
Retrieves the number of entries in the rows.
A class that can be used to build a sparse matrix by adding value by value.
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.
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.
const_rows getRow(index_type row) const
Returns an object representing the given row.
index_type getRowGroupCount() const
Returns the number of row groups in the matrix.
index_type getColumnCount() const
Returns the number of columns of the matrix.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
index_type getRowCount() const
Returns the number of rows of the matrix.
static EndComponentEliminatorReturnType transform(storm::storage::SparseMatrix< ValueType > const &originalMatrix, storm::storage::MaximalEndComponentDecomposition< ValueType > ecs, storm::storage::BitVector const &subsystemStates, storm::storage::BitVector const &addSinkRowStates, bool addSelfLoopAtSinkStates=false)