Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SparseMdpEndComponentInformation.cpp
Go to the documentation of this file.
2
7
10
12
13namespace storm {
14namespace modelchecker {
15namespace helper {
16
17template<typename ValueType>
19 storm::storage::MaximalEndComponentDecomposition<ValueType> const& endComponentDecomposition, storm::storage::BitVector const& maybeStates)
20 : NOT_IN_EC(std::numeric_limits<uint64_t>::max()),
21 eliminatedEndComponents(!endComponentDecomposition.empty()),
22 numberOfMaybeStatesInEc(0),
23 numberOfMaybeStatesNotInEc(0),
24 numberOfEc(endComponentDecomposition.size()) {
25 // (1) Compute how many maybe states there are before each other maybe state.
26 maybeStatesBefore = maybeStates.getNumberOfSetBitsBeforeIndices();
27
28 // (2) Create mapping from maybe states to their MEC. If they are not contained in an MEC, their value
29 // is set to a special constant.
30 maybeStateToEc.resize(maybeStates.getNumberOfSetBits(), NOT_IN_EC);
31 uint64_t mecIndex = 0;
32 for (auto const& mec : endComponentDecomposition) {
33 for (auto const& stateActions : mec) {
34 maybeStateToEc[maybeStatesBefore[stateActions.first]] = mecIndex;
35 ++numberOfMaybeStatesInEc;
36 }
37 ++mecIndex;
38 }
39
40 // (3) Compute number of states not in MECs.
41 numberOfMaybeStatesNotInEc = maybeStateToEc.size() - numberOfMaybeStatesInEc;
42
43 // (4) Compute the number of maybe states that are not in ECs before every maybe state.
44 maybeStatesNotInEcBefore = std::vector<uint64_t>(maybeStateToEc.size());
45
46 uint64_t count = 0;
47 auto resultIt = maybeStatesNotInEcBefore.begin();
48 for (auto const& e : maybeStateToEc) {
49 *resultIt = count;
50 if (e == NOT_IN_EC) {
51 ++count;
52 }
53 ++resultIt;
54 }
55}
56
57template<typename ValueType>
59 return maybeStateToEc[maybeState] != NOT_IN_EC;
60}
61
62template<typename ValueType>
64 return maybeStateToEc[maybeStatesBefore[state]] != NOT_IN_EC;
65}
66
67template<typename ValueType>
69 return maybeStatesNotInEcBefore;
70}
71
72template<typename ValueType>
74 return numberOfMaybeStatesNotInEc;
75}
76
77template<typename ValueType>
79 return maybeStateToEc[maybeStatesBefore[state]];
80}
81
82template<typename ValueType>
84 if (this->isStateInEc(state)) {
85 return numberOfMaybeStatesNotInEc + getEc(state);
86 } else {
87 return maybeStatesNotInEcBefore[maybeStatesBefore[state]];
88 }
89}
90
91template<typename ValueType>
93 return eliminatedEndComponents;
94}
95
96template<typename ValueType>
98 return NOT_IN_EC;
99}
100
101template<typename ValueType>
104 storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& maybeStates, storm::storage::BitVector const* sumColumns,
105 storm::storage::BitVector const* selectedChoices, std::vector<ValueType> const* summand, storm::storage::SparseMatrix<ValueType>& submatrix,
106 std::vector<ValueType>* columnSumVector, std::vector<ValueType>* summandResultVector, bool gatherExitChoices) {
107 SparseMdpEndComponentInformation<ValueType> result(endComponentDecomposition, maybeStates);
108 // TODO: Just like SparseMdpPrctlHelper::computeFixedPointSystemUntilProbabilities, this method must be adapted for intervals.
109 if constexpr (std::is_same_v<ValueType, storm::Interval>) {
110 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException,
111 "We do not support the elimination of end components and the creation of an adequate equation system with interval models.");
112 }
113 // (1) Compute the number of maybe states not in ECs before any other maybe state.
114 std::vector<uint64_t> const& maybeStatesNotInEcBefore = result.getNumberOfMaybeStatesNotInEcBeforeIndices();
115 uint64_t numberOfStates = result.numberOfMaybeStatesNotInEc + result.numberOfEc;
116
117 STORM_LOG_TRACE("Creating " << numberOfStates << " states from " << result.numberOfMaybeStatesNotInEc << " states not in ECs and "
118 << result.numberOfMaybeStatesInEc << " states in " << result.numberOfEc << " ECs.");
119
120 // Prepare builder and vector storage.
121 storm::storage::SparseMatrixBuilder<ValueType> builder(0, numberOfStates, 0, true, true, numberOfStates);
122 STORM_LOG_ASSERT((sumColumns && columnSumVector) || (!sumColumns && !columnSumVector),
123 "Expecting a bit vector for which columns to sum iff there is a column sum result vector.");
124 if (columnSumVector) {
125 // Clearing column sum vector as we do not know the number of choices at this point.
126 columnSumVector->resize(0);
127 }
128 STORM_LOG_ASSERT((summand && summandResultVector) || (!summand && !summandResultVector), "Expecting summand iff there is a summand result vector.");
129 if (summandResultVector) {
130 // Clearing summand result vector as we do not know the number of choices at this point.
131 summandResultVector->resize(0);
132 }
133 std::vector<std::pair<uint64_t, ValueType>> ecValuePairs;
134
135 // (2) Create the parts of the submatrix and vector b that belong to states not contained in ECs.
136 uint64_t currentRow = 0;
137 for (auto state : maybeStates) {
138 if (!result.isStateInEc(state)) {
139 builder.newRowGroup(currentRow);
140 for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row < endRow; ++row) {
141 // If the choices is not in the selected ones, drop it.
142 if (selectedChoices && !selectedChoices->get(row)) {
143 continue;
144 }
145
146 ecValuePairs.clear();
147
148 if (summand) {
149 summandResultVector->emplace_back((*summand)[row]);
150 }
151 if (columnSumVector) {
152 columnSumVector->emplace_back(storm::utility::zero<ValueType>());
153 }
154 for (auto const& e : transitionMatrix.getRow(row)) {
155 if (sumColumns && sumColumns->get(e.getColumn())) {
156 columnSumVector->back() += e.getValue();
157 } else if (maybeStates.get(e.getColumn())) {
158 // If the target state of the transition is not contained in an EC, we can just add the entry.
159 if (!result.isStateInEc(e.getColumn())) {
160 builder.addNextValue(currentRow, maybeStatesNotInEcBefore[result.maybeStatesBefore[e.getColumn()]], e.getValue());
161 } else {
162 // Otherwise, we store the information that the state can go to a certain EC.
163 ecValuePairs.emplace_back(result.getEc(e.getColumn()), e.getValue());
164 }
165 }
166 }
167
168 if (!ecValuePairs.empty()) {
169 std::sort(ecValuePairs.begin(), ecValuePairs.end());
170
171 for (auto const& e : ecValuePairs) {
172 builder.addNextValue(currentRow, result.numberOfMaybeStatesNotInEc + e.first, e.second);
173 }
174 }
175
176 ++currentRow;
177 }
178 }
179 }
180
181 // (3) Create the parts of the submatrix and vector b that belong to states contained in ECs.
182 for (auto const& mec : endComponentDecomposition) {
183 builder.newRowGroup(currentRow);
184 std::vector<uint64_t> exitChoices;
185 for (auto const& stateActions : mec) {
186 uint64_t const& state = stateActions.first;
187 for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row < endRow; ++row) {
188 // If the choice is contained in the MEC, drop it.
189 if (stateActions.second.find(row) != stateActions.second.end()) {
190 continue;
191 }
192
193 // If the choices is not in the selected ones, drop it.
194 if (selectedChoices && !selectedChoices->get(row)) {
195 continue;
196 }
197
198 ecValuePairs.clear();
199
200 if (summand) {
201 summandResultVector->emplace_back((*summand)[row]);
202 }
203 if (columnSumVector) {
204 columnSumVector->emplace_back(storm::utility::zero<ValueType>());
205 }
206 for (auto const& e : transitionMatrix.getRow(row)) {
207 if (sumColumns && sumColumns->get(e.getColumn())) {
208 columnSumVector->back() += e.getValue();
209 } else if (maybeStates.get(e.getColumn())) {
210 // If the target state of the transition is not contained in an EC, we can just add the entry.
211 if (!result.isStateInEc(e.getColumn())) {
212 builder.addNextValue(currentRow, maybeStatesNotInEcBefore[result.maybeStatesBefore[e.getColumn()]], e.getValue());
213 } else {
214 // Otherwise, we store the information that the state can go to a certain EC.
215 ecValuePairs.emplace_back(result.getEc(e.getColumn()), e.getValue());
216 }
217 }
218 }
219
220 if (!ecValuePairs.empty()) {
221 std::sort(ecValuePairs.begin(), ecValuePairs.end());
222
223 for (auto const& e : ecValuePairs) {
224 builder.addNextValue(currentRow, result.getNumberOfMaybeStatesNotInEc() + e.first, e.second);
225 }
226 }
227
228 if (gatherExitChoices) {
229 exitChoices.push_back(row);
230 }
231
232 ++currentRow;
233 }
234 }
235 if (gatherExitChoices) {
236 result.ecToExitChoicesBefore.push_back(std::move(exitChoices));
237 }
238 }
239
240 submatrix = builder.build(currentRow);
241 return result;
242}
243
244template<typename ValueType>
247 storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType>& rhsVector, storm::storage::BitVector const& maybeStates,
248 storm::storage::SparseMatrix<ValueType>& submatrix, std::vector<ValueType>& subvector, bool gatherExitChoices) {
249 SparseMdpEndComponentInformation<ValueType> result(endComponentDecomposition, maybeStates);
250 // TODO: Just like SparseMdpPrctlHelper::computeFixedPointSystemUntilProbabilities, this method must be adapted for intervals.
251 if constexpr (std::is_same_v<ValueType, storm::Interval>) {
252 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException,
253 "We do not support the elimination of end components and the creation of an adequate equation system with interval models.");
254 }
255
256 // (1) Compute the number of maybe states not in ECs before any other maybe state.
257 std::vector<uint64_t> maybeStatesNotInEcBefore = result.getNumberOfMaybeStatesNotInEcBeforeIndices();
258 uint64_t numberOfStates = result.numberOfMaybeStatesNotInEc + result.numberOfEc;
259
260 STORM_LOG_TRACE("Found " << numberOfStates << " states, " << result.numberOfMaybeStatesNotInEc << " not in ECs, " << result.numberOfMaybeStatesInEc
261 << " in ECs and " << result.numberOfEc << " ECs.");
262
263 // Prepare builder and vector storage.
264 storm::storage::SparseMatrixBuilder<ValueType> builder(0, numberOfStates, 0, true, true, numberOfStates);
265 subvector.resize(numberOfStates);
266
267 std::vector<std::pair<uint64_t, ValueType>> ecValuePairs;
268
269 // (2) Create the parts of the submatrix and vector b that belong to states not contained in ECs.
270 uint64_t currentRow = 0;
271 for (auto state : maybeStates) {
272 if (!result.isStateInEc(state)) {
273 builder.newRowGroup(currentRow);
274 for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row < endRow; ++row) {
275 // Copy over the entry of the vector.
276 subvector[currentRow] = rhsVector[row];
277
278 ecValuePairs.clear();
279 for (auto const& e : transitionMatrix.getRow(row)) {
280 if (maybeStates.get(e.getColumn())) {
281 // If the target state of the transition is not contained in an EC, we can just add the entry.
282 if (result.isStateInEc(e.getColumn())) {
283 builder.addNextValue(currentRow, maybeStatesNotInEcBefore[result.maybeStatesBefore[e.getColumn()]], e.getValue());
284 } else {
285 // Otherwise, we store the information that the state can go to a certain EC.
286 ecValuePairs.emplace_back(result.getEc(e.getColumn()), e.getValue());
287 }
288 }
289 }
290
291 if (!ecValuePairs.empty()) {
292 std::sort(ecValuePairs.begin(), ecValuePairs.end());
293
294 for (auto const& e : ecValuePairs) {
295 builder.addNextValue(currentRow, result.numberOfMaybeStatesNotInEc + e.first, e.second);
296 }
297 }
298
299 ++currentRow;
300 }
301 }
302 }
303
304 // (3) Create the parts of the submatrix and vector b that belong to states contained in ECs.
305 for (auto const& mec : endComponentDecomposition) {
306 builder.newRowGroup(currentRow);
307 std::vector<uint64_t> exitChoices;
308 for (auto const& stateActions : mec) {
309 uint64_t const& state = stateActions.first;
310 for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row < endRow; ++row) {
311 // If the choice is contained in the MEC, drop it.
312 if (stateActions.second.find(row) != stateActions.second.end()) {
313 continue;
314 }
315
316 // Copy over the entry of the vector.
317 subvector[currentRow] = rhsVector[row];
318
319 ecValuePairs.clear();
320 for (auto const& e : transitionMatrix.getRow(row)) {
321 if (maybeStates.get(e.getColumn())) {
322 // If the target state of the transition is not contained in an EC, we can just add the entry.
323 if (result.isStateInEc(e.getColumn())) {
324 builder.addNextValue(currentRow, maybeStatesNotInEcBefore[result.maybeStatesBefore[e.getColumn()]], e.getValue());
325 } else {
326 // Otherwise, we store the information that the state can go to a certain EC.
327 ecValuePairs.emplace_back(result.getEc(e.getColumn()), e.getValue());
328 }
329 }
330 }
331
332 if (!ecValuePairs.empty()) {
333 std::sort(ecValuePairs.begin(), ecValuePairs.end());
334
335 for (auto const& e : ecValuePairs) {
336 builder.addNextValue(currentRow, result.getNumberOfMaybeStatesNotInEc() + e.first, e.second);
337 }
338 }
339
340 if (gatherExitChoices) {
341 exitChoices.push_back(row);
342 }
343
344 ++currentRow;
345 }
346 }
347 if (gatherExitChoices) {
348 result.ecToExitChoicesBefore.push_back(std::move(exitChoices));
349 }
350 }
351
352 submatrix = builder.build();
353 return result;
354}
355
356template<typename ValueType>
357void SparseMdpEndComponentInformation<ValueType>::setValues(std::vector<ValueType>& result, storm::storage::BitVector const& maybeStates,
358 std::vector<ValueType> const& fromResult) {
359 // The following assumes that row groups associated to EC states are at the very end.
360 auto notInEcResultIt = fromResult.begin();
361 for (auto state : maybeStates) {
362 if (this->isStateInEc(state)) {
363 STORM_LOG_ASSERT(this->getRowGroupAfterElimination(state) >= this->getNumberOfMaybeStatesNotInEc(),
364 "Expected introduced EC states to be located at the end of the matrix.");
365 result[state] = fromResult[this->getRowGroupAfterElimination(state)];
366 } else {
367 result[state] = *notInEcResultIt;
368 ++notInEcResultIt;
369 }
370 }
371 STORM_LOG_ASSERT(notInEcResultIt == fromResult.begin() + this->getNumberOfMaybeStatesNotInEc(), "Mismatching iterators.");
372}
373
374template<typename ValueType>
375template<typename SolutionType>
377 storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
378 storm::storage::SparseMatrix<ValueType> const& backwardTransitions,
379 std::vector<uint64_t> const& fromResult) {
380 // The following assumes that row groups associated to EC states are at the very end.
381 storm::storage::BitVector maybeStatesWithoutChoice(maybeStates.size(), false);
382 storm::storage::BitVector ecStayChoices(transitionMatrix.getRowCount(), false);
383 auto notInEcResultIt = fromResult.begin();
384 for (auto state : maybeStates) {
385 if (this->isStateInEc(state)) {
386 STORM_LOG_ASSERT(this->getRowGroupAfterElimination(state) >= this->getNumberOfMaybeStatesNotInEc(),
387 "Expected introduced EC states to be located at the end of the matrix.");
388 STORM_LOG_ASSERT(!ecToExitChoicesBefore.empty(), "No EC exit choices available. End Components have probably been build without.");
389 uint64_t ec = getEc(state);
390 auto const& exitChoices = ecToExitChoicesBefore[ec];
391 uint64_t afterEliminationChoice = fromResult[this->getRowGroupAfterElimination(state)];
392 uint64_t beforeEliminationGlobalChoiceIndex = exitChoices[afterEliminationChoice];
393 bool noChoice = true;
394 for (uint64_t globalChoice = transitionMatrix.getRowGroupIndices()[state]; globalChoice < transitionMatrix.getRowGroupIndices()[state + 1];
395 ++globalChoice) {
396 // Is this the selected exit choice?
397 if (globalChoice == beforeEliminationGlobalChoiceIndex) {
398 scheduler.setChoice(beforeEliminationGlobalChoiceIndex - transitionMatrix.getRowGroupIndices()[state], state);
399 noChoice = false;
400 } else {
401 // Check if this is an exit choice
402 if (std::find(exitChoices.begin(), exitChoices.end(), globalChoice) == exitChoices.end()) {
403 ecStayChoices.set(globalChoice, true);
404 }
405 }
406 }
407 maybeStatesWithoutChoice.set(state, noChoice);
408 } else {
409 scheduler.setChoice(*notInEcResultIt, state);
410 ++notInEcResultIt;
411 }
412 }
413
414 STORM_LOG_ASSERT(notInEcResultIt == fromResult.begin() + this->getNumberOfMaybeStatesNotInEc(), "Mismatching iterators.");
415 // The maybeStates without a choice (i.e. those within an end component for which we do not take an exiting choice) shall reach maybeStates with a choice
416 // with probability 1 We have to make sure that choices for non-maybe states are not set
417 auto maybeStatesWithChoice = maybeStates & ~maybeStatesWithoutChoice;
418 storm::utility::graph::computeSchedulerProb1E(maybeStates, transitionMatrix, backwardTransitions, maybeStatesWithoutChoice, maybeStatesWithChoice,
419 scheduler, ecStayChoices);
420}
421
425
427 storm::storage::SparseMatrix<double> const& transitionMatrix,
428 storm::storage::SparseMatrix<double> const& backwardTransitions,
429 std::vector<uint64_t> const& fromResult);
430
434 std::vector<uint64_t> const& fromResult);
435
437 storm::storage::BitVector const& maybeStates,
438 storm::storage::SparseMatrix<storm::Interval> const& transitionMatrix,
439 storm::storage::SparseMatrix<storm::Interval> const& backwardTransitions,
440 std::vector<uint64_t> const& fromResult);
441
442// template class SparseMdpEndComponentInformation<storm::RationalFunction>;
443
444} // namespace helper
445} // namespace modelchecker
446} // namespace storm
uint64_t getRowGroupAfterElimination(uint64_t state) const
Retrieves the row group of the state after end component elimination.
uint64_t getNumberOfMaybeStatesNotInEc() const
Retrieves the total number of maybe states on in ECs.
void setScheduler(storm::storage::Scheduler< SolutionType > &scheduler, storm::storage::BitVector const &maybeStates, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, std::vector< uint64_t > const &fromResult)
uint64_t getEc(uint64_t state) const
Retrieves the EC of the state (result may be NOT_IN_EC).
void setValues(std::vector< ValueType > &result, storm::storage::BitVector const &maybeStates, std::vector< ValueType > const &fromResult)
static SparseMdpEndComponentInformation< ValueType > eliminateEndComponents(storm::storage::MaximalEndComponentDecomposition< ValueType > const &endComponentDecomposition, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::BitVector const &maybeStates, storm::storage::BitVector const *sumColumns, storm::storage::BitVector const *selectedChoices, std::vector< ValueType > const *summand, storm::storage::SparseMatrix< ValueType > &submatrix, std::vector< ValueType > *columnSumVector, std::vector< ValueType > *summandResultVector, bool gatherExitChoices=false)
std::vector< uint64_t > const & getNumberOfMaybeStatesNotInEcBeforeIndices() const
Retrieves for each maybe state the number of maybe states not contained in ECs with an index smaller ...
SparseMdpEndComponentInformation(storm::storage::MaximalEndComponentDecomposition< ValueType > const &endComponentDecomposition, storm::storage::BitVector const &maybeStates)
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:18
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.
std::vector< uint_fast64_t > getNumberOfSetBitsBeforeIndices() const
Retrieves a vector that holds at position i the number of bits set before index i.
bool get(uint_fast64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
This class represents the decomposition of a nondeterministic model into its maximal end components.
This class defines which action is chosen in a particular state of a non-deterministic model.
Definition Scheduler.h:18
void setChoice(SchedulerChoice< ValueType > const &choice, uint_fast64_t modelState, uint_fast64_t memoryState=0)
Sets the choice defined by the scheduler for the given state.
Definition Scheduler.cpp:37
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.
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.
#define STORM_LOG_TRACE(message)
Definition logging.h:17
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
void computeSchedulerProb1E(storm::storage::BitVector const &prob1EStates, storm::storage::SparseMatrix< T > const &transitionMatrix, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, storm::storage::Scheduler< SchedulerValueType > &scheduler, boost::optional< storm::storage::BitVector > const &rowFilter)
Computes a scheduler for the given prob1EStates such that in the induced system the given psiStates a...
Definition graph.cpp:624
LabParser.cpp.
Definition cli.cpp:18