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