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