Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
VisitingTimesHelper.cpp
Go to the documentation of this file.
2
10
12
13template<typename ValueType>
16 bool assumeOptimalTransitionProbabilities) {
17 STORM_LOG_ASSERT(mec.size() > 0, "empty mec not expected");
18 auto res = storm::utility::one<ValueType>();
19 if (mec.size() == 1) {
20 return res;
21 }
22 // Whenever s' is reachable from s, there is at least one finite path that visits each state of the mec at most once.
23 // We compute a naive lower bound for the probability of such a single path using the product of the smallest probabilities occurring at each state
24 // (Excluding self-loop probabilities)
25 for (auto const& stateChoices : mec) {
27 auto const& s = stateChoices.first;
28 for (auto const& c : stateChoices.second) {
29 auto row = transitions.getRow(c);
30 if (assumeOptimalTransitionProbabilities) {
31 // Count the number of non-selfloop entries and assume a uniform distribution (which gives us the largest minimal probability)
32 auto numEntries = row.getNumberOfEntries();
33 for (auto const& entry : row) {
34 if (entry.getColumn() > s) {
35 if (entry.getColumn() == s) {
36 --numEntries;
37 }
38 break;
39 }
40 }
41 if (numEntries > 0) {
42 v &= storm::utility::one<ValueType>() / storm::utility::convertNumber<ValueType>(numEntries);
43 }
44 } else {
45 // actually determine the minimal probability
46 for (auto const& entry : row) {
47 if (entry.getColumn() != s && !storm::utility::isZero(entry.getValue())) {
48 v &= entry.getValue();
49 }
50 }
51 }
52 }
53 STORM_LOG_ASSERT(!v.empty(), "self-loop state in non-singleton mec?");
54 res *= *v;
55 }
56 return res;
57}
58
59template<typename ValueType>
62 bool assumeOptimalTransitionProbabilities) {
63 auto const one = storm::utility::one<ValueType>();
64 auto const traversalLowerBound = computeMecTraversalLowerBound(mec, transitions, assumeOptimalTransitionProbabilities);
65 if (assumeOptimalTransitionProbabilities) {
66 // We assume that the probability to go back to the MEC using an exiting choice is zero.
67 return one / traversalLowerBound;
68 } else {
69 // compute the largest probability to go back to the MEC when using an exiting choice
70 storm::utility::Maximum<ValueType> q(storm::utility::zero<ValueType>());
71 for (auto const& stateChoices : mec) {
72 for (auto c : transitions.getRowGroupIndices(stateChoices.first)) {
73 if (stateChoices.second.contains(c)) {
74 continue; // not an exit choice!
75 }
76 auto choiceValue = storm::utility::zero<ValueType>();
77 for (auto const& entry : transitions.getRow(c)) {
78 if (mec.containsState(entry.getColumn())) {
79 choiceValue += entry.getValue();
80 }
81 }
82 q &= choiceValue;
83 }
84 }
85 return one / (traversalLowerBound * (one - *q));
86 }
87}
88
89template<typename ValueType>
91 storm::storage::BitVector const& subsystem, storm::storage::SparseMatrix<ValueType> const& transitions,
92 storm::storage::SparseMatrix<ValueType> const& backwardTransitions) {
93 storm::storage::MaximalEndComponentDecomposition mecs(transitions, backwardTransitions, subsystem);
94 storm::storage::BitVector allStates(subsystem.size(), true);
95 auto quotientData = storm::transformer::EndComponentEliminator<ValueType>::transform(transitions, mecs, subsystem, subsystem);
96 auto notSubsystem = ~subsystem;
97
98 // map collapsed states in the quotient to the value l that is to be multiplied to the transitions of those states
99 std::map<uint64_t, ValueType> collapsedStateToValueMap;
100 for (auto const& mec : mecs) {
101 collapsedStateToValueMap.emplace(quotientData.oldToNewStateMapping.at(mec.begin()->first), computeMecTraversalLowerBound(mec, transitions));
102 }
103
104 // Create a modified quotient with scaled transitions
105 storm::storage::SparseMatrixBuilder<ValueType> modifiedQuotientBuilder(quotientData.matrix.getRowCount(), quotientData.matrix.getColumnCount(), 0, true,
106 true, quotientData.matrix.getRowGroupCount());
107 std::vector<ValueType> toSinkProbabilities;
108 toSinkProbabilities.reserve(quotientData.matrix.getRowGroupCount());
109 for (uint64_t state = 0; state < quotientData.matrix.getRowGroupCount(); ++state) {
110 modifiedQuotientBuilder.newRowGroup(quotientData.matrix.getRowGroupIndices()[state]);
111 ValueType scalingFactor = storm::utility::one<ValueType>();
112 if (auto findRes = collapsedStateToValueMap.find(state); findRes != collapsedStateToValueMap.end()) {
113 scalingFactor = findRes->second;
114 }
115 for (auto const choice : quotientData.matrix.getRowGroupIndices(state)) {
116 if (!storm::utility::isOne(scalingFactor)) {
117 modifiedQuotientBuilder.addDiagonalEntry(choice, storm::utility::one<ValueType>() - scalingFactor);
118 }
119 for (auto const& entry : quotientData.matrix.getRow(choice)) {
120 modifiedQuotientBuilder.addNextValue(choice, entry.getColumn(), scalingFactor * entry.getValue());
121 }
122 if (quotientData.sinkRows.get(choice)) {
123 toSinkProbabilities.push_back(scalingFactor);
124 } else {
125 toSinkProbabilities.push_back(scalingFactor * transitions.getConstrainedRowSum(quotientData.newToOldRowMapping.at(choice), notSubsystem));
126 }
127 }
128 }
129 auto modifiedQuotient = modifiedQuotientBuilder.build();
130 STORM_LOG_ASSERT(modifiedQuotient.getRowCount() == toSinkProbabilities.size(), "Unexpected row count");
131
132 // compute upper visiting time bounds
133 auto quotientUpperBounds =
135
136 std::vector<ValueType> result;
137 result.reserve(subsystem.size());
138 for (uint64_t state = 0; state < subsystem.size(); ++state) {
139 auto const& quotientState = quotientData.oldToNewStateMapping[state];
140 if (quotientState < quotientData.matrix.getRowGroupCount()) {
141 result.push_back(quotientUpperBounds.at(quotientState));
142 } else {
143 result.push_back(-storm::utility::one<ValueType>()); // not in given subsystem;
144 }
145 }
146 return result;
147}
148
149template class VisitingTimesHelper<double>;
151
152} // namespace storm::modelchecker::multiobjective
static std::vector< ValueType > computeUpperBoundOnExpectedVisitingTimes(storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, std::vector< ValueType > const &oneStepTargetProbabilities)
Computes for each state an upper bound for the maximal expected times each state is visited.
Provides helper functions for computing bounds on the expected visiting times.
static ValueType computeMecVisitsUpperBound(storm::storage::MaximalEndComponent const &mec, storm::storage::SparseMatrix< ValueType > const &transitions, bool assumeOptimalTransitionProbabilities=false)
Computes an upper bound for the largest finite expected number of times a state s in the given MEC is...
static std::vector< ValueType > computeUpperBoundsOnExpectedVisitingTimes(storm::storage::BitVector const &subsystem, storm::storage::SparseMatrix< ValueType > const &transitions, storm::storage::SparseMatrix< ValueType > const &backwardTransitions)
Computes for each state in the given subsystem an upper bound for the maximal finite expected number ...
static ValueType computeMecTraversalLowerBound(storm::storage::MaximalEndComponent const &mec, storm::storage::SparseMatrix< ValueType > const &transitions, bool assumeOptimalTransitionProbabilities=false)
Computes value l in (0,1] such that for any pair of distinct states s,s' and deterministic,...
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:18
size_t size() const
Retrieves the number of bits this bit vector can store.
This class represents the decomposition of a nondeterministic model into its maximal end components.
This class represents a maximal end-component of a nondeterministic model.
bool containsState(uint_fast64_t state) const
Retrieves whether the given state is contained in this MEC.
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.
void addDiagonalEntry(index_type row, ValueType const &value)
Makes sure that a diagonal entry will be inserted at the given row.
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.
value_type getConstrainedRowSum(index_type row, storm::storage::BitVector const &columns) const
Sums the entries in the given row and columns.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this 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)
Stores and manages an extremal (maximal or minimal) value.
Definition Extremum.h:15
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
bool isOne(ValueType const &a)
Definition constants.cpp:36
bool isZero(ValueType const &a)
Definition constants.cpp:41