Storm
A Modern Probabilistic Model Checker
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DsMpiUpperRewardBoundsComputer.cpp
Go to the documentation of this file.
2
3#include "storm-config.h"
4
6
10
12
16
17namespace storm {
18namespace modelchecker {
19namespace helper {
20
21template<typename ValueType>
23 std::vector<ValueType> const& rewards,
24 std::vector<ValueType> const& oneStepTargetProbabilities)
25 : transitionMatrix(transitionMatrix),
26 originalRewards(rewards),
27 originalOneStepTargetProbabilities(oneStepTargetProbabilities),
28 backwardTransitions(transitionMatrix.transpose()),
29 p(transitionMatrix.getRowGroupCount()),
30 w(transitionMatrix.getRowGroupCount()),
31 rewards(rewards),
32 targetProbabilities(oneStepTargetProbabilities) {
33 // Intentionally left empty.
34}
35
36template<typename ValueType>
38 STORM_LOG_TRACE("Computing upper reward bounds using DS-MPI.");
39 std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
40 sweep();
41 ValueType lambda = computeLambda();
42 STORM_LOG_TRACE("DS-MPI computed lambda as " << lambda << ".");
43
44 // Finally compute the upper bounds for the states.
45 std::vector<ValueType> result(transitionMatrix.getRowGroupCount());
46 auto one = storm::utility::one<ValueType>();
47 for (storm::storage::sparse::state_type state = 0; state < result.size(); ++state) {
48 result[state] = w[state] + (one - p[state]) * lambda;
49 }
50
51#ifndef NDEBUG
52 ValueType max = storm::utility::zero<ValueType>();
53 uint64_t nonZeroCount = 0;
54 for (auto const& e : result) {
55 if (!storm::utility::isZero(e)) {
56 ++nonZeroCount;
57 max = std::max(max, e);
58 }
59 }
60 STORM_LOG_TRACE("DS-MPI computed " << nonZeroCount << " non-zero upper bounds and a maximal bound of " << max << ".");
61#endif
62 std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
63 STORM_LOG_TRACE("Computed upper bounds on rewards in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
64 return result;
65}
66
67template<typename ValueType>
69 ValueType lambda = storm::utility::zero<ValueType>();
70 for (storm::storage::sparse::state_type state = 0; state < transitionMatrix.getRowGroupCount(); ++state) {
71 lambda = std::max(lambda, computeLambdaForChoice(state));
72 }
73 return lambda;
74}
75
76template<typename ValueType>
78 ValueType localLambda = storm::utility::zero<ValueType>();
79 uint64_t state = this->getStateForChoice(choice);
80
81 // Check whether condition (I) or (II) applies.
82 ValueType probSum = originalOneStepTargetProbabilities[choice];
83 for (auto const& e : transitionMatrix.getRow(choice)) {
84 probSum += e.getValue() * p[e.getColumn()];
85 }
86
87 if (p[state] < probSum) {
88 STORM_LOG_TRACE("Condition (I) does apply for state " << state << " as " << p[state] << " < " << probSum << ".");
89 // Condition (I) applies.
90 localLambda = probSum - p[state];
91 ValueType nominator = originalRewards[choice];
92 for (auto const& e : transitionMatrix.getRow(choice)) {
93 nominator += e.getValue() * w[e.getColumn()];
94 }
95 nominator -= w[state];
96 localLambda = nominator / localLambda;
97 } else {
98 STORM_LOG_TRACE("Condition (I) does not apply for state " << state << std::setprecision(30) << " as " << probSum << " <= " << p[state] << ".");
99 // Here, condition (II) automatically applies and as the resulting local lambda is 0, we
100 // don't need to consider it.
101
102#ifndef NDEBUG
103 // Actually check condition (II).
104 ValueType rewardSum = originalRewards[choice];
105 for (auto const& e : transitionMatrix.getRow(choice)) {
106 rewardSum += e.getValue() * w[e.getColumn()];
107 }
108 STORM_LOG_WARN_COND(w[state] >= rewardSum || storm::utility::ConstantsComparator<ValueType>().isEqual(w[state], rewardSum),
109 "Expected condition (II) to hold in state " << state << ", but " << w[state] << " < " << rewardSum << ".");
111 "Expected condition (II) to hold in state " << state << ", but " << probSum << " != " << p[state] << ".");
112#endif
113 }
114
115 return localLambda;
116}
117
118template<typename ValueType>
120 return choice;
121}
122
123template<typename ValueType>
125 public:
127 // Intentionally left empty.
128 }
129
131 ValueType pa = dsmpi.targetProbabilities[a];
132 ValueType pb = dsmpi.targetProbabilities[b];
133 if (pa < pb) {
134 return true;
135 } else if (pa == pb) {
136 return dsmpi.rewards[a] > dsmpi.rewards[b];
137 }
138 return false;
139 }
140
141 private:
143};
144
145template<typename ValueType>
147 // Create a priority queue that allows for easy retrieval of the currently best state.
150
151 // Keep track of visited states.
152 storm::storage::BitVector visited(p.size());
153
154 while (!queue.empty()) {
155 // Get first entry in queue.
156 storm::storage::sparse::state_type currentState = queue.popTop();
157
158 // Mark state as visited.
159 visited.set(currentState);
160
161 // Set weight and probability for the state.
162 w[currentState] = rewards[currentState];
163 p[currentState] = targetProbabilities[currentState];
164
165 for (auto const& e : backwardTransitions.getRow(currentState)) {
166 if (visited.get(e.getColumn())) {
167 continue;
168 }
169
170 // Update reward/probability values.
171 rewards[e.getColumn()] += e.getValue() * w[currentState];
172 targetProbabilities[e.getColumn()] += e.getValue() * p[currentState];
173
174 // Increase priority of element.
175 queue.increase(e.getColumn());
176 }
177 }
178}
179
180template<typename ValueType>
182 std::vector<ValueType> const& rewards,
183 std::vector<ValueType> const& oneStepTargetProbabilities)
184 : DsMpiDtmcUpperRewardBoundsComputer<ValueType>(transitionMatrix, rewards, oneStepTargetProbabilities), policy(transitionMatrix.getRowCount()) {
185 // Create a mapping from choices to states.
186 // Also pick a choice in each state that maximizes the target probability and minimizes the reward.
187 choiceToState.resize(transitionMatrix.getRowCount());
188 for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) {
189 uint64_t choice = transitionMatrix.getRowGroupIndices()[state];
190
191 boost::optional<ValueType> minReward;
192 ValueType maxProb = storm::utility::zero<ValueType>();
193
194 for (uint64_t row = choice, endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row < endRow; ++row) {
195 choiceToState[row] = state;
196
197 if (this->targetProbabilities[row] > maxProb) {
198 maxProb = this->targetProbabilities[row];
199 minReward = this->rewards[row];
200 choice = row;
201 } else if (this->targetProbabilities[row] == maxProb && (!minReward || minReward.get() > this->rewards[row])) {
202 minReward = this->rewards[row];
203 choice = row;
204 }
205 }
206
207 setChoiceInState(state, choice);
208 }
209}
210
211template<typename ValueType>
213 ValueType lambda = storm::utility::zero<ValueType>();
214 for (storm::storage::sparse::state_type state = 0; state < this->transitionMatrix.getRowGroupCount(); ++state) {
215 lambda = std::max(lambda, this->computeLambdaForChoice(this->getChoiceInState(state)));
216 }
217 return lambda;
218}
219
220template<typename ValueType>
221uint64_t DsMpiMdpUpperRewardBoundsComputer<ValueType>::getStateForChoice(uint64_t choice) const {
222 return choiceToState[choice];
223}
224
225template<typename ValueType>
227 public:
229 // Intentionally left empty.
230 }
231
233 uint64_t choiceA = dsmpi.getChoiceInState(a);
234 uint64_t choiceB = dsmpi.getChoiceInState(b);
235
236 ValueType pa = dsmpi.targetProbabilities[choiceA];
237 ValueType pb = dsmpi.targetProbabilities[choiceB];
238 if (pa < pb) {
239 return true;
240 } else if (pa == pb) {
241 return dsmpi.rewards[choiceB] > dsmpi.rewards[choiceB];
242 }
243 return false;
244 }
245
246 private:
248};
249
250template<typename ValueType>
251void DsMpiMdpUpperRewardBoundsComputer<ValueType>::sweep() {
252 // Create a priority queue that allows for easy retrieval of the currently best state.
254 DsMpiMdpPriorityLess<ValueType>(*this));
255
256 // Keep track of visited states.
257 storm::storage::BitVector visited(this->transitionMatrix.getRowGroupCount());
258
259 while (!queue.empty()) {
260 // Get first entry in queue.
261 storm::storage::sparse::state_type currentState = queue.popTop();
262
263 // Mark state as visited.
264 visited.set(currentState);
265
266 // Set weight and probability for the state.
267 uint64_t choiceInCurrentState = this->getChoiceInState(currentState);
268 this->w[currentState] = this->rewards[choiceInCurrentState];
269 this->p[currentState] = this->targetProbabilities[choiceInCurrentState];
270
271 for (auto const& choiceEntry : this->backwardTransitions.getRow(currentState)) {
272 uint64_t predecessor = this->getStateForChoice(choiceEntry.getColumn());
273 if (visited.get(predecessor)) {
274 continue;
275 }
276
277 // Update reward/probability values.
278 this->rewards[choiceEntry.getColumn()] += choiceEntry.getValue() * this->w[currentState];
279 this->targetProbabilities[choiceEntry.getColumn()] += choiceEntry.getValue() * this->p[currentState];
280
281 // If the choice is not the one that is currently taken in the predecessor state, we might need
282 // to update it.
283 uint64_t currentChoiceInPredecessor = this->getChoiceInState(predecessor);
284 if (currentChoiceInPredecessor != choiceEntry.getColumn()) {
285 // Check whether the updates choice now becomes a better choice in the predecessor state.
286 ValueType const& newTargetProbability = this->targetProbabilities[choiceEntry.getColumn()];
287 ValueType const& newReward = this->rewards[choiceEntry.getColumn()];
288 ValueType const& currentTargetProbability = this->targetProbabilities[this->getChoiceInState(predecessor)];
289 ValueType const& currentReward = this->rewards[this->getChoiceInState(predecessor)];
290
291 if (newTargetProbability > currentTargetProbability || (newTargetProbability == currentTargetProbability && newReward < currentReward)) {
292 setChoiceInState(predecessor, choiceEntry.getColumn());
293 }
294 }
295
296 // Notify the priority of a potential increase of the priority of the element.
297 queue.increase(predecessor);
298 }
299 }
300}
301
302template<typename ValueType>
303uint64_t DsMpiMdpUpperRewardBoundsComputer<ValueType>::getChoiceInState(uint64_t state) const {
304 return policy[state];
305}
306
307template<typename ValueType>
308void DsMpiMdpUpperRewardBoundsComputer<ValueType>::setChoiceInState(uint64_t state, uint64_t choice) {
309 policy[state] = choice;
310}
311
312template class DsMpiDtmcUpperRewardBoundsComputer<double>;
313template class DsMpiMdpUpperRewardBoundsComputer<double>;
314
315#ifdef STORM_HAVE_CARL
316template class DsMpiDtmcUpperRewardBoundsComputer<storm::RationalNumber>;
317template class DsMpiMdpUpperRewardBoundsComputer<storm::RationalNumber>;
318#endif
319} // namespace helper
320} // namespace modelchecker
321} // namespace storm
DsMpiDtmcPriorityLess(DsMpiDtmcUpperRewardBoundsComputer< ValueType > const &dsmpi)
bool operator()(storm::storage::sparse::state_type const &a, storm::storage::sparse::state_type const &b)
virtual ValueType computeLambda() const
Computes the lambda used for the estimation.
ValueType computeLambdaForChoice(uint64_t choice) const
Computes the lambda just for the provided choice.
std::vector< ValueType > computeUpperBounds()
Computes upper bounds on the expected rewards.
DsMpiDtmcUpperRewardBoundsComputer(storm::storage::SparseMatrix< ValueType > const &transitionMatrix, std::vector< ValueType > const &rewards, std::vector< ValueType > const &oneStepTargetProbabilities)
Creates an object that can compute upper bounds on the expected rewards for the provided DTMC.
virtual uint64_t getStateForChoice(uint64_t choice) const
Retrieves the state associated with the given choice.
bool operator()(storm::storage::sparse::state_type const &a, storm::storage::sparse::state_type const &b)
DsMpiMdpPriorityLess(DsMpiMdpUpperRewardBoundsComputer< ValueType > const &dsmpi)
DsMpiMdpUpperRewardBoundsComputer(storm::storage::SparseMatrix< ValueType > const &transitionMatrix, std::vector< ValueType > const &rewards, std::vector< ValueType > const &oneStepTargetProbabilities)
Creates an object that can compute upper bounds on the minimal expected rewards for the provided MDP.
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.
A class that holds a possibly non-square matrix in the compressed row storage format.
#define STORM_LOG_TRACE(message)
Definition logging.h:17
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:38
bool isZero(ValueType const &a)
Definition constants.cpp:41
LabParser.cpp.
Definition cli.cpp:18