Storm 1.13.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SparseStepBoundedHorizonHelper.cpp
Go to the documentation of this file.
7
9
11#include "storm/utility/graph.h"
14
17
19
20namespace detail {
21template<typename ValueType, typename SolutionType>
23 storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
24 storm::storage::SparseMatrix<ValueType> const& backwardTransitions,
25 storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates,
26 uint64_t const upperBound, ModelCheckerHint const& hint) {
27 if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().getComputeOnlyMaybeStates()) {
28 return hint.template asExplicitModelCheckerHint<ValueType>().getMaybeStates() | psiStates;
29 } else {
30 if (transitionMatrix.hasTrivialRowGrouping()) { // DTMC
31 return storm::utility::graph::performProbGreater0(backwardTransitions, phiStates, psiStates, true, upperBound);
32 } else { // MDP
33 if (goal.minimize()) {
34 return storm::utility::graph::performProbGreater0A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, phiStates,
35 psiStates, true, upperBound);
36 } else {
37 return storm::utility::graph::performProbGreater0E(backwardTransitions, phiStates, psiStates, true, upperBound);
38 }
39 }
40 }
41}
42} // namespace detail
43
44template<typename ValueType, typename SolutionType>
48
49template<typename ValueType, typename SolutionType>
52 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates,
53 uint64_t const lowerBound, uint64_t const upperBound, ModelCheckerHint const& hint) {
54 STORM_LOG_ASSERT(([&]() {
55 uint64_t const numStates = transitionMatrix.getRowGroupCount();
56 std::initializer_list<uint64_t> const r{transitionMatrix.getColumnCount(), backwardTransitions.getRowCount(),
57 backwardTransitions.getColumnCount(), phiStates.size(), psiStates.size()};
58 return std::all_of(r.begin(), r.end(), [&numStates](auto i) { return i == numStates; });
59 }()),
60 "Inconsistent input dimensions.");
61 STORM_LOG_ASSERT(transitionMatrix.hasTrivialRowGrouping() || goal.hasDirection(),
62 "Got a nondeterministic transition matrix but solve goal does not specify a direction.");
63 STORM_LOG_ASSERT(!storm::IsIntervalType<ValueType> || storm::solver::isSet(goal.getUncertaintyResolutionMode()),
64 "Interval transition matrix given, but no uncertainty resolution mode is specified.");
65
66 // Catch trivial case where lowerBound exceeds the upperBound
67 if (lowerBound > upperBound) {
68 return std::vector<SolutionType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<SolutionType>());
69 }
70
71 storm::solver::OptimizationDirection const optimizationDirection =
72 transitionMatrix.hasTrivialRowGrouping() ? OptimizationDirection::Maximize : goal.direction();
73
74 // We identify states that must have probability 0 of reaching the target states to exclude them in the further analysis.
75 storm::storage::BitVector const probGreater0States =
76 detail::computeProbGreater0States<ValueType, SolutionType>(goal, transitionMatrix, backwardTransitions, phiStates, psiStates, upperBound, hint);
77 STORM_LOG_INFO("Preprocessing step-bounded reachability probability computation: "
78 << probGreater0States.getNumberOfSetBits() << " states with probability greater 0. " << psiStates.getNumberOfSetBits() << " target states.");
79
80 // We compute the values using matrix-vector multiplication in two phases.
81 // The first phase computes the values for step epochs upperBound, upperBound-1, upperBound-2, ..., lowerBound.
82 // In that phase, reaching a psiState incurs a probability of 1.
83 // After the first phase, the result vector contains the probabilities for reaching Psi via Phi within upperBound-lowerBound steps.
84 // The second phase computes the values for step epochs lowerBound-1, lowerBound-2, ..., 0.
85 // In the second phase, psiStates are treated as any other state.
86
87 // Allocate the solution vector for the iterations.
88 std::vector<SolutionType> result;
89 result.reserve(transitionMatrix.getRowGroupCount()); // x will later hold the final result for each state.
90
91 // First phase: Apply upperBound-lowerBound many iterations
92 // During this phase, we set probability 1 to all psiStates. The maybeStates are those for which we still need to compute a value.
93 auto const firstPhaseMaybeStates = probGreater0States & ~psiStates;
95 // For interval models, we do not remove non-maybestates for the analysis: We need to keep their incoming transition intervals so that we can pick
96 // valid interval instantiations at predecessors of non-maybestates.
97 // The result vector thus has one entry for each state.
98 // We initialize the result with the probability of reaching psiStates in 0 steps.
100 // Check if we actually need to do any iteration
101 if (upperBound > lowerBound && firstPhaseMaybeStates.getNumberOfSetBits() > 0) {
102 // For the iterations, we clear all outgoing transitions of non-maybe states.
103 auto submatrix = transitionMatrix.filterEntries(transitionMatrix.getRowFilter(firstPhaseMaybeStates));
104 // The `b` vector is used to set a constant value for the non-maybe states. That means it has to hold value 1 for all choices at psiStates.
105 std::vector<ValueType> b;
108 // Perform the iterations for the first phase
109 auto multiplier = storm::solver::MultiplierFactory<ValueType, SolutionType>().create(env, std::move(submatrix));
110 multiplier->repeatedMultiplyAndReduce(env, optimizationDirection, result, &b, upperBound - lowerBound, goal.getUncertaintyResolutionMode());
111 }
112 } else {
113 // For non-interval models, we can consider a proper subsystem consisting only of maybe states. That means, the solution vector only has entries for
114 // each maybeState. Initially, (when doing 0 steps), all maybeStates have value 0
115 result.assign(firstPhaseMaybeStates.getNumberOfSetBits(), storm::utility::zero<SolutionType>());
116 // Check if we actually need to do any iteration
117 if (upperBound > lowerBound && firstPhaseMaybeStates.getNumberOfSetBits() > 0) {
118 // Create the subsystem that only consists of maybe states.
119 auto submatrix = transitionMatrix.getSubmatrix(true, firstPhaseMaybeStates, firstPhaseMaybeStates, false);
120 // The 'b' vector contains for each choice the probabilities to reach psiStates within one step via that choice
121 auto const b = transitionMatrix.getConstrainedRowGroupSumVector(firstPhaseMaybeStates, psiStates);
122 // Perform the iterations for the first phase
123 auto multiplier = storm::solver::MultiplierFactory<ValueType, SolutionType>().create(env, std::move(submatrix));
124 multiplier->repeatedMultiplyAndReduce(env, optimizationDirection, result, &b, upperBound - lowerBound);
125 }
126 }
127
128 // Second phase: Apply lowerBound many iterations
129 auto const secondPhaseMaybeStates = probGreater0States & phiStates;
130 if (lowerBound != 0 && !secondPhaseMaybeStates.empty()) {
131 // In the second phase, we compute values for states those states where the value is not known to be zero.
132 // Note that there might be (psiStates & ~phiStates)-states which have value 1 in the first phase but must get value 0 at the end of this phase.
133 if constexpr (storm::IsIntervalType<ValueType>) {
134 // As in the first phase, we build a submatrix with all states. Now we do not include outgoing transitions for all states that must have value zero
135 auto submatrix = transitionMatrix.filterEntries(transitionMatrix.getRowFilter(secondPhaseMaybeStates));
136 // Perform the iterations for the second phase. We do not need to set a `b` vector, as the non-maybeStates in the second phase must get value zero.
137 // Note that (psiStates & ~phiStates)-states have value 1 right now, but will have value 0 after the first and any subsequent iteration.
138 auto multiplier = storm::solver::MultiplierFactory<ValueType, SolutionType>().create(env, std::move(submatrix));
139 multiplier->repeatedMultiplyAndReduce(env, optimizationDirection, result, nullptr, lowerBound, goal.getUncertaintyResolutionMode());
140 } else {
141 // Create the subsystem that only consists of maybe states.
142 // In contrast to the first phase, we add (psiStates & phiStates) to the set of maybe states.
143 // That means we have to enlarge our solution vector and insert probability 1 for those newly added states, as this is the value of those states
144 // towards the end of the first phase.
145 auto firstPhaseFilter = firstPhaseMaybeStates % secondPhaseMaybeStates; // indicates those states that were already present before
147 // Create a submatrix that only consists of maybeStates for the second phase
148 auto submatrix = transitionMatrix.getSubmatrix(true, secondPhaseMaybeStates, secondPhaseMaybeStates, false);
149 // Perform the iterations for the second phase.
150 auto multiplier = storm::solver::MultiplierFactory<ValueType, SolutionType>().create(env, std::move(submatrix));
151 uint64_t numIterations = lowerBound;
152 // For the very first iteration, we might need to add the probability of reaching a (psiStates & ~phiStates) state in one step.
153 if (auto const excludedPsiStates = psiStates & ~phiStates; !excludedPsiStates.empty()) {
154 auto const b = transitionMatrix.getConstrainedRowGroupSumVector(secondPhaseMaybeStates, excludedPsiStates);
155 multiplier->multiplyAndReduce(env, optimizationDirection, result, &b, result);
156 --numIterations;
157 }
158 multiplier->repeatedMultiplyAndReduce(env, optimizationDirection, result, nullptr, numIterations);
159 // Finally, we blow up the solution vector once more to also incorporate values for the non-maybe states, which all have value zero.
161 }
162 } else {
163 // If there is no second phase, we still need to blow up the solution vector in case it refers to the reduced system
167 }
168 }
169
170 return result;
171}
172
178
179} // namespace storm::modelchecker::helper
This class contains information that might accelerate the model checking process.
std::vector< SolutionType > computeStepBoundedUntilProbabilities(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, uint64_t const lowerBound, uint64_t const upperBound, ModelCheckerHint const &hint=ModelCheckerHint())
Computes the probability of staying in phiStates until reaching psiStates within [lowerBound,...
std::unique_ptr< Multiplier< ValueType, SolutionType > > create(Environment const &env, storm::storage::SparseMatrix< ValueType > const &matrix)
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
bool empty() const
Retrieves whether no bits are set to true in this bit vector.
uint64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
size_t size() const
Retrieves the number of bits this bit vector can store.
A class that holds a possibly non-square matrix in the compressed row storage format.
SparseMatrix getSubmatrix(bool useGroups, storm::storage::BitVector const &rowConstraint, storm::storage::BitVector const &columnConstraint, bool insertDiagonalEntries=false, storm::storage::BitVector const &makeZeroColumns=storm::storage::BitVector()) const
Creates a submatrix of the current matrix by dropping all rows and columns whose bits are not set to ...
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.
bool hasTrivialRowGrouping() const
Retrieves whether the matrix has a trivial row grouping.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
std::vector< value_type > getConstrainedRowGroupSumVector(storm::storage::BitVector const &rowGroupConstraint, storm::storage::BitVector const &columnConstraint) const
Computes a vector whose entries represent the sums of selected columns for all rows in selected row g...
index_type getRowCount() const
Returns the number of rows of the matrix.
storm::storage::BitVector getRowFilter(storm::storage::BitVector const &groupConstraint) const
Returns a bitvector representing the set of rows, with all indices set that correspond to one of the ...
SparseMatrix filterEntries(storm::storage::BitVector const &rowFilter) const
Returns a copy of this matrix that only considers entries in the selected rows.
#define STORM_LOG_INFO(message)
Definition logging.h:24
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
storm::storage::BitVector computeProbGreater0States(storm::solver::SolveGoal< ValueType, SolutionType > const &goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, uint64_t const upperBound, ModelCheckerHint const &hint)
bool isSet(OptimizationDirectionSetting s)
storm::storage::BitVector performProbGreater0(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps)
Performs a backward depth-first search trough the underlying graph structure of the given model to de...
Definition graph.cpp:315
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
storm::storage::BitVector performProbGreater0E(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps)
Computes the sets of states that have probability greater 0 of satisfying phi until psi under at leas...
Definition graph.cpp:673
void setVectorValues(std::vector< T > &vector, storm::storage::BitVector const &positions, std::vector< T > const &values)
Sets the provided values at the provided positions in the given vector.
Definition vector.h:78
void setAllValues(std::vector< T > &vec, storm::storage::BitVector const &positions, T const &positiveValue=storm::utility::one< T >(), T const &negativeValue=storm::utility::zero< T >())
Definition vector.h:53
void blowUpVectorInPlace(std::vector< T > &vector, storm::storage::BitVector const &positions, T const &defaultValue=storm::utility::zero< T >())
Gets as input a vector with size n and a BitVector with size m>=n and exactly n set bits.
Definition vector.h:1101
ValueType zero()
Definition constants.cpp:24
ValueType one()
Definition constants.cpp:19
constexpr bool IsIntervalType
Helper to check if a type is an interval.