Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SparseMultiObjectiveRewardAnalysis.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4
11#include "storm/utility/graph.h"
14
15namespace storm {
16namespace modelchecker {
17namespace multiobjective {
18namespace preprocessing {
19
20template<typename SparseModelType>
23 ReturnType result;
24 auto backwardTransitions = preprocessorResult.preprocessedModel->getBackwardTransitions();
25
26 setReward0States(result, preprocessorResult, backwardTransitions);
27 checkRewardFiniteness(result, preprocessorResult, backwardTransitions);
28
29 return result;
30}
31
32template<typename SparseModelType>
35 storm::storage::SparseMatrix<ValueType> const& backwardTransitions) {
36 uint_fast64_t stateCount = preprocessorResult.preprocessedModel->getNumberOfStates();
37 auto const& transitions = preprocessorResult.preprocessedModel->getTransitionMatrix();
38 std::vector<uint_fast64_t> const& groupIndices = transitions.getRowGroupIndices();
39 storm::storage::BitVector allStates(stateCount, true);
40
41 // Get the choices without any reward for the various objective types
42 storm::storage::BitVector zeroLraRewardChoices(preprocessorResult.preprocessedModel->getNumberOfChoices(), true);
43 storm::storage::BitVector zeroTotalRewardChoices(preprocessorResult.preprocessedModel->getNumberOfChoices(), true);
44 storm::storage::BitVector zeroCumulativeRewardChoices(preprocessorResult.preprocessedModel->getNumberOfChoices(), true);
45 for (auto const& obj : preprocessorResult.objectives) {
46 if (obj.formula->isRewardOperatorFormula()) {
47 auto const& rewModel = preprocessorResult.preprocessedModel->getRewardModel(obj.formula->asRewardOperatorFormula().getRewardModelName());
48 if (obj.formula->getSubformula().isLongRunAverageRewardFormula()) {
49 zeroLraRewardChoices &= rewModel.getChoicesWithZeroReward(transitions);
50 } else if (obj.formula->getSubformula().isTotalRewardFormula()) {
51 zeroTotalRewardChoices &= rewModel.getChoicesWithZeroReward(transitions);
52 } else {
53 STORM_LOG_WARN_COND(obj.formula->getSubformula().isCumulativeRewardFormula(),
54 "Analyzing subformula " << obj.formula->getSubformula() << " is not supported properly.");
55 zeroCumulativeRewardChoices &= rewModel.getChoicesWithZeroReward(transitions);
56 }
57 }
58 }
59
60 // get the states for which there is a scheduler yielding total reward zero
61 auto statesWithTotalRewardForAllChoices = transitions.getRowGroupFilter(~zeroTotalRewardChoices, true);
62 result.totalReward0EStates = storm::utility::graph::performProbGreater0A(transitions, groupIndices, backwardTransitions, allStates,
63 statesWithTotalRewardForAllChoices, false, 0, zeroTotalRewardChoices);
64 result.totalReward0EStates.complement();
65
66 // Get the states for which all schedulers yield a reward of 0
67 // Starting with LRA objectives
68 auto statesWithoutLraReward = transitions.getRowGroupFilter(zeroLraRewardChoices, true);
69 // Compute Sat(Forall F (Forall G "LRAStatesWithoutReward"))
70 auto forallGloballyStatesWithoutLraReward = storm::utility::graph::performProb0A(backwardTransitions, statesWithoutLraReward, ~statesWithoutLraReward);
71 result.reward0AStates =
72 storm::utility::graph::performProb1A(transitions, groupIndices, backwardTransitions, allStates, forallGloballyStatesWithoutLraReward);
73 // Now also incorporate cumulative and total reward objectives
74 auto statesWithTotalOrCumulativeReward = transitions.getRowGroupFilter(~(zeroTotalRewardChoices & zeroCumulativeRewardChoices), false);
75 result.reward0AStates &= storm::utility::graph::performProb0A(backwardTransitions, allStates, statesWithTotalOrCumulativeReward);
76 assert(result.reward0AStates.isSubsetOf(result.totalReward0EStates));
77}
78
79template<typename SparseModelType>
80void SparseMultiObjectiveRewardAnalysis<SparseModelType>::checkRewardFiniteness(
82 storm::storage::SparseMatrix<ValueType> const& backwardTransitions) {
83 result.rewardFinitenessType = RewardFinitenessType::AllFinite;
84
85 auto const& transitions = preprocessorResult.preprocessedModel->getTransitionMatrix();
86 std::vector<uint_fast64_t> const& groupIndices = transitions.getRowGroupIndices();
87
88 // Gather choices where infinite reward is collected if they are taken infinitely often.
89 // Distinguish between attracting choices, where (for some objective) optimal policies might take that choice infinitely often
90 // and draining choices, where optimal policies should never take that choice infinitely often.
91 storm::storage::BitVector attractingInfRewardChoices(preprocessorResult.preprocessedModel->getNumberOfChoices(), true);
92 storm::storage::BitVector drainingInfRewardChoices(preprocessorResult.preprocessedModel->getNumberOfChoices(), true);
93 for (auto objIndex : preprocessorResult.maybeInfiniteRewardObjectives) {
94 STORM_LOG_ASSERT(preprocessorResult.objectives[objIndex].formula->isRewardOperatorFormula(),
95 "Objective needs to be checked for finite reward but has no reward operator.");
96 auto const& rewModel = preprocessorResult.preprocessedModel->getRewardModel(
97 preprocessorResult.objectives[objIndex].formula->asRewardOperatorFormula().getRewardModelName());
98 auto irrelevantChoices = rewModel.getChoicesWithZeroReward(transitions);
99 // For (upper) reward bounded cumulative reward formulas, we do not need to consider the choices where boundReward is collected.
100 if (preprocessorResult.objectives[objIndex].formula->getSubformula().isCumulativeRewardFormula()) {
101 auto const& timeBoundReference =
102 preprocessorResult.objectives[objIndex].formula->getSubformula().asCumulativeRewardFormula().getTimeBoundReference();
103 // Only reward bounded formulas need a finiteness check
104 assert(timeBoundReference.isRewardBound());
105 auto const& rewModelOfBound = preprocessorResult.preprocessedModel->getRewardModel(timeBoundReference.getRewardName());
106 irrelevantChoices |= ~rewModelOfBound.getChoicesWithZeroReward(transitions);
107 }
108
109 bool const maximizing = storm::solver::maximize(preprocessorResult.objectives[objIndex].formula->getOptimalityType());
110 bool const negativeRewards = rewModel.hasNegativeRewards();
111 bool const positiveRewards = rewModel.hasPositiveRewards();
112 bool const hasMixedSignRewards = negativeRewards && positiveRewards;
113
114 if (hasMixedSignRewards || (maximizing && !negativeRewards) || (!maximizing && !positiveRewards)) {
115 attractingInfRewardChoices &= irrelevantChoices;
116 } else {
117 drainingInfRewardChoices &= irrelevantChoices;
118 }
119 }
120 attractingInfRewardChoices.complement();
121 drainingInfRewardChoices.complement();
122
123 // Check reward finiteness under all schedulers
124 storm::storage::BitVector allStates(preprocessorResult.preprocessedModel->getNumberOfStates(), true);
125 if (storm::utility::graph::checkIfECWithChoiceExists(transitions, backwardTransitions, allStates, attractingInfRewardChoices | drainingInfRewardChoices)) {
126 // Check whether there is a scheduler yielding infinite reward for a maximizing objective
127 if (storm::utility::graph::checkIfECWithChoiceExists(transitions, backwardTransitions, allStates, attractingInfRewardChoices)) {
128 result.rewardFinitenessType = RewardFinitenessType::Infinite;
129 } else {
130 // Check whether there is a scheduler under which all rewards are finite.
131 result.totalRewardLessInfinityEStates =
132 storm::utility::graph::performProb1E(transitions, groupIndices, backwardTransitions, allStates, result.totalReward0EStates);
133 if ((result.totalRewardLessInfinityEStates.get() & preprocessorResult.preprocessedModel->getInitialStates()).empty()) {
134 // There is no scheduler that induces finite reward for the initial state
135 result.rewardFinitenessType = RewardFinitenessType::Infinite;
136 } else {
137 result.rewardFinitenessType = RewardFinitenessType::ExistsParetoFinite;
138 }
139 }
140 } else {
141 result.totalRewardLessInfinityEStates = allStates;
142 }
143}
144
145template<typename SparseModelType>
148 storm::storage::SparseMatrix<ValueType> const& backwardTransitions) {
149 STORM_LOG_INFO_COND(!objective.upperResultBound.is_initialized(),
150 "Tried to find an upper result bound for an objective, but a result bound is already there.");
151
152 if (model.isOfType(storm::models::ModelType::Mdp)) {
153 auto const& transitions = model.getTransitionMatrix();
154
155 if (objective.formula->isRewardOperatorFormula()) {
156 auto const& rewModel = model.getRewardModel(objective.formula->asRewardOperatorFormula().getRewardModelName());
157 auto actionRewards = rewModel.getTotalRewardVector(transitions);
158
159 if (objective.formula->getSubformula().isTotalRewardFormula() || objective.formula->getSubformula().isCumulativeRewardFormula()) {
160 // We have to eliminate ECs here to treat zero-reward ECs
161
162 storm::storage::BitVector allStates(model.getNumberOfStates(), true);
163
164 // Get the set of states from which no reward is reachable
165 auto nonZeroRewardStates = rewModel.getStatesWithZeroReward(transitions);
166 nonZeroRewardStates.complement();
167 auto expRewGreater0EStates = storm::utility::graph::performProbGreater0E(backwardTransitions, allStates, nonZeroRewardStates);
168
169 auto zeroRewardChoices = rewModel.getChoicesWithZeroReward(transitions);
170
171 auto ecElimRes =
172 storm::transformer::EndComponentEliminator<ValueType>::transform(transitions, expRewGreater0EStates, zeroRewardChoices, ~allStates);
173
174 allStates.resize(ecElimRes.matrix.getRowGroupCount());
175 storm::storage::BitVector outStates(allStates.size(), false);
176 std::vector<ValueType> rew0StateProbs;
177 rew0StateProbs.reserve(ecElimRes.matrix.getRowCount());
178 for (uint64_t state = 0; state < allStates.size(); ++state) {
179 for (uint64_t choice = ecElimRes.matrix.getRowGroupIndices()[state]; choice < ecElimRes.matrix.getRowGroupIndices()[state + 1]; ++choice) {
180 // Check whether the choice lead to a state with expRew 0 in the original model
181 bool isOutChoice = false;
182 uint64_t originalModelChoice = ecElimRes.newToOldRowMapping[choice];
183 for (auto const& entry : transitions.getRow(originalModelChoice)) {
184 if (!expRewGreater0EStates.get(entry.getColumn())) {
185 isOutChoice = true;
186 outStates.set(state, true);
187 rew0StateProbs.push_back(storm::utility::one<ValueType>() - ecElimRes.matrix.getRowSum(choice));
188 assert(!storm::utility::isZero(rew0StateProbs.back()));
189 break;
190 }
191 }
192 if (!isOutChoice) {
193 rew0StateProbs.push_back(storm::utility::zero<ValueType>());
194 }
195 }
196 }
197
198 // An upper reward bound can only be computed if it is below infinity
199 if (storm::utility::graph::performProb1A(ecElimRes.matrix, ecElimRes.matrix.getRowGroupIndices(), ecElimRes.matrix.transpose(true), allStates,
200 outStates)
201 .full()) {
202 std::vector<ValueType> rewards;
203 rewards.reserve(ecElimRes.matrix.getRowCount());
204 for (auto row : ecElimRes.newToOldRowMapping) {
205 rewards.push_back(actionRewards[row]);
206 }
207
208 storm::modelchecker::helper::BaierUpperRewardBoundsComputer<ValueType> baier(ecElimRes.matrix, rewards, rew0StateProbs);
209 if (objective.upperResultBound) {
210 objective.upperResultBound = std::min(objective.upperResultBound.get(), baier.computeUpperBound());
211 } else {
212 objective.upperResultBound = baier.computeUpperBound();
213 }
214 }
215 }
216 }
217
218 if (objective.upperResultBound) {
219 STORM_LOG_INFO("Computed upper result bound " << objective.upperResultBound.get() << " for objective " << *objective.formula << ".");
220 } else {
221 STORM_LOG_WARN("Could not compute upper result bound for objective " << *objective.formula);
222 }
223 }
224}
225
228
231} // namespace preprocessing
232} // namespace multiobjective
233} // namespace modelchecker
234} // namespace storm
ValueType computeUpperBound()
Computes an upper bound on the expected rewards.
static ReturnType analyze(storm::modelchecker::multiobjective::preprocessing::SparseMultiObjectivePreprocessorResult< SparseModelType > const &preprocessorResult)
Analyzes the reward objectives of the multi objective query.
static void computeUpperResultBound(SparseModelType const &model, storm::modelchecker::multiobjective::Objective< ValueType > &objective, storm::storage::SparseMatrix< ValueType > const &backwardTransitions)
Tries to finds an upper bound for the expected reward of the objective (assuming it considers an expe...
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
bool full() const
Retrieves whether all bits are set 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.
void resize(uint64_t newLength, bool init=false)
Resizes the bit vector to hold the given new number of bits.
A class that holds a possibly non-square matrix in the compressed row storage format.
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)
#define STORM_LOG_INFO(message)
Definition logging.h:24
#define STORM_LOG_WARN(message)
Definition logging.h:25
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:38
#define STORM_LOG_INFO_COND(cond, message)
Definition macros.h:45
bool constexpr maximize(OptimizationDirection d)
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 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 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
storm::storage::BitVector performProb0A(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Definition graph.cpp:733
bool checkIfECWithChoiceExists(storm::storage::SparseMatrix< T > const &transitionMatrix, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &subsystem, storm::storage::BitVector const &choices)
Checks whether there is an End Component that.
Definition graph.cpp:175
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
boost::optional< ValueType > upperResultBound
Definition Objective.h:28
std::shared_ptr< storm::logic::OperatorFormula const > formula
Definition Objective.h:20