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