Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
QualitativeAnalysisOnGraphs.cpp
Go to the documentation of this file.
2
10#include "storm/utility/graph.h"
12
13namespace storm {
14namespace analysis {
15
16template<typename ValueType>
20
21template<typename ValueType>
25
26template<typename ValueType>
30
31template<typename ValueType>
33 STORM_LOG_THROW(formula.hasOptimalityType() || formula.hasBound(), storm::exceptions::InvalidPropertyException,
34 "The formula " << formula << " does not specify whether to minimize or maximize.");
35 bool minimizes = (formula.hasOptimalityType() && storm::solver::minimize(formula.getOptimalityType())) ||
37 STORM_LOG_THROW(!minimizes, storm::exceptions::NotImplementedException, "This operation is only supported when maximizing");
38 std::shared_ptr<storm::logic::Formula const> subformula = formula.getSubformula().asSharedPointer();
39 std::shared_ptr<storm::logic::UntilFormula> untilSubformula;
40 // If necessary, convert the subformula to a more general case
41 if (subformula->isEventuallyFormula()) {
42 untilSubformula = std::make_shared<storm::logic::UntilFormula>(storm::logic::Formula::getTrueFormula(),
43 subformula->asEventuallyFormula().getSubformula().asSharedPointer());
44 } else if (subformula->isUntilFormula()) {
45 untilSubformula = std::make_shared<storm::logic::UntilFormula>(subformula->asUntilFormula());
46 }
47 // The vector is sound, but not necessarily complete!
48 return ~storm::utility::graph::performProb1E(pomdp.getTransitionMatrix(), pomdp.getTransitionMatrix().getRowGroupIndices(), pomdp.getBackwardTransitions(),
49 checkPropositionalFormula(untilSubformula->getLeftSubformula()),
50 checkPropositionalFormula(untilSubformula->getRightSubformula()));
51}
52
53template<typename ValueType>
55 // check whether the property is minimizing or maximizing
56 STORM_LOG_THROW(pomdp.isCanonic(), storm::exceptions::IllegalArgumentException, "POMDP needs to be canonic");
57 STORM_LOG_THROW(formula.hasOptimalityType() || formula.hasBound(), storm::exceptions::InvalidPropertyException,
58 "The formula " << formula << " does not specify whether to minimize or maximize.");
59 bool minimizes = (formula.hasOptimalityType() && storm::solver::minimize(formula.getOptimalityType())) ||
61
62 std::shared_ptr<storm::logic::Formula const> subformula = formula.getSubformula().asSharedPointer();
63 // If necessary, convert the subformula to a more general case
64 if (subformula->isEventuallyFormula()) {
65 subformula = std::make_shared<storm::logic::UntilFormula>(storm::logic::Formula::getTrueFormula(),
66 subformula->asEventuallyFormula().getSubformula().asSharedPointer());
67 }
68
69 if (subformula->isUntilFormula()) {
70 if (minimizes && prob0) {
71 return analyseProb0Min(subformula->asUntilFormula());
72 } else if (minimizes && !prob0) {
73 return analyseProb1Min(subformula->asUntilFormula());
74 } else if (!minimizes && prob0) {
75 return analyseProb0Max(subformula->asUntilFormula());
76 } else if (!minimizes && !prob0) {
77 return analyseProb1Max(subformula->asUntilFormula());
78 }
79 }
80 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Prob0or1 analysis is not supported for the property " << formula);
81}
82
83template<typename ValueType>
84storm::storage::BitVector QualitativeAnalysisOnGraphs<ValueType>::analyseProb0Max(storm::logic::UntilFormula const& formula) const {
85 return storm::utility::graph::performProb0A(pomdp.getBackwardTransitions(), checkPropositionalFormula(formula.getLeftSubformula()),
86 checkPropositionalFormula(formula.getRightSubformula()));
87}
88
89template<typename ValueType>
90[[maybe_unused]] storm::storage::BitVector QualitativeAnalysisOnGraphs<ValueType>::analyseProb0Min(storm::logic::UntilFormula const& formula) const {
91 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Prob0 analysis is currently not implemented for minimizing properties.");
92}
93
94template<typename ValueType>
96 storm::storage::BitVector const& good) const {
98 pomdp.getTransitionMatrix(), pomdp.getTransitionMatrix().getRowGroupIndices(), pomdp.getBackwardTransitions(), okay, good);
99 STORM_LOG_TRACE("Prob1A states according to MDP: " << newGoalStates);
100 // Now find a set of observations such that there is (a memoryless) scheduler inducing prob. 1 for each state whose observation is in the set.
102 pomdp.getTransitionMatrix(), pomdp.getTransitionMatrix().getRowGroupIndices(), pomdp.getBackwardTransitions(), okay, newGoalStates);
103 STORM_LOG_TRACE("Prob1E states according to MDP: " << potentialGoalStates);
104
105 storm::storage::BitVector avoidStates = ~potentialGoalStates;
106 storm::storage::BitVector potentialGoalObservations(pomdp.getNrObservations(), true);
107 for (uint64_t observation = 0; observation < pomdp.getNrObservations(); ++observation) {
108 for (uint64_t state : avoidStates) {
109 potentialGoalObservations.set(pomdp.getObservation(state), false);
110 }
111 }
112 // Prob1E observations are observations from which every state is in Prob1E in the underlying MDP
113 STORM_LOG_TRACE("Prob1E observations according to MDP: " << potentialGoalObservations);
114
115 std::vector<std::vector<uint64_t>> statesPerObservation(pomdp.getNrObservations(), std::vector<uint64_t>());
116 for (uint64_t state : potentialGoalStates) {
117 statesPerObservation[pomdp.getObservation(state)].push_back(state);
118 }
119 storm::storage::BitVector singleObservationStates(pomdp.getNumberOfStates());
120 for (uint64_t state = 0; state < pomdp.getNumberOfStates(); ++state) {
121 if (statesPerObservation[pomdp.getObservation(state)].size() == 1) {
122 singleObservationStates.set(state);
123 }
124 }
125
126 storm::storage::BitVector goalStates(pomdp.getNumberOfStates());
127 while (goalStates != newGoalStates) {
128 goalStates = storm::utility::graph::performProb1A(pomdp.getTransitionMatrix(), pomdp.getTransitionMatrix().getRowGroupIndices(),
129 pomdp.getBackwardTransitions(), okay, newGoalStates);
130 goalStates = storm::utility::graph::performProb1E(pomdp.getTransitionMatrix(), pomdp.getTransitionMatrix().getRowGroupIndices(),
131 pomdp.getBackwardTransitions(), okay & singleObservationStates, goalStates);
132 newGoalStates = goalStates;
133 STORM_LOG_TRACE("Prob1A states according to MDP: " << newGoalStates);
134 for (uint64_t observation : potentialGoalObservations) {
135 STORM_LOG_TRACE("Consider observation " << observation);
136 uint64_t actsForObservation = pomdp.getTransitionMatrix().getRowGroupSize(statesPerObservation[observation][0]);
137 // Search whether we find an action that works for this observation.
138 for (uint64_t act = 0; act < actsForObservation; act++) {
139 STORM_LOG_TRACE("Consider action " << act);
140 bool isGoalAction = true; // Assume that this works, then check whether we find a violation.
141 for (uint64_t state : statesPerObservation[observation]) {
142 STORM_LOG_TRACE("Consider state " << state);
143 if (newGoalStates.get(state)) {
144 STORM_LOG_TRACE("Already a goal state " << state);
145
146 // A state is only a goal state if all actions work,
147 // or if all states with the same observation are goal states (and then, it does not matter which action is a goal action).
148 // Notice that this can mean that we wrongly conclude that some action is okay even if this is not the correct action
149 // (but then some other action exists which is okay for all states).
150 continue;
151 }
152 uint64_t row = pomdp.getNondeterministicChoiceIndices()[state] + act;
153 // Check whether all actions lead with a positive probabilty to a goal, and with zero probability to another (non-goal) state.
154 bool hasGoalEntry = false;
155 for (auto const& entry : pomdp.getTransitionMatrix().getRow(row)) {
156 assert(!storm::utility::isZero(entry.getValue()));
157 if (newGoalStates.get(entry.getColumn())) {
158 STORM_LOG_TRACE("Reaches state " << entry.getColumn() << " which is a PROB1e state");
159 hasGoalEntry = true;
160 } else if (pomdp.getObservation(entry.getColumn()) != observation) {
161 STORM_LOG_TRACE("Reaches state " << entry.getColumn() << " which may not be a PROB1e state");
162 isGoalAction = false;
163 break;
164 }
165 }
166 if (!isGoalAction || !hasGoalEntry) {
167 // Action is definitiely not a goal action, no need to check further states.
168 isGoalAction = false;
169 break;
170 }
171 }
172 if (isGoalAction) {
173 for (uint64_t state : statesPerObservation[observation]) {
174 newGoalStates.set(state);
175 }
176 // No need to check other actions.
177 break;
178 }
179 }
180 }
181 }
182 // Notice that the goal states are not observable, i.e., the observations may not be sufficient to decide whether we are in a goal state.
183 return goalStates;
184}
185
186template<typename ValueType>
188 // We consider the states that satisfy the formula with prob.1 under arbitrary schedulers as goal states.
189 return this->analyseProb1Max(checkPropositionalFormula(formula.getLeftSubformula()), checkPropositionalFormula(formula.getRightSubformula()));
190}
191
192template<typename ValueType>
193storm::storage::BitVector QualitativeAnalysisOnGraphs<ValueType>::analyseProb1Min(storm::logic::UntilFormula const& formula) const {
194 return storm::utility::graph::performProb1A(pomdp.getTransitionMatrix(), pomdp.getTransitionMatrix().getRowGroupIndices(), pomdp.getBackwardTransitions(),
195 checkPropositionalFormula(formula.getLeftSubformula()),
196 checkPropositionalFormula(formula.getRightSubformula()));
197}
198
199template<typename ValueType>
200storm::storage::BitVector QualitativeAnalysisOnGraphs<ValueType>::checkPropositionalFormula(storm::logic::Formula const& propositionalFormula) const {
202 STORM_LOG_THROW(mc.canHandle(propositionalFormula), storm::exceptions::InvalidPropertyException,
203 "Propositional model checker can not handle formula " << propositionalFormula);
204 return mc.check(propositionalFormula)->asExplicitQualitativeCheckResult().getTruthValuesVector();
205}
206
207template class QualitativeAnalysisOnGraphs<double>;
208template class QualitativeAnalysisOnGraphs<storm::RationalNumber>;
209} // namespace analysis
210} // namespace storm
storm::storage::BitVector analyseProb0(storm::logic::ProbabilityOperatorFormula const &formula) const
storm::storage::BitVector analyseProbSmaller1(storm::logic::ProbabilityOperatorFormula const &formula) const
storm::storage::BitVector analyseProb1Max(storm::storage::BitVector const &okay, storm::storage::BitVector const &target) const
QualitativeAnalysisOnGraphs(storm::models::sparse::Pomdp< ValueType > const &pomdp)
storm::storage::BitVector analyseProb1(storm::logic::ProbabilityOperatorFormula const &formula) const
Formula const & getRightSubformula() const
Formula const & getLeftSubformula() const
static std::shared_ptr< Formula const > getTrueFormula()
Definition Formula.cpp:213
std::shared_ptr< Formula const > asSharedPointer()
Definition Formula.cpp:571
Bound const & getBound() const
storm::solver::OptimizationDirection const & getOptimalityType() const
Formula const & getSubformula() const
This class represents a partially observable Markov decision process.
Definition Pomdp.h:13
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
bool get(uint64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
#define STORM_LOG_TRACE(message)
Definition logging.h:12
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
bool isLowerBound(ComparisonType t)
bool constexpr minimize(OptimizationDirection d)
storm::storage::BitVector performProb1A(storm::models::sparse::NondeterministicModel< T, RM > const &model, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Computes the sets of states that have probability 1 of satisfying phi until psi under all possible re...
Definition graph.cpp:981
storm::storage::BitVector performProb0A(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Definition graph.cpp:733
storm::storage::BitVector performProb1E(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, boost::optional< storm::storage::BitVector > const &choiceConstraint)
Computes the sets of states that have probability 1 of satisfying phi until psi under at least one po...
Definition graph.cpp:741
bool isZero(ValueType const &a)
Definition constants.cpp:39
ComparisonType comparisonType
Definition Bound.h:18