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