Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
EndComponentEliminator.h
Go to the documentation of this file.
1#ifndef STORM_TRANSFORMER_ENDCOMPONENTELIMINATOR_H
2#define STORM_TRANSFORMER_ENDCOMPONENTELIMINATOR_H
3
8
9namespace storm {
10namespace transformer {
11
12template<typename ValueType>
14 public:
16 // The resulting matrix
18 // Index mapping that gives for each row of the resulting matrix the corresponding row in the original matrix.
19 // For the sink rows added to EC states, an arbitrary row of the original matrix that stays inside the EC is given.
20 std::vector<uint_fast64_t> newToOldRowMapping;
21 // Gives for each state (=rowGroup) of the original matrix the corresponding state in the resulting matrix.
22 // States of a removed ECs are mapped to the state that substitutes the EC.
23 // If the given state does not exist in the result (i.e., it is not in the provided subsystem), the returned value will be
24 // std::numeric_limits<uint_fast64_t>::max(), i.e., an invalid index.
25 std::vector<uint_fast64_t> oldToNewStateMapping;
26 // Indicates the rows that represent "staying" in the eliminated EC for ever
28 };
29
30 /*
31 * Substitutes the given end components by a single state.
32 *
33 *
34 * Only states in the given subsystem are kept. Transitions leading to a state outside of the subsystem will be
35 * removed (but the corresponding row is kept, possibly yielding empty rows).
36 * The given ECs all have to lie within the provided subsystem.
37 *
38 * For each such EC (that is not contained in another EC), we add a new state and redirect all incoming and outgoing
39 * transitions of the EC to (and from) this state.
40 * If addSinkRowStates is true for at least one state of an eliminated EC, a row is added to the new state (representing the choice to stay at the EC
41 * forever). If addSelfLoopAtSinkStates is true, such rows get a selfloop (with value 1). Otherwise, the row remains empty.
42 */
45 storm::storage::BitVector const& subsystemStates, storm::storage::BitVector const& addSinkRowStates,
46 bool addSelfLoopAtSinkStates = false) {
47 // further shrink the set of kept states by removing all states that are part of an EC
48 storm::storage::BitVector keptStates = subsystemStates;
49 for (auto const& ec : ecs) {
50 for (auto const& stateActionsPair : ec) {
51 keptStates.set(stateActionsPair.first, false);
52 }
53 }
54 STORM_LOG_DEBUG("Found " << ecs.size() << " end components to eliminate. Keeping " << keptStates.getNumberOfSetBits() << " of " << keptStates.size()
55 << " original states plus " << ecs.size() << "new end component states.");
56
58 std::vector<uint_fast64_t> newRowGroupIndices;
59 result.oldToNewStateMapping = std::vector<uint_fast64_t>(originalMatrix.getRowGroupCount(), std::numeric_limits<uint_fast64_t>::max());
60 result.sinkRows =
61 storm::storage::BitVector(originalMatrix.getRowCount(), false); // will be resized as soon as the rowCount of the resulting matrix is known
62
63 for (auto keptState : keptStates) {
64 result.oldToNewStateMapping[keptState] = newRowGroupIndices.size(); // i.e., the current number of processed states
65 newRowGroupIndices.push_back(result.newToOldRowMapping.size()); // i.e., the current number of processed rows
66 for (uint_fast64_t oldRow = originalMatrix.getRowGroupIndices()[keptState]; oldRow < originalMatrix.getRowGroupIndices()[keptState + 1]; ++oldRow) {
67 result.newToOldRowMapping.push_back(oldRow);
68 }
69 }
70 for (auto const& ec : ecs) {
71 newRowGroupIndices.push_back(result.newToOldRowMapping.size());
72 bool ecGetsSinkRow = false;
73 for (auto const& stateActionsPair : ec) {
74 result.oldToNewStateMapping[stateActionsPair.first] = newRowGroupIndices.size() - 1;
75 for (uint_fast64_t row = originalMatrix.getRowGroupIndices()[stateActionsPair.first];
76 row < originalMatrix.getRowGroupIndices()[stateActionsPair.first + 1]; ++row) {
77 if (stateActionsPair.second.find(row) == stateActionsPair.second.end()) {
78 result.newToOldRowMapping.push_back(row);
79 }
80 }
81 ecGetsSinkRow |= addSinkRowStates.get(stateActionsPair.first);
82 }
83 if (ecGetsSinkRow) {
84 STORM_LOG_ASSERT(result.newToOldRowMapping.size() < originalMatrix.getRowCount(),
85 "Didn't expect to see more rows in the reduced matrix than in the original one.");
86 result.sinkRows.set(result.newToOldRowMapping.size(), true);
87 result.newToOldRowMapping.push_back(*ec.begin()->second.begin());
88 }
89 }
90 newRowGroupIndices.push_back(result.newToOldRowMapping.size());
91 result.sinkRows.resize(result.newToOldRowMapping.size());
92
93 result.matrix = buildTransformedMatrix(originalMatrix, newRowGroupIndices, result.newToOldRowMapping, result.oldToNewStateMapping, result.sinkRows,
94 addSelfLoopAtSinkStates);
95 STORM_LOG_DEBUG("EndComponentEliminator is done. Resulting matrix has " << result.matrix.getRowGroupCount() << " row groups.");
96 return result;
97 }
98
99 /*
100 * Identifies end components and substitutes them by a single state.
101 *
102 * Only states in the given subsystem are kept. Transitions leading to a state outside of the subsystem will be
103 * removed (but the corresponding row is kept, possibly yielding empty rows).
104 * The ECs are then identified on the subsystem.
105 *
106 * Only ECs for which possibleECRows is true for all choices are considered.
107 * Furthermore, the rows that contain a transition leading outside of the subsystem are not considered for an EC.
108 *
109 * For each such EC (that is not contained in another EC), we add a new state and redirect all incoming and outgoing
110 * transitions of the EC to (and from) this state.
111 * If addSinkRowStates is true for at least one state of an eliminated EC, a row is added to the new state (representing the choice to stay at the EC
112 * forever). If addSelfLoopAtSinkStates is true, such rows get a selfloop (with value 1). Otherwise, the row remains empty.
113 */
115 storm::storage::BitVector const& subsystemStates, storm::storage::BitVector const& possibleECRows,
116 storm::storage::BitVector const& addSinkRowStates, bool addSelfLoopAtSinkStates = false) {
117 STORM_LOG_DEBUG("Invoked EndComponentEliminator on matrix with " << originalMatrix.getRowGroupCount() << " row groups and "
118 << subsystemStates.getNumberOfSetBits() << " subsystem states.");
119
120 // storm::storage::MaximalEndComponentDecomposition<ValueType> ecs = computeECs(originalMatrix, possibleECRows, subsystemStates);
121 storm::storage::MaximalEndComponentDecomposition<ValueType> ecs(originalMatrix, originalMatrix.transpose(true), subsystemStates, possibleECRows);
122 return transform(originalMatrix, ecs, subsystemStates, addSinkRowStates, addSelfLoopAtSinkStates);
123 }
124
125 private:
127 storm::storage::BitVector const& possibleECRows,
128 storm::storage::BitVector const& subsystemStates) {
129 // Get an auxiliary matrix to identify the correct end components w.r.t. the possible EC rows and the subsystem.
130 // This is done by redirecting choices that can never be part of an EC to a sink state.
131 // Such choices are either non-possible EC rows or rows that lead to a state that is not in the subsystem.
132 uint_fast64_t sinkState = originalMatrix.getRowGroupCount();
133 storm::storage::SparseMatrixBuilder<ValueType> builder(originalMatrix.getRowCount() + 1, originalMatrix.getColumnCount() + 1,
134 originalMatrix.getEntryCount() + 1, false, true, originalMatrix.getRowGroupCount() + 1);
135 uint_fast64_t row = 0;
136 for (uint_fast64_t rowGroup = 0; rowGroup < originalMatrix.getRowGroupCount(); ++rowGroup) {
137 builder.newRowGroup(row);
138 for (; row < originalMatrix.getRowGroupIndices()[rowGroup + 1]; ++row) {
139 bool keepRow = possibleECRows.get(row);
140 if (keepRow) { // Also check whether all successors are in the subsystem
141 for (auto const& entry : originalMatrix.getRow(row)) {
142 keepRow &= subsystemStates.get(entry.getColumn());
143 }
144 }
145 if (keepRow) {
146 for (auto const& entry : originalMatrix.getRow(row)) {
147 builder.addNextValue(row, entry.getColumn(), entry.getValue());
148 }
149 } else {
150 builder.addNextValue(row, sinkState, storm::utility::one<ValueType>());
151 }
152 }
153 }
154 builder.newRowGroup(row);
155 builder.addNextValue(row, sinkState, storm::utility::one<ValueType>());
157 builder.build(originalMatrix.getRowCount() + 1, originalMatrix.getColumnCount() + 1, originalMatrix.getRowGroupCount() + 1);
158 storm::storage::SparseMatrix<ValueType> backwardsTransitions = auxiliaryMatrix.transpose(true);
159 storm::storage::BitVector sinkStateAsBitVector(auxiliaryMatrix.getRowGroupCount(), false);
160 sinkStateAsBitVector.set(sinkState);
161 storm::storage::BitVector auxSubsystemStates = subsystemStates;
162 auxSubsystemStates.resize(subsystemStates.size() + 1, true);
163 // The states for which sinkState is reachable under every scheduler can not be part of an EC
164 auxSubsystemStates &= ~(storm::utility::graph::performProbGreater0A(auxiliaryMatrix, auxiliaryMatrix.getRowGroupIndices(), backwardsTransitions,
165 auxSubsystemStates, sinkStateAsBitVector));
166 return storm::storage::MaximalEndComponentDecomposition<ValueType>(auxiliaryMatrix, backwardsTransitions, auxSubsystemStates);
167 }
168
169 static storm::storage::SparseMatrix<ValueType> buildTransformedMatrix(storm::storage::SparseMatrix<ValueType> const& originalMatrix,
170 std::vector<uint_fast64_t> const& newRowGroupIndices,
171 std::vector<uint_fast64_t> const& newToOldRowMapping,
172 std::vector<uint_fast64_t> const& oldToNewStateMapping,
173 storm::storage::BitVector const& sinkRows, bool addSelfLoopAtSinkStates) {
174 uint_fast64_t numRowGroups = newRowGroupIndices.size() - 1;
175 uint_fast64_t newRow = 0;
176 storm::storage::SparseMatrixBuilder<ValueType> builder(newToOldRowMapping.size(), numRowGroups, originalMatrix.getEntryCount(), false, true,
177 numRowGroups);
178 for (uint_fast64_t newRowGroup = 0; newRowGroup < numRowGroups; ++newRowGroup) {
179 builder.newRowGroup(newRow);
180 for (; newRow < newRowGroupIndices[newRowGroup + 1]; ++newRow) {
181 if (sinkRows.get(newRow)) {
182 if (addSelfLoopAtSinkStates) {
183 builder.addNextValue(newRow, newRowGroup, storm::utility::one<ValueType>());
184 }
185 } else {
186 // Make sure that the entries for this row are inserted in the right order.
187 // Also, transitions to the same EC need to be merged and transitions to states that are erased need to be ignored
188 std::map<uint_fast64_t, ValueType> sortedEntries;
189 for (auto const& entry : originalMatrix.getRow(newToOldRowMapping[newRow])) {
190 uint_fast64_t newColumn = oldToNewStateMapping[entry.getColumn()];
191 if (newColumn < numRowGroups) {
192 auto insertResult = sortedEntries.insert(std::make_pair(newColumn, entry.getValue()));
193 if (!insertResult.second) {
194 // We have already seen an entry with this column. ==> merge transitions
195 insertResult.first->second += entry.getValue();
196 }
197 }
198 }
199 for (auto const& sortedEntry : sortedEntries) {
200 builder.addNextValue(newRow, sortedEntry.first, sortedEntry.second);
201 }
202 }
203 }
204 }
205 return builder.build(newToOldRowMapping.size(), numRowGroups, numRowGroups);
206 }
207};
208} // namespace transformer
209} // namespace storm
210#endif // STORM_TRANSFORMER_ENDCOMPONENTREMOVER_H
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:18
void resize(uint_fast64_t newLength, bool init=false)
Resizes the bit vector to hold the given new number of bits.
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 getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
bool get(uint_fast64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
std::size_t size() const
Retrieves the number of blocks of this decomposition.
This class represents the decomposition of a nondeterministic model into its maximal end components.
A class that can be used to build a sparse matrix by adding value by value.
A class that holds a possibly non-square matrix in the compressed row storage format.
index_type getEntryCount() const
Returns the number of entries in the matrix.
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.
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.
static EndComponentEliminatorReturnType transform(storm::storage::SparseMatrix< ValueType > const &originalMatrix, storm::storage::BitVector const &subsystemStates, storm::storage::BitVector const &possibleECRows, storm::storage::BitVector const &addSinkRowStates, bool addSelfLoopAtSinkStates=false)
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)
#define STORM_LOG_DEBUG(message)
Definition logging.h:23
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
storm::storage::BitVector performProbGreater0A(storm::storage::SparseMatrix< T > const &transitionMatrix, std::vector< uint_fast64_t > const &nondeterministicChoiceIndices, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps, boost::optional< storm::storage::BitVector > const &choiceConstraint)
Computes the sets of states that have probability greater 0 of satisfying phi until psi under any pos...
Definition graph.cpp:857
LabParser.cpp.
Definition cli.cpp:18