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