Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
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 // The following is a bit of a hack but I'd prefer not getting the settings into this part of the code for such a simple check.
109 storm::utility::ConstantsComparator<ValueType> cc(storm::utility::convertNumber<ValueType>(0.0001));
110 STORM_LOG_WARN_COND(w[state] >= rewardSum || cc.isEqual(w[state], rewardSum),
111 "Expected condition (II) to hold in state " << state << ", but " << w[state] << " < " << rewardSum << ".");
112 STORM_LOG_WARN_COND(cc.isEqual(probSum, p[state]),
113 "Expected condition (II) to hold in state " << state << ", but " << probSum << " != " << p[state] << ".");
114#endif
115 }
116
117 return localLambda;
118}
119
120template<typename ValueType>
122 return choice;
123}
124
125template<typename ValueType>
127 public:
129 // Intentionally left empty.
130 }
131
133 ValueType pa = dsmpi.targetProbabilities[a];
134 ValueType pb = dsmpi.targetProbabilities[b];
135 if (pa < pb) {
136 return true;
137 } else if (pa == pb) {
138 return dsmpi.rewards[a] > dsmpi.rewards[b];
139 }
140 return false;
141 }
142
143 private:
145};
146
147template<typename ValueType>
149 // Create a priority queue that allows for easy retrieval of the currently best state.
152
153 // Keep track of visited states.
154 storm::storage::BitVector visited(p.size());
155
156 while (!queue.empty()) {
157 // Get first entry in queue.
158 storm::storage::sparse::state_type currentState = queue.popTop();
159
160 // Mark state as visited.
161 visited.set(currentState);
162
163 // Set weight and probability for the state.
164 w[currentState] = rewards[currentState];
165 p[currentState] = targetProbabilities[currentState];
166
167 for (auto const& e : backwardTransitions.getRow(currentState)) {
168 if (visited.get(e.getColumn())) {
169 continue;
170 }
171
172 // Update reward/probability values.
173 rewards[e.getColumn()] += e.getValue() * w[currentState];
174 targetProbabilities[e.getColumn()] += e.getValue() * p[currentState];
175
176 // Increase priority of element.
177 queue.increase(e.getColumn());
178 }
179 }
180}
181
182template<typename ValueType>
184 std::vector<ValueType> const& rewards,
185 std::vector<ValueType> const& oneStepTargetProbabilities)
186 : DsMpiDtmcUpperRewardBoundsComputer<ValueType>(transitionMatrix, rewards, oneStepTargetProbabilities), policy(transitionMatrix.getRowCount()) {
187 // Create a mapping from choices to states.
188 // Also pick a choice in each state that maximizes the target probability and minimizes the reward.
189 choiceToState.resize(transitionMatrix.getRowCount());
190 for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) {
191 uint64_t choice = transitionMatrix.getRowGroupIndices()[state];
192
193 boost::optional<ValueType> minReward;
194 ValueType maxProb = storm::utility::zero<ValueType>();
195
196 for (uint64_t row = choice, endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row < endRow; ++row) {
197 choiceToState[row] = state;
198
199 if (this->targetProbabilities[row] > maxProb) {
200 maxProb = this->targetProbabilities[row];
201 minReward = this->rewards[row];
202 choice = row;
203 } else if (this->targetProbabilities[row] == maxProb && (!minReward || minReward.get() > this->rewards[row])) {
204 minReward = this->rewards[row];
205 choice = row;
206 }
207 }
208
209 setChoiceInState(state, choice);
210 }
211}
212
213template<typename ValueType>
215 ValueType lambda = storm::utility::zero<ValueType>();
216 for (storm::storage::sparse::state_type state = 0; state < this->transitionMatrix.getRowGroupCount(); ++state) {
217 lambda = std::max(lambda, this->computeLambdaForChoice(this->getChoiceInState(state)));
218 }
219 return lambda;
220}
221
222template<typename ValueType>
223uint64_t DsMpiMdpUpperRewardBoundsComputer<ValueType>::getStateForChoice(uint64_t choice) const {
224 return choiceToState[choice];
225}
226
227template<typename ValueType>
229 public:
231 // Intentionally left empty.
232 }
233
235 uint64_t choiceA = dsmpi.getChoiceInState(a);
236 uint64_t choiceB = dsmpi.getChoiceInState(b);
237
238 ValueType pa = dsmpi.targetProbabilities[choiceA];
239 ValueType pb = dsmpi.targetProbabilities[choiceB];
240 if (pa < pb) {
241 return true;
242 } else if (pa == pb) {
243 return dsmpi.rewards[choiceB] > dsmpi.rewards[choiceB];
244 }
245 return false;
246 }
247
248 private:
250};
251
252template<typename ValueType>
253void DsMpiMdpUpperRewardBoundsComputer<ValueType>::sweep() {
254 // Create a priority queue that allows for easy retrieval of the currently best state.
256 DsMpiMdpPriorityLess<ValueType>(*this));
257
258 // Keep track of visited states.
259 storm::storage::BitVector visited(this->transitionMatrix.getRowGroupCount());
260
261 while (!queue.empty()) {
262 // Get first entry in queue.
263 storm::storage::sparse::state_type currentState = queue.popTop();
264
265 // Mark state as visited.
266 visited.set(currentState);
267
268 // Set weight and probability for the state.
269 uint64_t choiceInCurrentState = this->getChoiceInState(currentState);
270 this->w[currentState] = this->rewards[choiceInCurrentState];
271 this->p[currentState] = this->targetProbabilities[choiceInCurrentState];
272
273 for (auto const& choiceEntry : this->backwardTransitions.getRow(currentState)) {
274 uint64_t predecessor = this->getStateForChoice(choiceEntry.getColumn());
275 if (visited.get(predecessor)) {
276 continue;
277 }
278
279 // Update reward/probability values.
280 this->rewards[choiceEntry.getColumn()] += choiceEntry.getValue() * this->w[currentState];
281 this->targetProbabilities[choiceEntry.getColumn()] += choiceEntry.getValue() * this->p[currentState];
282
283 // If the choice is not the one that is currently taken in the predecessor state, we might need
284 // to update it.
285 uint64_t currentChoiceInPredecessor = this->getChoiceInState(predecessor);
286 if (currentChoiceInPredecessor != choiceEntry.getColumn()) {
287 // Check whether the updates choice now becomes a better choice in the predecessor state.
288 ValueType const& newTargetProbability = this->targetProbabilities[choiceEntry.getColumn()];
289 ValueType const& newReward = this->rewards[choiceEntry.getColumn()];
290 ValueType const& currentTargetProbability = this->targetProbabilities[this->getChoiceInState(predecessor)];
291 ValueType const& currentReward = this->rewards[this->getChoiceInState(predecessor)];
292
293 if (newTargetProbability > currentTargetProbability || (newTargetProbability == currentTargetProbability && newReward < currentReward)) {
294 setChoiceInState(predecessor, choiceEntry.getColumn());
295 }
296 }
297
298 // Notify the priority of a potential increase of the priority of the element.
299 queue.increase(predecessor);
300 }
301 }
302}
303
304template<typename ValueType>
305uint64_t DsMpiMdpUpperRewardBoundsComputer<ValueType>::getChoiceInState(uint64_t state) const {
306 return policy[state];
307}
308
309template<typename ValueType>
310void DsMpiMdpUpperRewardBoundsComputer<ValueType>::setChoiceInState(uint64_t state, uint64_t choice) {
311 policy[state] = choice;
312}
313
314template class DsMpiDtmcUpperRewardBoundsComputer<double>;
315template class DsMpiMdpUpperRewardBoundsComputer<double>;
316
317#ifdef STORM_HAVE_CARL
318template class DsMpiDtmcUpperRewardBoundsComputer<storm::RationalNumber>;
319template class DsMpiMdpUpperRewardBoundsComputer<storm::RationalNumber>;
320#endif
321} // namespace helper
322} // namespace modelchecker
323} // 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: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.
A class that holds a possibly non-square matrix in the compressed row storage format.
bool isEqual(ValueType const &value1, ValueType const &value2) const
#define STORM_LOG_TRACE(message)
Definition logging.h:12
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:38
bool isZero(ValueType const &a)
Definition constants.cpp:38