Storm 1.13.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
BeliefMdpExplorer.cpp
Go to the documentation of this file.
2
6
16#include "storm/utility/graph.h"
19
20namespace storm {
21namespace builder {
22template<typename PomdpType, typename BeliefValueType>
28
29template<typename PomdpType, typename BeliefValueType>
37template<typename PomdpType, typename BeliefValueType>
38BeliefMdpExplorer<PomdpType, BeliefValueType>::BeliefMdpExplorer(std::shared_ptr<BeliefManagerType> beliefManager,
40 ExplorationHeuristic explorationHeuristic)
41 : beliefManager(beliefManager), pomdpValueBounds(pomdpValueBounds), explHeuristic(explorationHeuristic), status(Status::Uninitialized) {
42 // Intentionally left empty
43}
44
45template<typename PomdpType, typename BeliefValueType>
49
50template<typename PomdpType, typename BeliefValueType>
51void BeliefMdpExplorer<PomdpType, BeliefValueType>::startNewExploration(std::optional<ValueType> extraTargetStateValue,
52 std::optional<ValueType> extraBottomStateValue) {
53 status = Status::Exploring;
54 // Reset data from potential previous explorations
56 nextId = 0;
57 mdpStateToBeliefIdMap.clear();
58 beliefIdToMdpStateMap.clear();
59 exploredBeliefIds.clear();
60 exploredBeliefIds.grow(beliefManager->getNumberOfBeliefIds(), false);
61 mdpStatesToExplorePrioState.clear();
62 mdpStatesToExploreStatePrio.clear();
63 stateRemapping.clear();
64 lowerValueBounds.clear();
65 upperValueBounds.clear();
66 values.clear();
67 exploredMdpTransitions.clear();
68 exploredChoiceIndices.clear();
69 previousChoiceIndices.clear();
70 probabilityEstimation.clear();
71 mdpActionRewards.clear();
72 targetStates.clear();
73 truncatedStates.clear();
74 clippedStates.clear();
75 delayedExplorationChoices.clear();
76 clippingTransitionRewards.clear();
77 mdpStateToChoiceLabelsMap.clear();
78 optimalChoices = std::nullopt;
79 optimalChoicesReachableMdpStates = std::nullopt;
80 scheduler = nullptr;
81 exploredMdp = nullptr;
82 internalAddRowGroupIndex(); // Mark the start of the first row group
83
84 // Add some states with special treatment (if requested)
85 if (extraBottomStateValue) {
86 currentMdpState = getCurrentNumberOfMdpStates();
87 extraBottomState = currentMdpState;
88 mdpStateToBeliefIdMap.push_back(beliefManager->noId());
89 probabilityEstimation.push_back(storm::utility::zero<ValueType>());
90 insertValueHints(extraBottomStateValue.value(), extraBottomStateValue.value());
91
92 internalAddTransition(getStartOfCurrentRowGroup(), extraBottomState.value(), storm::utility::one<ValueType>());
93 mdpStateToChoiceLabelsMap[getStartOfCurrentRowGroup()][0] = "loop";
94 internalAddRowGroupIndex();
95 ++nextId;
96 } else {
97 extraBottomState = std::nullopt;
98 }
99 if (extraTargetStateValue) {
100 currentMdpState = getCurrentNumberOfMdpStates();
101 extraTargetState = currentMdpState;
102 mdpStateToBeliefIdMap.push_back(beliefManager->noId());
103 probabilityEstimation.push_back(storm::utility::zero<ValueType>());
104 insertValueHints(extraTargetStateValue.value(), extraTargetStateValue.value());
105
106 internalAddTransition(getStartOfCurrentRowGroup(), extraTargetState.value(), storm::utility::one<ValueType>());
107 mdpStateToChoiceLabelsMap[getStartOfCurrentRowGroup()][0] = "loop";
108 internalAddRowGroupIndex();
109
110 targetStates.grow(getCurrentNumberOfMdpStates(), false);
111 targetStates.set(extraTargetState.value(), true);
112 ++nextId;
113 } else {
114 extraTargetState = std::nullopt;
115 }
116 currentMdpState = noState();
117
118 // Set up the initial state.
119 initialMdpState = getOrAddMdpState(beliefManager->getInitialBelief());
120}
121
122template<typename PomdpType, typename BeliefValueType>
124 STORM_LOG_ASSERT(status == Status::ModelChecked || status == Status::ModelFinished, "Method call is invalid in current status.");
125 status = Status::Exploring;
126 // We will not erase old states during the exploration phase, so most state-based data (like mappings between MDP and Belief states) remain valid.
128 stateRemapping.clear();
129 exploredBeliefIds.clear();
130 exploredBeliefIds.grow(beliefManager->getNumberOfBeliefIds(), false);
131 exploredMdpTransitions.clear();
132 exploredMdpTransitions.resize(exploredMdp->getNumberOfChoices());
133 clippingTransitionRewards.clear();
134 previousChoiceIndices = exploredMdp->getNondeterministicChoiceIndices();
135 exploredChoiceIndices = exploredMdp->getNondeterministicChoiceIndices();
136 mdpActionRewards.clear();
137 probabilityEstimation.clear();
138 if (exploredMdp->hasRewardModel()) {
139 // Can be overwritten during exploration
140 mdpActionRewards = exploredMdp->getUniqueRewardModel().getStateActionRewardVector();
141 }
143 truncatedStates = storm::storage::BitVector(getCurrentNumberOfMdpStates(), false);
145 delayedExplorationChoices.clear();
146 mdpStatesToExplorePrioState.clear();
147 mdpStatesToExploreStatePrio.clear();
148
149 // The extra states are not changed
150 if (extraBottomState) {
151 currentMdpState = extraBottomState.value();
153 }
154 if (extraTargetState) {
155 currentMdpState = extraTargetState.value();
157 targetStates.set(extraTargetState.value(), true);
158 }
159 currentMdpState = noState();
160
161 // Set up the initial state.
162 initialMdpState = getOrAddMdpState(beliefManager->getInitialBelief());
163}
164
165template<typename PomdpType, typename BeliefValueType>
167 explorationStorage.storedMdpStateToBeliefIdMap = std::vector<BeliefId>(mdpStateToBeliefIdMap);
168 explorationStorage.storedBeliefIdToMdpStateMap = std::map<BeliefId, MdpStateType>(beliefIdToMdpStateMap);
169 explorationStorage.storedExploredBeliefIds = storm::storage::BitVector(exploredBeliefIds);
170 explorationStorage.storedMdpStateToChoiceLabelsMap = std::map<BeliefId, std::map<uint64_t, std::string>>(mdpStateToChoiceLabelsMap);
171 explorationStorage.storedMdpStatesToExplorePrioState = std::multimap<ValueType, uint64_t>(mdpStatesToExplorePrioState);
172 explorationStorage.storedMdpStatesToExploreStatePrio = std::map<uint64_t, ValueType>(mdpStatesToExploreStatePrio);
173 explorationStorage.storedProbabilityEstimation = std::vector<ValueType>(probabilityEstimation);
174 explorationStorage.storedExploredMdpTransitions = std::vector<std::map<MdpStateType, ValueType>>(exploredMdpTransitions);
175 explorationStorage.storedExploredChoiceIndices = std::vector<MdpStateType>(exploredChoiceIndices);
176 explorationStorage.storedMdpActionRewards = std::vector<ValueType>(mdpActionRewards);
177 explorationStorage.storedClippingTransitionRewards = std::map<MdpStateType, ValueType>(clippingTransitionRewards);
178 explorationStorage.storedCurrentMdpState = currentMdpState;
179 explorationStorage.storedStateRemapping = std::map<MdpStateType, MdpStateType>(stateRemapping);
180 explorationStorage.storedNextId = nextId;
181 explorationStorage.storedPrio = ValueType(prio);
182 explorationStorage.storedLowerValueBounds = std::vector<ValueType>(lowerValueBounds);
183 explorationStorage.storedUpperValueBounds = std::vector<ValueType>(upperValueBounds);
184 explorationStorage.storedValues = std::vector<ValueType>(values);
185
186 explorationStorage.storedTargetStates = storm::storage::BitVector(targetStates);
187}
188
189template<typename PomdpType, typename BeliefValueType>
191 mdpStateToBeliefIdMap = std::vector<BeliefId>(explorationStorage.storedMdpStateToBeliefIdMap);
192 beliefIdToMdpStateMap = std::map<BeliefId, MdpStateType>(explorationStorage.storedBeliefIdToMdpStateMap);
193 exploredBeliefIds = storm::storage::BitVector(explorationStorage.storedExploredBeliefIds);
194 mdpStateToChoiceLabelsMap = std::map<BeliefId, std::map<uint64_t, std::string>>(explorationStorage.storedMdpStateToChoiceLabelsMap);
195 mdpStatesToExplorePrioState = std::multimap<ValueType, uint64_t>(explorationStorage.storedMdpStatesToExplorePrioState);
196 mdpStatesToExploreStatePrio = std::map<uint64_t, ValueType>(explorationStorage.storedMdpStatesToExploreStatePrio);
197 probabilityEstimation = std::vector<ValueType>(explorationStorage.storedProbabilityEstimation);
198 exploredMdpTransitions = std::vector<std::map<MdpStateType, ValueType>>(explorationStorage.storedExploredMdpTransitions);
199 exploredChoiceIndices = std::vector<MdpStateType>(explorationStorage.storedExploredChoiceIndices);
200 mdpActionRewards = std::vector<ValueType>(explorationStorage.storedMdpActionRewards);
201 clippingTransitionRewards = std::map<MdpStateType, ValueType>(explorationStorage.storedClippingTransitionRewards);
202 currentMdpState = explorationStorage.storedCurrentMdpState;
203 stateRemapping = std::map<MdpStateType, MdpStateType>(explorationStorage.storedStateRemapping);
204 nextId = explorationStorage.storedNextId;
205 prio = ValueType(explorationStorage.storedPrio);
206 lowerValueBounds = explorationStorage.storedLowerValueBounds;
207 upperValueBounds = explorationStorage.storedUpperValueBounds;
208 values = explorationStorage.storedValues;
209 status = Status::Exploring;
210 targetStates = explorationStorage.storedTargetStates;
211
212 truncatedStates.clear();
213 clippedStates.clear();
214 delayedExplorationChoices.clear();
215 optimalChoices = std::nullopt;
216 optimalChoicesReachableMdpStates = std::nullopt;
217 exploredMdp = nullptr;
218 scheduler = nullptr;
219}
220
221template<typename PomdpType, typename BeliefValueType>
223 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
224 return !mdpStatesToExploreStatePrio.empty();
225}
226
227template<typename PomdpType, typename BeliefValueType>
229 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
230 std::vector<uint64_t> res;
231 res.reserve(mdpStatesToExploreStatePrio.size());
232 for (auto const &entry : mdpStatesToExploreStatePrio) {
233 res.push_back(entry.first);
234 }
235 return res;
236}
237
238template<typename PomdpType, typename BeliefValueType>
240 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
241 // Mark the end of the previously explored row group.
242 if (currentMdpState != noState() && mdpStatesToExplorePrioState.rbegin()->second == exploredChoiceIndices.size()) {
243 internalAddRowGroupIndex();
244 }
245
246 // Pop from the queue.
247 currentMdpState = mdpStatesToExplorePrioState.rbegin()->second;
248 auto currprio = mdpStatesToExplorePrioState.rbegin()->first;
249 auto range = mdpStatesToExplorePrioState.equal_range(currprio);
250 for (auto i = range.first; i != range.second; ++i) {
251 if (i->second == currentMdpState) {
252 mdpStatesToExplorePrioState.erase(i);
253 break;
254 }
255 }
256 mdpStatesToExploreStatePrio.erase(currentMdpState);
257 if (currentMdpState != nextId && !currentStateHasOldBehavior()) {
258 stateRemapping[currentMdpState] = nextId;
259 STORM_LOG_DEBUG("Explore state " << currentMdpState << " [Bel " << getCurrentBeliefId() << " " << beliefManager->toString(getCurrentBeliefId())
260 << "] as state with ID " << nextId << " (Prio: " << storm::utility::to_string(currprio) << ")");
261 } else {
262 STORM_LOG_DEBUG("Explore state " << currentMdpState << " [Bel " << getCurrentBeliefId() << " " << beliefManager->toString(getCurrentBeliefId()) << "]"
263 << " (Prio: " << storm::utility::to_string(currprio) << ")");
264 }
265
267 ++nextId;
268 }
269 if (explHeuristic == ExplorationHeuristic::ProbabilityPrio) {
270 probabilityEstimation.push_back(currprio);
271 }
272
273 return mdpStateToBeliefIdMap[currentMdpState];
274}
275
276template<typename PomdpType, typename BeliefValueType>
277void BeliefMdpExplorer<PomdpType, BeliefValueType>::addTransitionsToExtraStates(uint64_t const &localActionIndex, ValueType const &targetStateValue,
278 ValueType const &bottomStateValue) {
279 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
280 STORM_LOG_ASSERT(!currentStateHasOldBehavior() || localActionIndex < previousChoiceIndices[currentMdpState + 1] - previousChoiceIndices[currentMdpState] ||
282 "Action index " << localActionIndex << " was not valid at non-truncated state " << currentMdpState << " of the previously explored MDP.");
283 uint64_t row = getStartOfCurrentRowGroup() + localActionIndex;
284 if (!storm::utility::isZero(bottomStateValue)) {
285 STORM_LOG_ASSERT(extraBottomState.has_value(), "Requested a transition to the extra bottom state but there is none.");
286 internalAddTransition(row, extraBottomState.value(), bottomStateValue);
287 }
288 if (!storm::utility::isZero(targetStateValue)) {
289 STORM_LOG_ASSERT(extraTargetState.has_value(), "Requested a transition to the extra target state but there is none.");
290 internalAddTransition(row, extraTargetState.value(), targetStateValue);
291 }
292}
293
294template<typename PomdpType, typename BeliefValueType>
295void BeliefMdpExplorer<PomdpType, BeliefValueType>::addSelfloopTransition(uint64_t const &localActionIndex, ValueType const &value) {
296 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
297 STORM_LOG_ASSERT(!currentStateHasOldBehavior() || localActionIndex < previousChoiceIndices[currentMdpState + 1] - previousChoiceIndices[currentMdpState] ||
299 "Action index " << localActionIndex << " was not valid at non-truncated state " << currentMdpState << " of the previously explored MDP.");
300 uint64_t row = getStartOfCurrentRowGroup() + localActionIndex;
301 internalAddTransition(row, getCurrentMdpState(), value);
302}
303
304template<typename PomdpType, typename BeliefValueType>
305bool BeliefMdpExplorer<PomdpType, BeliefValueType>::addTransitionToBelief(uint64_t const &localActionIndex, BeliefId const &transitionTarget,
306 ValueType const &value, bool ignoreNewBeliefs) {
307 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
308 STORM_LOG_ASSERT(!currentStateHasOldBehavior() || localActionIndex < previousChoiceIndices[currentMdpState + 1] - previousChoiceIndices[currentMdpState] ||
310 "Action index " << localActionIndex << " was not valid at non-truncated state " << currentMdpState << " of the previously explored MDP.");
311
312 MdpStateType column;
313 if (ignoreNewBeliefs) {
314 column = getExploredMdpState(transitionTarget);
315 if (column == noState()) {
316 return false;
317 }
318 } else {
319 column = getOrAddMdpState(transitionTarget, value);
320 }
321 if (getCurrentMdpState() == exploredChoiceIndices.size()) {
322 internalAddRowGroupIndex();
323 }
324 uint64_t row = getStartOfCurrentRowGroup() + localActionIndex;
325 internalAddTransition(row, column, value);
326 return true;
327}
328
329template<typename PomdpType, typename BeliefValueType>
331 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
332 if (getCurrentNumberOfMdpChoices() > mdpActionRewards.size()) {
334 }
335 uint64_t row = getStartOfCurrentRowGroup() + localActionIndex;
336 mdpActionRewards[row] = beliefManager->getBeliefActionReward(getCurrentBeliefId(), localActionIndex) + extraReward;
337}
338
339template<typename PomdpType, typename BeliefValueType>
341 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
342 if (getCurrentNumberOfMdpChoices() > mdpActionRewards.size()) {
344 }
345 uint64_t row = getStartOfCurrentRowGroup() + localActionIndex;
346 mdpActionRewards[row] = rewardValue;
347}
348
349template<typename PomdpType, typename BeliefValueType>
351 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
352 uint64_t row = getStartOfCurrentRowGroup() + localActionIndex;
353 clippingTransitionRewards[row] = rewardValue;
354}
355
356template<typename PomdpType, typename BeliefValueType>
358 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
359 targetStates.grow(getCurrentNumberOfMdpStates(), false);
360 targetStates.set(getCurrentMdpState(), true);
361}
362
363template<typename PomdpType, typename BeliefValueType>
365 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
366 truncatedStates.grow(getCurrentNumberOfMdpStates(), false);
367 truncatedStates.set(getCurrentMdpState(), true);
368}
369
370template<typename PomdpType, typename BeliefValueType>
372 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
374 clippedStates.grow(getCurrentNumberOfMdpStates(), false);
375 clippedStates.set(getCurrentMdpState(), true);
376}
377
378template<typename PomdpType, typename BeliefValueType>
380 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
381 delayedExplorationChoices.grow(getCurrentNumberOfMdpChoices(), false);
382 delayedExplorationChoices.set(getStartOfCurrentRowGroup() + localActionIndex, true);
383}
384
385template<typename PomdpType, typename BeliefValueType>
387 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
388 STORM_LOG_ASSERT(getCurrentMdpState() != noState(), "Method 'currentStateHasOldBehavior' called but there is no current state.");
389 return exploredMdp && getCurrentMdpState() < exploredMdp->getNumberOfStates();
390}
391
392template<typename PomdpType, typename BeliefValueType>
394 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
395 STORM_LOG_ASSERT(getCurrentMdpState() != noState(), "Method 'actionAtCurrentStateWasOptimal' called but there is no current state.");
396 STORM_LOG_ASSERT(currentStateHasOldBehavior(), "Method 'actionAtCurrentStateWasOptimal' called but current state has no old behavior");
397 STORM_LOG_ASSERT(exploredMdp, "No 'old' mdp available");
398 return exploredMdp->getStateLabeling().getStateHasLabel("truncated", getCurrentMdpState());
399}
400
401template<typename PomdpType, typename BeliefValueType>
403 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
404 STORM_LOG_ASSERT(getCurrentMdpState() != noState(), "Method 'actionAtCurrentStateWasOptimal' called but there is no current state.");
405 STORM_LOG_ASSERT(currentStateHasOldBehavior(), "Method 'actionAtCurrentStateWasOptimal' called but current state has no old behavior");
406 STORM_LOG_ASSERT(exploredMdp, "No 'old' mdp available");
407 return exploredMdp->getStateLabeling().getStateHasLabel("clipped", getCurrentMdpState());
408}
409
410template<typename PomdpType, typename BeliefValueType>
412 STORM_LOG_ASSERT(status == Status::ModelChecked, "Method call is invalid in current status.");
413 STORM_LOG_ASSERT(optimalChoicesReachableMdpStates.has_value(),
414 "Method 'stateIsOptimalSchedulerReachable' called but 'computeOptimalChoicesAndReachableMdpStates' was not called before.");
415 return optimalChoicesReachableMdpStates->get(mdpState);
416}
417
418template<typename PomdpType, typename BeliefValueType>
419bool BeliefMdpExplorer<PomdpType, BeliefValueType>::actionIsOptimal(uint64_t const &globalActionIndex) const {
420 STORM_LOG_ASSERT(status == Status::ModelChecked, "Method call is invalid in current status.");
421 STORM_LOG_ASSERT(optimalChoices.has_value(), "Method 'actionIsOptimal' called but 'computeOptimalChoicesAndReachableMdpStates' was not called before.");
422 return optimalChoices->get(globalActionIndex);
423}
424
425template<typename PomdpType, typename BeliefValueType>
427 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
428 STORM_LOG_ASSERT(getCurrentMdpState() != noState(), "Method 'currentStateIsOptimalSchedulerReachable' called but there is no current state.");
429 STORM_LOG_ASSERT(currentStateHasOldBehavior(), "Method 'currentStateIsOptimalSchedulerReachable' called but current state has no old behavior");
430 STORM_LOG_ASSERT(optimalChoicesReachableMdpStates.has_value(),
431 "Method 'currentStateIsOptimalSchedulerReachable' called but 'computeOptimalChoicesAndReachableMdpStates' was not called before.");
432 return optimalChoicesReachableMdpStates->get(getCurrentMdpState());
433}
434
435template<typename PomdpType, typename BeliefValueType>
437 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
438 STORM_LOG_ASSERT(getCurrentMdpState() != noState(), "Method 'actionAtCurrentStateWasOptimal' called but there is no current state.");
439 STORM_LOG_ASSERT(currentStateHasOldBehavior(), "Method 'actionAtCurrentStateWasOptimal' called but current state has no old behavior");
440 STORM_LOG_ASSERT(optimalChoices.has_value(),
441 "Method 'currentStateIsOptimalSchedulerReachable' called but 'computeOptimalChoicesAndReachableMdpStates' was not called before.");
442 uint64_t choice = previousChoiceIndices.at(getCurrentMdpState()) + localActionIndex;
443 return optimalChoices->get(choice);
444}
445
446template<typename PomdpType, typename BeliefValueType>
448 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
449 STORM_LOG_ASSERT(getCurrentMdpState() != noState(), "Method 'actionAtCurrentStateWasOptimal' called but there is no current state.");
450 STORM_LOG_ASSERT(currentStateHasOldBehavior(), "Method 'actionAtCurrentStateWasOptimal' called but current state has no old behavior");
451 STORM_LOG_ASSERT(exploredMdp, "No 'old' mdp available");
452 uint64_t choice = exploredMdp->getNondeterministicChoiceIndices()[getCurrentMdpState()] + localActionIndex;
453 return exploredMdp->hasChoiceLabeling() && exploredMdp->getChoiceLabeling().getLabels().count("delayed") > 0 &&
454 exploredMdp->getChoiceLabeling().getChoiceHasLabel("delayed", choice);
455}
456
457template<typename PomdpType, typename BeliefValueType>
459 STORM_LOG_ASSERT(currentStateHasOldBehavior(), "Cannot restore old behavior as the current state does not have any.");
460 STORM_LOG_ASSERT(localActionIndex < previousChoiceIndices[currentMdpState + 1] - previousChoiceIndices[currentMdpState],
461 "Action index " << localActionIndex << " was not valid at state " << currentMdpState << " of the previously explored MDP.");
462
463 if (getCurrentMdpState() == exploredChoiceIndices.size()) {
464 internalAddRowGroupIndex();
465 }
466
467 assert(getCurrentMdpState() < previousChoiceIndices.size());
468 assert(getCurrentMdpState() < exploredChoiceIndices.size());
469 uint64_t oldChoiceIndex = previousChoiceIndices.at(getCurrentMdpState()) + localActionIndex;
470 uint64_t newChoiceIndex = exploredChoiceIndices.at(getCurrentMdpState()) + localActionIndex;
471
472 // Insert the transitions
473 for (auto const &transition : exploredMdp->getTransitionMatrix().getRow(oldChoiceIndex)) {
474 internalAddTransition(newChoiceIndex, transition.getColumn(), transition.getValue());
475 // Check whether exploration is needed
476 auto beliefId = getBeliefId(transition.getColumn());
477 if (beliefId != beliefManager->noId()) { // Not the extra target or bottom state
478 if (!exploredBeliefIds.get(beliefId)) {
479 // This belief needs exploration
480 exploredBeliefIds.set(beliefId, true);
481 ValueType currentPrio;
482 switch (explHeuristic) {
484 currentPrio = prio;
485 prio = prio - storm::utility::one<ValueType>();
486 break;
488 currentPrio = getLowerValueBoundAtCurrentState();
489 break;
491 currentPrio = getUpperValueBoundAtCurrentState();
492 break;
495 break;
497 if (getCurrentMdpState() != noState()) {
498 currentPrio = probabilityEstimation[getCurrentMdpState()] * transition.getValue();
499 } else {
500 currentPrio = storm::utility::one<ValueType>();
501 }
502 break;
503 default:
504 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Other heuristics not implemented yet");
505 }
506 mdpStatesToExploreStatePrio[transition.getColumn()] = currentPrio;
507 mdpStatesToExplorePrioState.emplace(currentPrio, transition.getColumn());
508 }
509 }
510 }
511
512 // Actually, nothing needs to be done for rewards since we already initialize the vector with the "old" values
513}
514
515template<typename PomdpType, typename BeliefValueType>
517 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
518 STORM_LOG_ASSERT(!hasUnexploredState(), "Finishing exploration not possible if there are still unexplored states.");
519
520 // Complete the exploration
521 // Finish the last row grouping in case the last explored state was new
522 if (!currentStateHasOldBehavior() || exploredChoiceIndices.back() < getCurrentNumberOfMdpChoices()) {
523 internalAddRowGroupIndex();
524 }
525 // Resize state- and choice based vectors to the correct size
526 targetStates.resize(getCurrentNumberOfMdpStates(), false);
527 truncatedStates.resize(getCurrentNumberOfMdpStates(), false);
528 clippedStates.resize(getCurrentNumberOfMdpStates(), false);
529 if (!mdpActionRewards.empty()) {
531 }
532
533 // We are not exploring anymore
534 currentMdpState = noState();
535
536 // If this was a restarted exploration, we might still have unexplored states (which were only reachable and explored in a previous build).
537 // We get rid of these before rebuilding the model
538 if (exploredMdp) {
540 }
541
542 // The potentially computed optimal choices and the set of states that are reachable under these choices are not valid anymore.
543 optimalChoices = std::nullopt;
544 optimalChoicesReachableMdpStates = std::nullopt;
545
546 // Apply state remapping to the Belief-State maps
547 if (!stateRemapping.empty()) {
548 std::vector<BeliefId> remappedStateToBeliefIdMap(mdpStateToBeliefIdMap);
549 for (auto const &entry : stateRemapping) {
550 remappedStateToBeliefIdMap[entry.second] = mdpStateToBeliefIdMap[entry.first];
551 }
552 mdpStateToBeliefIdMap = remappedStateToBeliefIdMap;
553 for (auto const &beliefMdpState : beliefIdToMdpStateMap) {
554 if (stateRemapping.find(beliefMdpState.second) != stateRemapping.end()) {
555 beliefIdToMdpStateMap[beliefMdpState.first] = stateRemapping[beliefMdpState.second];
556 }
557 }
558 if (!mdpStateToChoiceLabelsMap.empty()) {
559 std::map<BeliefId, std::map<uint64_t, std::string>> temp(mdpStateToChoiceLabelsMap);
560 for (auto const &entry : stateRemapping) {
561 temp[entry.second] = mdpStateToChoiceLabelsMap[entry.first];
562 }
563 mdpStateToChoiceLabelsMap = temp;
564 }
565 }
566
567 // Create the transition matrix
568 uint64_t entryCount = 0;
569 for (auto const &row : exploredMdpTransitions) {
570 entryCount += row.size();
571 }
574 for (uint64_t groupIndex = 0; groupIndex < exploredChoiceIndices.size() - 1; ++groupIndex) {
575 uint64_t rowIndex = exploredChoiceIndices[groupIndex];
576 uint64_t groupEnd = exploredChoiceIndices[groupIndex + 1];
577 builder.newRowGroup(rowIndex);
578 for (; rowIndex < groupEnd; ++rowIndex) {
579 for (auto const &entry : exploredMdpTransitions[rowIndex]) {
580 if (stateRemapping.find(entry.first) == stateRemapping.end()) {
581 builder.addNextValue(rowIndex, entry.first, entry.second);
582 } else {
583 builder.addNextValue(rowIndex, stateRemapping[entry.first], entry.second);
584 }
585 }
586 }
587 }
588 auto mdpTransitionMatrix = builder.build();
589
590 // Create a standard labeling
592 mdpLabeling.addLabel("init");
593 mdpLabeling.addLabelToState("init", initialMdpState);
594 targetStates.resize(getCurrentNumberOfMdpStates(), false);
595 mdpLabeling.addLabel("target", std::move(targetStates));
596 truncatedStates.resize(getCurrentNumberOfMdpStates(), false);
597 mdpLabeling.addLabel("truncated", std::move(truncatedStates));
598 clippedStates.resize(getCurrentNumberOfMdpStates(), false);
599 mdpLabeling.addLabel("clipped", std::move(clippedStates));
600
601 for (uint64_t state = 0; state < getCurrentNumberOfMdpStates(); ++state) {
602 if (state == extraBottomState || state == extraTargetState) {
603 if (!mdpLabeling.containsLabel("__extra")) {
604 mdpLabeling.addLabel("__extra");
605 }
606 mdpLabeling.addLabelToState("__extra", state);
607 } else {
608 STORM_LOG_DEBUG("Observation of MDP state " << state << " : " << beliefManager->getObservationLabel(mdpStateToBeliefIdMap[state]) << "\n");
609 std::string obsLabel = beliefManager->getObservationLabel(mdpStateToBeliefIdMap[state]);
610 uint32_t obsId = beliefManager->getBeliefObservation(mdpStateToBeliefIdMap[state]);
611 if (!obsLabel.empty()) {
612 if (!mdpLabeling.containsLabel(obsLabel)) {
613 mdpLabeling.addLabel(obsLabel);
614 }
615 mdpLabeling.addLabelToState(obsLabel, state);
616 } else if (mdpStateToBeliefIdMap[state] != beliefManager->noId()) {
617 std::string obsIdLabel = "obs_" + std::to_string(obsId);
618 if (!mdpLabeling.containsLabel(obsIdLabel)) {
619 mdpLabeling.addLabel(obsIdLabel);
620 }
621 mdpLabeling.addLabelToState(obsIdLabel, state);
622 }
623 }
624 }
625
626 // Create a standard reward model (if rewards are available)
627 std::unordered_map<std::string, storm::models::sparse::StandardRewardModel<ValueType>> mdpRewardModels;
628 if (!mdpActionRewards.empty()) {
630 if (!clippingTransitionRewards.empty()) {
632 clippingTransitionRewards.size(), true, true, getCurrentNumberOfMdpStates());
633 for (uint64_t groupIndex = 0; groupIndex < exploredChoiceIndices.size() - 1; ++groupIndex) {
634 uint64_t rowIndex = exploredChoiceIndices[groupIndex];
635 uint64_t groupEnd = exploredChoiceIndices[groupIndex + 1];
636 rewardBuilder.newRowGroup(rowIndex);
637 for (; rowIndex < groupEnd; ++rowIndex) {
638 if (clippingTransitionRewards.find(rowIndex) != clippingTransitionRewards.end()) {
639 STORM_LOG_ASSERT(extraTargetState.has_value(), "Requested a transition to the extra target state but there is none.");
640 rewardBuilder.addNextValue(rowIndex, extraTargetState.value(), clippingTransitionRewards[rowIndex]);
641 }
642 }
643 }
644 auto transitionRewardMatrix = rewardBuilder.build();
645 mdpRewardModels.emplace("default", storm::models::sparse::StandardRewardModel<ValueType>(
646 std::optional<std::vector<ValueType>>(), std::move(mdpActionRewards), std::move(transitionRewardMatrix)));
647 } else {
648 mdpRewardModels.emplace(
649 "default", storm::models::sparse::StandardRewardModel<ValueType>(std::optional<std::vector<ValueType>>(), std::move(mdpActionRewards)));
650 }
651 }
652
653 // Create model components
654 storm::storage::sparse::ModelComponents<ValueType> modelComponents(std::move(mdpTransitionMatrix), std::move(mdpLabeling), std::move(mdpRewardModels));
655
656 // Potentially create a choice labeling
657 if (!mdpStateToChoiceLabelsMap.empty()) {
659 for (auto const &stateMap : mdpStateToChoiceLabelsMap) {
660 auto rowGroup = stateMap.first;
661 for (auto const &actionLabel : stateMap.second) {
662 if (!modelComponents.choiceLabeling->containsLabel(actionLabel.second)) {
663 modelComponents.choiceLabeling->addLabel(actionLabel.second);
664 }
665 modelComponents.choiceLabeling->addLabelToChoice(actionLabel.second, exploredChoiceIndices.at(rowGroup) + actionLabel.first);
666 }
667 }
668 }
669
670 if (!delayedExplorationChoices.empty()) {
672 delayedExplorationChoices.resize(getCurrentNumberOfMdpChoices(), false);
673 modelComponents.choiceLabeling->addLabel("delayed", std::move(delayedExplorationChoices));
674 }
675
676 // Create the final model.
677 exploredMdp = std::make_shared<storm::models::sparse::Mdp<ValueType>>(std::move(modelComponents));
678 status = Status::ModelFinished;
679 STORM_LOG_DEBUG("Explored Mdp with " << exploredMdp->getNumberOfStates() << " states (" << clippedStates.getNumberOfSetBits()
680 << " of which were clipped and " << truncatedStates.getNumberOfSetBits() - clippedStates.getNumberOfSetBits()
681 << " of which were flagged as truncated).");
682}
683
684template<typename PomdpType, typename BeliefValueType>
686 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
687 STORM_LOG_ASSERT(!hasUnexploredState(), "Finishing exploration not possible if there are still unexplored states.");
688
689 STORM_LOG_ASSERT(exploredMdp, "Method called although no 'old' MDP is available.");
690 // Find the states (and corresponding choices) that were not explored.
691 // These correspond to "empty" MDP transitions
692 storm::storage::BitVector relevantMdpStates(getCurrentNumberOfMdpStates(), true), relevantMdpChoices(getCurrentNumberOfMdpChoices(), true);
693 std::vector<MdpStateType> toRelevantStateIndexMap(getCurrentNumberOfMdpStates(), noState());
694 MdpStateType nextRelevantIndex = 0;
695 for (uint64_t groupIndex = 0; groupIndex < exploredChoiceIndices.size() - 1; ++groupIndex) {
696 uint64_t rowIndex = exploredChoiceIndices[groupIndex];
697 // Check first row in group
698 if (exploredMdpTransitions[rowIndex].empty()) {
699 relevantMdpChoices.set(rowIndex, false);
700 relevantMdpStates.set(groupIndex, false);
701 } else {
702 toRelevantStateIndexMap[groupIndex] = nextRelevantIndex;
703 ++nextRelevantIndex;
704 }
705 uint64_t groupEnd = exploredChoiceIndices[groupIndex + 1];
706 // process remaining rows in group
707 for (++rowIndex; rowIndex < groupEnd; ++rowIndex) {
708 // Assert that all actions at the current state were consistently explored or unexplored.
709 STORM_LOG_ASSERT(exploredMdpTransitions[rowIndex].empty() != relevantMdpStates.get(groupIndex),
710 "Actions at 'old' MDP state " << groupIndex << " were only partly explored.");
711 if (exploredMdpTransitions[rowIndex].empty()) {
712 relevantMdpChoices.set(rowIndex, false);
713 }
714 }
715 }
716
717 if (relevantMdpStates.full()) {
718 // All states are relevant so nothing to do
719 return;
720 }
721
722 nextId -= (relevantMdpStates.size() - relevantMdpStates.getNumberOfSetBits());
723
724 // Translate various components to the "new" MDP state set
725 storm::utility::vector::filterVectorInPlace(mdpStateToBeliefIdMap, relevantMdpStates);
726 { // beliefIdToMdpStateMap
727 for (auto belIdToMdpStateIt = beliefIdToMdpStateMap.begin(); belIdToMdpStateIt != beliefIdToMdpStateMap.end();) {
728 if (relevantMdpStates.get(belIdToMdpStateIt->second)) {
729 // Translate current entry and move on to the next one.
730 belIdToMdpStateIt->second = toRelevantStateIndexMap[belIdToMdpStateIt->second];
731 ++belIdToMdpStateIt;
732 } else {
733 STORM_LOG_ASSERT(!exploredBeliefIds.get(belIdToMdpStateIt->first),
734 "Inconsistent exploration information: Unexplored MDPState corresponds to explored beliefId");
735 // Delete current entry and move on to the next one.
736 // This works because std::map::erase does not invalidate other iterators within the map!
737 beliefIdToMdpStateMap.erase(belIdToMdpStateIt++);
738 }
739 }
740 }
741 { // exploredMdpTransitions
742 storm::utility::vector::filterVectorInPlace(exploredMdpTransitions, relevantMdpChoices);
743 // Adjust column indices. Unfortunately, the fastest way seems to be to "rebuild" the map
744 // It might pay off to do this when building the matrix.
745 for (auto &transitions : exploredMdpTransitions) {
746 std::map<MdpStateType, ValueType> newTransitions;
747 for (auto const &entry : transitions) {
748 STORM_LOG_ASSERT(relevantMdpStates.get(entry.first), "Relevant state has transition to irrelevant state.");
749 newTransitions.emplace_hint(newTransitions.end(), toRelevantStateIndexMap[entry.first], entry.second);
750 }
751 transitions = std::move(newTransitions);
752 }
753 }
754 { // exploredChoiceIndices
755 MdpStateType newState = 0;
756 assert(exploredChoiceIndices[0] == 0u);
757 // Loop invariant: all indices up to exploredChoiceIndices[newState] consider the new row indices and all other entries are not touched.
758 for (auto const oldState : relevantMdpStates) {
759 if (oldState != newState) {
760 assert(oldState > newState);
761 uint64_t groupSize = getRowGroupSizeOfState(oldState);
762 exploredChoiceIndices.at(newState + 1) = exploredChoiceIndices.at(newState) + groupSize;
763 }
764 ++newState;
765 }
766 exploredChoiceIndices.resize(newState + 1);
767 }
768 if (!mdpActionRewards.empty()) {
769 storm::utility::vector::filterVectorInPlace(mdpActionRewards, relevantMdpChoices);
770 }
771 if (extraBottomState) {
772 extraBottomState = toRelevantStateIndexMap[extraBottomState.value()];
773 }
774 if (extraTargetState) {
775 extraTargetState = toRelevantStateIndexMap[extraTargetState.value()];
776 }
777 targetStates = targetStates % relevantMdpStates;
778 truncatedStates = truncatedStates % relevantMdpStates;
779 clippedStates = clippedStates % relevantMdpStates;
780 initialMdpState = toRelevantStateIndexMap[initialMdpState];
781
782 storm::utility::vector::filterVectorInPlace(lowerValueBounds, relevantMdpStates);
783 storm::utility::vector::filterVectorInPlace(upperValueBounds, relevantMdpStates);
784 storm::utility::vector::filterVectorInPlace(values, relevantMdpStates);
785
786 { // mdpStateToChoiceLabelsMap
787 if (!mdpStateToChoiceLabelsMap.empty()) {
788 auto temp = std::map<BeliefId, std::map<uint64_t, std::string>>();
789 for (auto const relevantState : relevantMdpStates) {
790 temp[toRelevantStateIndexMap[relevantState]] = mdpStateToChoiceLabelsMap[relevantState];
791 }
792 mdpStateToChoiceLabelsMap = temp;
793 }
794 }
795}
796
797template<typename PomdpType, typename BeliefValueType>
798std::shared_ptr<storm::models::sparse::Mdp<typename BeliefMdpExplorer<PomdpType, BeliefValueType>::ValueType>>
800 STORM_LOG_ASSERT(status == Status::ModelFinished || status == Status::ModelChecked, "Method call is invalid in current status.");
801 STORM_LOG_ASSERT(exploredMdp, "Tried to get the explored MDP but exploration was not finished yet.");
802 return exploredMdp;
803}
804
805template<typename PomdpType, typename BeliefValueType>
807 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
808 return mdpStateToBeliefIdMap.size();
809}
810
811template<typename PomdpType, typename BeliefValueType>
813 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
814 return exploredMdpTransitions.size();
815}
816
817template<typename PomdpType, typename BeliefValueType>
819 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
820 assert(getCurrentMdpState() < exploredChoiceIndices.size());
821 return exploredChoiceIndices.at(getCurrentMdpState());
822}
823
824template<typename PomdpType, typename BeliefValueType>
826 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
827 assert(getCurrentMdpState() < exploredChoiceIndices.size() - 1);
828 return exploredChoiceIndices.at(getCurrentMdpState() + 1) - exploredChoiceIndices.at(getCurrentMdpState());
829}
830
831template<typename PomdpType, typename BeliefValueType>
833 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
834 assert(state < exploredChoiceIndices.size());
835 if (state < exploredChoiceIndices.size() - 1) {
836 return exploredChoiceIndices.at(state + 1) - exploredChoiceIndices.at(state);
837 } else if (state == exploredChoiceIndices.size() - 1) {
838 return exploredMdpTransitions.size() - exploredChoiceIndices.at(state);
839 } else {
840 return 0;
841 }
842}
843
844template<typename PomdpType, typename BeliefValueType>
846 return (currentStateHasOldBehavior() && getCurrentStateWasTruncated() && getCurrentMdpState() < exploredChoiceIndices.size() - 1 &&
847 getSizeOfCurrentRowGroup() != numActionsNeeded);
848}
849
850template<typename PomdpType, typename BeliefValueType>
852 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
853 return lowerValueBounds[getCurrentMdpState()];
854}
855
856template<typename PomdpType, typename BeliefValueType>
858 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
859 return upperValueBounds[getCurrentMdpState()];
860}
861
862template<typename PomdpType, typename BeliefValueType>
864 BeliefId const &beliefId) const {
865 STORM_LOG_ASSERT(!pomdpValueBounds.lower.empty(), "Requested lower value bounds but none were available.");
866 auto it = pomdpValueBounds.lower.begin();
867 ValueType result = beliefManager->getWeightedSum(beliefId, *it);
868 for (++it; it != pomdpValueBounds.lower.end(); ++it) {
869 result = std::max(result, beliefManager->getWeightedSum(beliefId, *it));
870 }
871 return result;
872}
873
874template<typename PomdpType, typename BeliefValueType>
876 BeliefId const &beliefId) const {
877 STORM_LOG_ASSERT(!pomdpValueBounds.upper.empty(), "Requested upper value bounds but none were available.");
878 auto it = pomdpValueBounds.upper.begin();
879 ValueType result = beliefManager->getWeightedSum(beliefId, *it);
880 for (++it; it != pomdpValueBounds.upper.end(); ++it) {
881 result = std::min(result, beliefManager->getWeightedSum(beliefId, *it));
882 }
883 return result;
884}
885
886template<typename PomdpType, typename BeliefValueType>
888 BeliefId const &beliefId, uint64_t schedulerId) const {
889 STORM_LOG_ASSERT(!pomdpValueBounds.lower.empty(), "Requested lower value bounds but none were available.");
890 STORM_LOG_ASSERT(pomdpValueBounds.lower.size() > schedulerId, "Requested lower value bound for scheduler with ID " << schedulerId << " not available.");
891 return beliefManager->getWeightedSum(beliefId, pomdpValueBounds.lower[schedulerId]);
892}
893
894template<typename PomdpType, typename BeliefValueType>
896 BeliefId const &beliefId, uint64_t schedulerId) const {
897 STORM_LOG_ASSERT(!pomdpValueBounds.upper.empty(), "Requested upper value bounds but none were available.");
898 STORM_LOG_ASSERT(pomdpValueBounds.upper.size() > schedulerId, "Requested upper value bound for scheduler with ID " << schedulerId << " not available.");
899 return beliefManager->getWeightedSum(beliefId, pomdpValueBounds.upper[schedulerId]);
900}
901
902template<typename PomdpType, typename BeliefValueType>
903std::pair<bool, typename BeliefMdpExplorer<PomdpType, BeliefValueType>::ValueType>
905 STORM_LOG_ASSERT(!fmSchedulerValueList.empty(), "Requested finite memory scheduler value bounds but none were available.");
906 auto obs = beliefManager->getBeliefObservation(beliefId);
907 STORM_LOG_ASSERT(fmSchedulerValueList.size() > obs, "Requested value bound for observation " << obs << " not available.");
908 STORM_LOG_ASSERT(fmSchedulerValueList.at(obs).size() > memoryNode,
909 "Requested value bound for observation " << obs << " and memory node " << memoryNode << " not available.");
910 return beliefManager->getWeightedSum(beliefId, fmSchedulerValueList.at(obs).at(memoryNode));
911}
912
913template<typename PomdpType, typename BeliefValueType>
915 STORM_LOG_ASSERT(status == Status::ModelFinished, "Method call is invalid in current status.");
916 STORM_LOG_ASSERT(exploredMdp, "Tried to compute values but the MDP is not explored");
917 auto property = createStandardProperty(dir, exploredMdp->hasRewardModel());
918 auto task = createStandardCheckTask(property);
919
920 std::unique_ptr<storm::modelchecker::CheckResult> res(storm::api::verifyWithSparseEngine<ValueType>(env, exploredMdp, task));
921 if (res) {
922 values = std::move(res->asExplicitQuantitativeCheckResult<ValueType>().getValueVector());
923 scheduler = std::make_shared<storm::storage::Scheduler<ValueType>>(res->asExplicitQuantitativeCheckResult<ValueType>().getScheduler());
924 STORM_LOG_WARN_COND_DEBUG(storm::utility::vector::compareElementWise(lowerValueBounds, values, std::less_equal<ValueType>()),
925 "Computed values are smaller than the lower bound.");
926 STORM_LOG_WARN_COND_DEBUG(storm::utility::vector::compareElementWise(upperValueBounds, values, std::greater_equal<ValueType>()),
927 "Computed values are larger than the upper bound.");
928 } else {
930 STORM_LOG_ERROR("No result obtained while checking.");
931 }
932 status = Status::ModelChecked;
933}
934
935template<typename PomdpType, typename BeliefValueType>
939
940template<typename PomdpType, typename BeliefValueType>
941std::vector<typename BeliefMdpExplorer<PomdpType, BeliefValueType>::ValueType> const &BeliefMdpExplorer<PomdpType, BeliefValueType>::getValuesOfExploredMdp()
942 const {
943 STORM_LOG_ASSERT(status == Status::ModelChecked, "Method call is invalid in current status.");
944 return values;
945}
946
947template<typename PomdpType, typename BeliefValueType>
948const std::shared_ptr<storm::storage::Scheduler<typename BeliefMdpExplorer<PomdpType, BeliefValueType>::ValueType>> &
950 STORM_LOG_ASSERT(status == Status::ModelChecked, "Method call is invalid in current status.");
951 return scheduler;
952}
953
954template<typename PomdpType, typename BeliefValueType>
956 STORM_LOG_ASSERT(status == Status::ModelChecked, "Method call is invalid in current status.");
957 STORM_LOG_ASSERT(exploredMdp, "Tried to get a value but no MDP was explored.");
958 return getValuesOfExploredMdp()[exploredMdp->getInitialStates().getNextSetIndex(0)];
959}
960
961template<typename PomdpType, typename BeliefValueType>
963 MdpStateType exploredMdpState) const {
964 STORM_LOG_ASSERT(status != Status::Uninitialized, "Method call is invalid in current status.");
965 return mdpStateToBeliefIdMap[exploredMdpState];
966}
967
968template<typename PomdpType, typename BeliefValueType>
970 uint64_t localActionIndex, std::map<uint32_t, SuccessorObservationInformation> &gatheredSuccessorObservations) {
971 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
972 STORM_LOG_ASSERT(currentStateHasOldBehavior(), "Method call is invalid since the current state has no old behavior");
973 uint64_t mdpChoice = getStartOfCurrentRowGroup() + localActionIndex;
974 gatherSuccessorObservationInformationAtMdpChoice(mdpChoice, gatheredSuccessorObservations);
975}
976
977template<typename PomdpType, typename BeliefValueType>
979 uint64_t mdpChoice, std::map<uint32_t, SuccessorObservationInformation> &gatheredSuccessorObservations) {
980 STORM_LOG_ASSERT(exploredMdp, "Method call is invalid if no MDP has been explored before");
981 for (auto const &entry : exploredMdp->getTransitionMatrix().getRow(mdpChoice)) {
982 auto const &beliefId = getBeliefId(entry.getColumn());
983 if (beliefId != beliefManager->noId()) {
984 auto const &obs = beliefManager->getBeliefObservation(beliefId);
985 SuccessorObservationInformation info(entry.getValue(), entry.getValue(), 1);
986 auto obsInsertion = gatheredSuccessorObservations.emplace(obs, info);
987 if (!obsInsertion.second) {
988 // There already is an entry for this observation, so join the two information constructs
989 obsInsertion.first->second.join(info);
990 }
991 beliefManager->joinSupport(beliefId, obsInsertion.first->second.support);
992 }
993 }
994}
995
996template<typename PomdpType, typename BeliefValueType>
998 storm::storage::BitVector const &observationSet) {
999 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
1000 STORM_LOG_ASSERT(currentStateHasOldBehavior(), "Method call is invalid since the current state has no old behavior");
1001 uint64_t mdpChoice = previousChoiceIndices.at(getCurrentMdpState()) + localActionIndex;
1002 return std::any_of(exploredMdp->getTransitionMatrix().getRow(mdpChoice).begin(), exploredMdp->getTransitionMatrix().getRow(mdpChoice).end(),
1003 [this, &observationSet](typename storm::storage::MatrixEntry<uint_fast64_t, ValueType> i) {
1004 return observationSet.get(beliefManager->getBeliefObservation(getBeliefId(i.getColumn())));
1005 });
1006}
1007
1008template<typename PomdpType, typename BeliefValueType>
1010 STORM_LOG_ASSERT(status == Status::ModelChecked, "Method call is invalid in current status.");
1011 upperValueBounds = values;
1012}
1013
1014template<typename PomdpType, typename BeliefValueType>
1016 STORM_LOG_ASSERT(status == Status::ModelChecked, "Method call is invalid in current status.");
1017 lowerValueBounds = values;
1018}
1019
1020template<typename PomdpType, typename BeliefValueType>
1022 bool relativeDifference) {
1023 STORM_LOG_ASSERT(status == Status::ModelChecked, "Method call is invalid in current status.");
1024 STORM_LOG_ASSERT(exploredMdp, "Method call is invalid in if no MDP is available.");
1025 STORM_LOG_ASSERT(!optimalChoices.has_value(), "Tried to compute optimal scheduler but this has already been done before.");
1026 STORM_LOG_ASSERT(!optimalChoicesReachableMdpStates.has_value(),
1027 "Tried to compute states that are reachable under an optimal scheduler but this has already been done before.");
1028
1029 // First find the choices that are optimal
1030 optimalChoices = storm::storage::BitVector(exploredMdp->getNumberOfChoices(), false);
1031 auto const &choiceIndices = exploredMdp->getNondeterministicChoiceIndices();
1032 auto const &transitions = exploredMdp->getTransitionMatrix();
1033 auto const &targetStatesExploredMDP = exploredMdp->getStates("target");
1034 for (uint64_t mdpState = 0; mdpState < exploredMdp->getNumberOfStates(); ++mdpState) {
1035 if (targetStatesExploredMDP.get(mdpState)) {
1036 // Target states can be skipped.
1037 continue;
1038 } else {
1039 auto const &stateValue = values[mdpState];
1040 for (uint64_t globalChoice = choiceIndices[mdpState]; globalChoice < choiceIndices[mdpState + 1]; ++globalChoice) {
1041 ValueType choiceValue = transitions.multiplyRowWithVector(globalChoice, values);
1042 if (exploredMdp->hasRewardModel()) {
1043 choiceValue += exploredMdp->getUniqueRewardModel().getStateActionReward(globalChoice);
1044 }
1045 auto absDiff = storm::utility::abs<ValueType>((choiceValue - stateValue));
1046 if ((relativeDifference && absDiff <= ancillaryChoicesEpsilon * stateValue) || (!relativeDifference && absDiff <= ancillaryChoicesEpsilon)) {
1047 optimalChoices->set(globalChoice, true);
1048 }
1049 }
1050 STORM_LOG_ASSERT(optimalChoices->getNextSetIndex(choiceIndices[mdpState]) < optimalChoices->size(), "Could not find an optimal choice.");
1051 }
1052 }
1053
1054 // Then, find the states that are reachable via these choices
1055 optimalChoicesReachableMdpStates = storm::utility::graph::getReachableStates(transitions, exploredMdp->getInitialStates(), ~targetStatesExploredMDP,
1056 targetStatesExploredMDP, false, 0, optimalChoices.value());
1057}
1058
1059template<typename PomdpType, typename BeliefValueType>
1061 return getExploredMdpState(beliefId) != noState();
1062}
1063
1064template<typename PomdpType, typename BeliefValueType>
1065typename BeliefMdpExplorer<PomdpType, BeliefValueType>::MdpStateType BeliefMdpExplorer<PomdpType, BeliefValueType>::noState() const {
1066 return std::numeric_limits<MdpStateType>::max();
1067}
1068
1069template<typename PomdpType, typename BeliefValueType>
1070std::shared_ptr<storm::logic::Formula const> BeliefMdpExplorer<PomdpType, BeliefValueType>::createStandardProperty(
1071 storm::solver::OptimizationDirection const &dir, bool computeRewards) {
1072 std::string propertyString = computeRewards ? "R" : "P";
1073 propertyString += storm::solver::minimize(dir) ? "min" : "max";
1074 propertyString += "=? [F \"target\"]";
1075 std::vector<storm::jani::Property> propertyVector = storm::api::parseProperties(propertyString);
1076 return storm::api::extractFormulasFromProperties(propertyVector).front();
1077}
1078
1079template<typename PomdpType, typename BeliefValueType>
1081BeliefMdpExplorer<PomdpType, BeliefValueType>::createStandardCheckTask(std::shared_ptr<storm::logic::Formula const> &property) {
1082 // Note: The property should not run out of scope after calling this because the task only stores the property by reference.
1083 // Therefore, this method needs the property by reference (and not const reference)
1084 auto task = storm::api::createTask<ValueType>(property, false);
1086 hint.setResultHint(values);
1087 auto hintPtr = std::make_shared<storm::modelchecker::ExplicitModelCheckerHint<ValueType>>(hint);
1088 task.setHint(hintPtr);
1089 task.setProduceSchedulers();
1090 return task;
1091}
1092
1093template<typename PomdpType, typename BeliefValueType>
1094typename BeliefMdpExplorer<PomdpType, BeliefValueType>::MdpStateType BeliefMdpExplorer<PomdpType, BeliefValueType>::getCurrentMdpState() const {
1095 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
1096 if (stateRemapping.find(currentMdpState) != stateRemapping.end()) {
1097 return stateRemapping.at(currentMdpState);
1098 } else {
1099 return currentMdpState;
1100 }
1101}
1102
1103template<typename PomdpType, typename BeliefValueType>
1104typename BeliefMdpExplorer<PomdpType, BeliefValueType>::MdpStateType BeliefMdpExplorer<PomdpType, BeliefValueType>::getCurrentBeliefId() const {
1105 STORM_LOG_ASSERT(status == Status::Exploring, "Method call is invalid in current status.");
1106 return getBeliefId(currentMdpState);
1107}
1108
1109template<typename PomdpType, typename BeliefValueType>
1110void BeliefMdpExplorer<PomdpType, BeliefValueType>::internalAddTransition(uint64_t const &row, MdpStateType const &column, ValueType const &value) {
1111 STORM_LOG_ASSERT(row <= exploredMdpTransitions.size(), "Skipped at least one row.");
1112 if (row == exploredMdpTransitions.size()) {
1113 exploredMdpTransitions.emplace_back();
1114 }
1115 STORM_LOG_ASSERT(exploredMdpTransitions[row].count(column) == 0, "Trying to insert multiple transitions to the same state.");
1116 exploredMdpTransitions[row][column] = value;
1117}
1118
1119template<typename PomdpType, typename BeliefValueType>
1120void BeliefMdpExplorer<PomdpType, BeliefValueType>::internalAddRowGroupIndex() {
1121 exploredChoiceIndices.push_back(getCurrentNumberOfMdpChoices());
1122}
1123
1124template<typename PomdpType, typename BeliefValueType>
1126 gridBeliefs.insert(beliefId);
1127}
1128
1129template<typename PomdpType, typename BeliefValueType>
1131 return gridBeliefs.count(beliefId) > 0;
1132}
1133
1134template<typename PomdpType, typename BeliefValueType>
1136 BeliefId const &beliefId) const {
1137 if (beliefId < exploredBeliefIds.size() && exploredBeliefIds.get(beliefId)) {
1138 return beliefIdToMdpStateMap.at(beliefId);
1139 } else {
1140 return noState();
1141 }
1142}
1143
1144template<typename PomdpType, typename BeliefValueType>
1145void BeliefMdpExplorer<PomdpType, BeliefValueType>::insertValueHints(ValueType const &lowerBound, ValueType const &upperBound) {
1146 lowerValueBounds.push_back(lowerBound);
1147 upperValueBounds.push_back(upperBound);
1148 // Take the middle value as a hint
1149 values.push_back((lowerBound + upperBound) / storm::utility::convertNumber<ValueType, uint64_t>(2));
1150 STORM_LOG_ASSERT(lowerValueBounds.size() == getCurrentNumberOfMdpStates(), "Value vectors have different size then number of available states.");
1151 STORM_LOG_ASSERT(lowerValueBounds.size() == upperValueBounds.size() && values.size() == upperValueBounds.size(), "Value vectors have inconsistent size.");
1152}
1153
1154template<typename PomdpType, typename BeliefValueType>
1155typename BeliefMdpExplorer<PomdpType, BeliefValueType>::MdpStateType BeliefMdpExplorer<PomdpType, BeliefValueType>::getOrAddMdpState(
1156 BeliefId const &beliefId, ValueType const &transitionValue) {
1157 exploredBeliefIds.grow(beliefId + 1, false);
1158 if (exploredBeliefIds.get(beliefId)) {
1159 if (explHeuristic == ExplorationHeuristic::ProbabilityPrio &&
1160 mdpStatesToExploreStatePrio.find(beliefIdToMdpStateMap[beliefId]) != mdpStatesToExploreStatePrio.end()) {
1161 // We check if the value is higher than the current priority and update if necessary
1162 auto newPrio = probabilityEstimation[getCurrentMdpState()] * transitionValue;
1163 if (newPrio > mdpStatesToExploreStatePrio[beliefIdToMdpStateMap[beliefId]]) {
1164 // Erase the state from the "queue" map and re-insert it with the new value
1165 auto range = mdpStatesToExplorePrioState.equal_range(mdpStatesToExploreStatePrio[beliefIdToMdpStateMap[beliefId]]);
1166 for (auto i = range.first; i != range.second; ++i) {
1167 if (i->second == beliefIdToMdpStateMap[beliefId]) {
1168 mdpStatesToExplorePrioState.erase(i);
1169 break;
1170 }
1171 }
1172 mdpStatesToExplorePrioState.emplace(newPrio, beliefIdToMdpStateMap[beliefId]);
1173 mdpStatesToExploreStatePrio[beliefIdToMdpStateMap[beliefId]] = newPrio;
1174 }
1175 }
1176 return beliefIdToMdpStateMap[beliefId];
1177 } else {
1178 // This state needs exploration
1179 exploredBeliefIds.set(beliefId, true);
1180
1181 // If this is a restart of the exploration, we still might have an MDP state for the belief
1182 if (exploredMdp) {
1183 auto findRes = beliefIdToMdpStateMap.find(beliefId);
1184 if (findRes != beliefIdToMdpStateMap.end()) {
1185 ValueType currentPrio;
1186 switch (explHeuristic) {
1188 currentPrio = prio;
1189 prio = prio - storm::utility::one<ValueType>();
1190 break;
1192 currentPrio = getLowerValueBoundAtCurrentState();
1193 break;
1195 currentPrio = getUpperValueBoundAtCurrentState();
1196 break;
1198 currentPrio = getUpperValueBoundAtCurrentState() - getLowerValueBoundAtCurrentState();
1199 break;
1201 if (getCurrentMdpState() != noState()) {
1202 currentPrio = probabilityEstimation[getCurrentMdpState()] * transitionValue;
1203 } else {
1204 currentPrio = storm::utility::one<ValueType>();
1205 }
1206 break;
1207 default:
1208 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Other heuristics not implemented yet");
1209 }
1210 mdpStatesToExploreStatePrio[findRes->second] = currentPrio;
1211 mdpStatesToExplorePrioState.emplace(currentPrio, findRes->second);
1212 return findRes->second;
1213 }
1214 }
1215 // At this point we need to add a new MDP state
1216 MdpStateType result = getCurrentNumberOfMdpStates();
1217 assert(getCurrentNumberOfMdpStates() == mdpStateToBeliefIdMap.size());
1218 mdpStateToBeliefIdMap.push_back(beliefId);
1219 beliefIdToMdpStateMap[beliefId] = result;
1220 insertValueHints(computeLowerValueBoundAtBelief(beliefId), computeUpperValueBoundAtBelief(beliefId));
1221 ValueType currentPrio;
1222 switch (explHeuristic) {
1224 currentPrio = prio;
1225 prio = prio - storm::utility::one<ValueType>();
1226 break;
1228 currentPrio = getLowerValueBoundAtCurrentState();
1229 break;
1231 currentPrio = getUpperValueBoundAtCurrentState();
1232 break;
1234 currentPrio = getUpperValueBoundAtCurrentState() - getLowerValueBoundAtCurrentState();
1235 break;
1237 if (getCurrentMdpState() != noState()) {
1238 currentPrio = probabilityEstimation[getCurrentMdpState()] * transitionValue;
1239 } else {
1240 currentPrio = storm::utility::one<ValueType>();
1241 }
1242 break;
1243 default:
1244 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Other heuristics not implemented yet");
1245 }
1246 mdpStatesToExploreStatePrio[result] = currentPrio;
1247 mdpStatesToExplorePrioState.emplace(currentPrio, result);
1248 return result;
1249 }
1250}
1251
1252template<typename PomdpType, typename BeliefValueType>
1253void BeliefMdpExplorer<PomdpType, BeliefValueType>::addChoiceLabelToCurrentState(uint64_t const &localActionIndex, std::string const &label) {
1254 mdpStateToChoiceLabelsMap[currentMdpState][localActionIndex] = label;
1255}
1256
1257template<typename PomdpType, typename BeliefValueType>
1258std::vector<typename BeliefMdpExplorer<PomdpType, BeliefValueType>::BeliefId> BeliefMdpExplorer<PomdpType, BeliefValueType>::getBeliefsInMdp() {
1259 return mdpStateToBeliefIdMap;
1260}
1261
1262template<typename PomdpType, typename BeliefValueType>
1263std::vector<typename BeliefMdpExplorer<PomdpType, BeliefValueType>::BeliefId> BeliefMdpExplorer<PomdpType, BeliefValueType>::getBeliefsWithObservationInMdp(
1264 uint32_t obs) const {
1265 std::vector<BeliefId> res;
1266 for (auto const &belief : mdpStateToBeliefIdMap) {
1267 if (belief != beliefManager->noId()) {
1268 if (beliefManager->getBeliefObservation(belief) == obs) {
1269 res.push_back(belief);
1270 }
1271 }
1272 }
1273 return res;
1274}
1275
1276template<typename PomdpType, typename BeliefValueType>
1278 uint64_t const &pomdpState) {
1279 return pomdpValueBounds.getSmallestUpperBound(pomdpState);
1280}
1281
1282template<typename PomdpType, typename BeliefValueType>
1284 uint64_t const &pomdpState) {
1285 return pomdpValueBounds.getHighestLowerBound(pomdpState);
1286}
1287
1288template<typename PomdpType, typename BeliefValueType>
1292
1293template<typename PomdpType, typename BeliefValueType>
1294void BeliefMdpExplorer<PomdpType, BeliefValueType>::setFMSchedValueList(std::vector<std::vector<std::unordered_map<uint64_t, ValueType>>> valueList) {
1295 fmSchedulerValueList = valueList;
1296}
1297
1298template<typename PomdpType, typename BeliefValueType>
1300 return fmSchedulerValueList.at(observation).size();
1301}
1302
1303template<typename PomdpType, typename BeliefValueType>
1305 const uint64_t &pomdpState) {
1306 return extremeValueBound.getValueForState(pomdpState);
1307}
1308
1309template<typename PomdpType, typename BeliefValueType>
1313
1314template<typename PomdpType, typename BeliefValueType>
1316 return pomdpValueBounds.upper.size();
1317}
1318
1319template<typename PomdpType, typename BeliefValueType>
1321 return pomdpValueBounds.lower.size();
1322}
1323
1324template<typename PomdpType, typename BeliefValueType>
1327 STORM_LOG_ASSERT(!pomdpValueBounds.lowerSchedulers.empty(), "Requested lower bound scheduler but none were available.");
1328 STORM_LOG_ASSERT(pomdpValueBounds.lowerSchedulers.size() > schedulerId,
1329 "Requested lower value bound scheduler with ID " << schedulerId << " not available.");
1330 return pomdpValueBounds.lowerSchedulers[schedulerId];
1331}
1332
1333template<typename PomdpType, typename BeliefValueType>
1336 STORM_LOG_ASSERT(!pomdpValueBounds.upperSchedulers.empty(), "Requested upper bound scheduler but none were available.");
1337 STORM_LOG_ASSERT(pomdpValueBounds.upperSchedulers.size() > schedulerId,
1338 "Requested upper value bound scheduler with ID " << schedulerId << " not available.");
1339 return pomdpValueBounds.upperSchedulers[schedulerId];
1340}
1341
1342template<typename PomdpType, typename BeliefValueType>
1343std::vector<storm::storage::Scheduler<typename BeliefMdpExplorer<PomdpType, BeliefValueType>::ValueType>>
1345 STORM_LOG_ASSERT(!pomdpValueBounds.lowerSchedulers.empty(), "Requested lower bound schedulers but none were available.");
1346 return pomdpValueBounds.lowerSchedulers;
1347}
1348
1349template<typename PomdpType, typename BeliefValueType>
1350std::vector<storm::storage::Scheduler<typename BeliefMdpExplorer<PomdpType, BeliefValueType>::ValueType>>
1352 STORM_LOG_ASSERT(!pomdpValueBounds.upperSchedulers.empty(), "Requested upper bound schedulers but none were available.");
1353 return pomdpValueBounds.upperSchedulers;
1354}
1355
1356template<typename PomdpType, typename BeliefValueType>
1357
1359 return !fmSchedulerValueList.empty();
1360}
1361
1362template<typename PomdpType, typename BeliefValueType>
1364 BeliefId const &beliefId, storm::storage::SparseMatrix<BeliefValueType> &matrix) const {
1365 return beliefManager->computeMatrixBeliefProduct(beliefId, matrix);
1366}
1367
1368template<typename PomdpType, typename BeliefValueType>
1370 uint64_t currentRowGroupSize = getSizeOfCurrentRowGroup();
1371 assert(totalNumberOfActions != currentRowGroupSize);
1372 if (totalNumberOfActions > currentRowGroupSize) {
1373 uint64_t numberOfActionsToAdd = totalNumberOfActions - currentRowGroupSize;
1374 exploredMdpTransitions.insert(exploredMdpTransitions.begin() + (exploredChoiceIndices[getCurrentMdpState() + 1]), numberOfActionsToAdd,
1375 std::map<MdpStateType, ValueType>());
1376 for (uint64_t i = getCurrentMdpState() + 1; i < exploredChoiceIndices.size(); i++) {
1377 exploredChoiceIndices[i] += numberOfActionsToAdd;
1378 }
1379 return;
1380 }
1381 if (totalNumberOfActions < currentRowGroupSize) {
1382 uint64_t numberOfActionsToRemove = currentRowGroupSize - totalNumberOfActions;
1383 exploredMdpTransitions.erase(exploredMdpTransitions.begin() + (exploredChoiceIndices[getCurrentMdpState() + 1]) - numberOfActionsToRemove,
1384 exploredMdpTransitions.begin() + (exploredChoiceIndices[getCurrentMdpState() + 1]));
1385 for (uint64_t i = getCurrentMdpState() + 1; i < exploredChoiceIndices.size(); i++) {
1386 exploredChoiceIndices[i] -= numberOfActionsToRemove;
1387 }
1388 }
1389}
1390
1392
1393template class BeliefMdpExplorer<storm::models::sparse::Pomdp<double>, storm::RationalNumber>;
1394
1396
1398} // namespace builder
1399} // namespace storm
MdpStateType getExploredMdpState(BeliefId const &beliefId) const
void addClippingRewardToCurrentState(uint64_t const &localActionIndex, ValueType rewardValue)
ValueType computeUpperValueBoundAtBelief(BeliefId const &beliefId) const
MdpStateType getCurrentNumberOfMdpStates() const
ValueType const & getComputedValueAtInitialState() const
void restartExploration()
Restarts the exploration to allow re-exploring each state.
bool currentStateHasSuccessorObservationInObservationSet(uint64_t localActionIndex, storm::storage::BitVector const &observationSet)
ValueType getTrivialLowerBoundAtPOMDPState(uint64_t const &pomdpState)
void setFMSchedValueList(std::vector< std::vector< std::unordered_map< uint64_t, ValueType > > > valueList)
ValueType getTrivialUpperBoundAtPOMDPState(uint64_t const &pomdpState)
void addTransitionsToExtraStates(uint64_t const &localActionIndex, ValueType const &targetStateValue=storm::utility::zero< ValueType >(), ValueType const &bottomStateValue=storm::utility::zero< ValueType >())
bool beliefHasMdpState(BeliefId const &beliefId) const
std::vector< ValueType > const & getValuesOfExploredMdp() const
storm::storage::BitVector getStateExtremeBoundIsInfinite()
storm::storage::Scheduler< ValueType > getLowerValueBoundScheduler(uint64_t schedulerId) const
void gatherSuccessorObservationInformationAtCurrentState(uint64_t localActionIndex, std::map< uint32_t, SuccessorObservationInformation > &gatheredSuccessorObservations)
void startNewExploration(std::optional< ValueType > extraTargetStateValue=boost::none, std::optional< ValueType > extraBottomStateValue=std::nullopt)
BeliefMdpExplorer(std::shared_ptr< BeliefManagerType > beliefManager, storm::pomdp::storage::PreprocessingPomdpValueBounds< ValueType > const &pomdpValueBounds, ExplorationHeuristic explorationHeuristic=ExplorationHeuristic::BreadthFirst)
bool actionIsOptimal(uint64_t const &globalActionIndex) const
Retrieves whether the given action at the current state was optimal in the most recent check.
bool needsActionAdjustment(uint64_t numActionsNeeded)
std::vector< BeliefId > getBeliefsWithObservationInMdp(uint32_t obs) const
ValueType getExtremeValueBoundAtPOMDPState(uint64_t const &pomdpState)
MdpStateType getBeliefId(MdpStateType exploredMdpState) const
void computeValuesOfExploredMdp(storm::Environment const &env, storm::solver::OptimizationDirection const &dir)
std::vector< BeliefId > getBeliefsInMdp()
std::shared_ptr< storm::models::sparse::Mdp< ValueType > > getExploredMdp() const
storm::storage::Scheduler< ValueType > getUpperValueBoundScheduler(uint64_t schedulerId) const
std::vector< storm::storage::Scheduler< ValueType > > getLowerValueBoundSchedulers() const
bool getCurrentStateActionExplorationWasDelayed(uint64_t const &localActionIndex) const
BeliefManagerType const & getBeliefManager() const
storm::storage::BeliefManager< PomdpType, BeliefValueType > BeliefManagerType
std::pair< bool, ValueType > computeFMSchedulerValueForMemoryNode(BeliefId const &beliefId, uint64_t memoryNode) const
void setExtremeValueBound(storm::pomdp::storage::ExtremePOMDPValueBound< ValueType > valueBound)
void addChoiceLabelToCurrentState(uint64_t const &localActionIndex, std::string const &label)
std::vector< uint64_t > getUnexploredStates()
void restoreOldBehaviorAtCurrentState(uint64_t const &localActionIndex)
Inserts transitions and rewards at the given action as in the MDP of the previous exploration.
ValueType computeLowerValueBoundAtBelief(BeliefId const &beliefId) const
uint64_t getRowGroupSizeOfState(uint64_t state) const
const std::shared_ptr< storm::storage::Scheduler< BeliefMdpExplorer< PomdpType, BeliefValueType >::ValueType > > & getSchedulerForExploredMdp() const
MdpStateType getStartOfCurrentRowGroup() const
ValueType computeLowerValueBoundForScheduler(BeliefId const &beliefId, uint64_t schedulerId) const
bool currentStateIsOptimalSchedulerReachable() const
Retrieves whether the current state can be reached under a scheduler that was optimal in the most rec...
void addRewardToCurrentState(uint64_t const &localActionIndex, ValueType rewardValue)
Adds the provided reward value to the given action of the current state.
void gatherSuccessorObservationInformationAtMdpChoice(uint64_t mdpChoice, std::map< uint32_t, SuccessorObservationInformation > &gatheredSuccessorObservations)
uint64_t getNrOfMemoryNodesForObservation(uint32_t observation) const
void computeRewardAtCurrentState(uint64_t const &localActionIndex, ValueType extraReward=storm::utility::zero< ValueType >())
void computeOptimalChoicesAndReachableMdpStates(ValueType const &ancillaryChoicesEpsilon, bool relativeDifference)
Computes the set of states that are reachable via a path that is consistent with an optimal MDP sched...
bool isMarkedAsGridBelief(BeliefId const &beliefId)
void markAsGridBelief(BeliefId const &beliefId)
ValueType computeUpperValueBoundForScheduler(BeliefId const &beliefId, uint64_t schedulerId) const
void adjustActions(uint64_t totalNumberOfActions)
bool actionAtCurrentStateWasOptimal(uint64_t const &localActionIndex) const
Retrieves whether the given action at the current state was optimal in the most recent check.
void setCurrentChoiceIsDelayed(uint64_t const &localActionIndex)
std::vector< BeliefValueType > computeProductWithSparseMatrix(BeliefId const &beliefId, storm::storage::SparseMatrix< BeliefValueType > &matrix) const
void addSelfloopTransition(uint64_t const &localActionIndex=0, ValueType const &value=storm::utility::one< ValueType >())
std::vector< storm::storage::Scheduler< ValueType > > getUpperValueBoundSchedulers() const
bool addTransitionToBelief(uint64_t const &localActionIndex, BeliefId const &transitionTarget, ValueType const &value, bool ignoreNewBeliefs)
Adds the next transition to the given successor belief.
bool stateIsOptimalSchedulerReachable(MdpStateType mdpState) const
Retrieves whether the current state can be reached under an optimal scheduler This requires a previou...
BeliefManagerType::BeliefId BeliefId
MdpStateType getCurrentNumberOfMdpChoices() const
This class contains information that might accelerate the model checking process.
This class manages the labeling of the choice space with a number of (atomic) labels.
void addLabel(std::string const &label)
Adds a new label to the labelings.
bool containsLabel(std::string const &label) const
Checks whether a label is registered within this labeling.
This class manages the labeling of the state space with a number of (atomic) labels.
void addLabelToState(std::string const &label, storm::storage::sparse::state_type state)
Adds a label to a given state.
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.
size_t size() const
Retrieves the number of bits this bit vector can store.
This class defines which action is chosen in a particular state of a non-deterministic model.
Definition Scheduler.h:18
A class that can be used to build a sparse matrix by adding value by value.
void addNextValue(index_type row, index_type column, value_type const &value)
Sets the matrix entry at the given row and column to the given value.
void newRowGroup(index_type startingRow)
Starts a new row group in the matrix.
SparseMatrix< value_type > build(index_type overriddenRowCount=0, index_type overriddenColumnCount=0, index_type overriddenRowGroupCount=0)
A class that holds a possibly non-square matrix in the compressed row storage format.
#define STORM_LOG_DEBUG(message)
Definition logging.h:18
#define STORM_LOG_ERROR(message)
Definition logging.h:26
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
#define STORM_LOG_WARN_COND_DEBUG(cond, message)
Definition macros.h:18
storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > createTask(std::shared_ptr< const storm::logic::Formula > const &formula, bool onlyInitialStatesRelevant=false)
std::vector< storm::jani::Property > parseProperties(storm::parser::FormulaParser &formulaParser, std::string const &inputString, boost::optional< std::set< std::string > > const &propertyFilter)
std::vector< std::shared_ptr< storm::logic::Formula const > > extractFormulasFromProperties(std::vector< storm::jani::Property > const &properties)
std::unique_ptr< storm::modelchecker::CheckResult > verifyWithSparseEngine(storm::Environment const &env, std::shared_ptr< storm::models::sparse::Dtmc< ValueType > > const &dtmc, storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > const &task)
SFTBDDChecker::ValueType ValueType
std::pair< storm::RationalNumber, storm::RationalNumber > count(std::vector< storm::storage::BitVector > const &origSets, std::vector< storm::storage::BitVector > const &intersects, std::vector< storm::storage::BitVector > const &intersectsInfo, storm::RationalNumber val, bool plus, uint64_t remdepth)
bool constexpr minimize(OptimizationDirection d)
storm::storage::BitVector getReachableStates(storm::storage::SparseMatrix< T > const &transitionMatrix, storm::storage::BitVector const &initialStates, storm::storage::BitVector const &constraintStates, storm::storage::BitVector const &targetStates, bool useStepBound, uint_fast64_t maximalSteps, boost::optional< storm::storage::BitVector > const &choiceFilter)
Performs a forward depth-first search through the underlying graph structure to identify the states t...
Definition graph.cpp:41
bool isTerminate()
Check whether the program should terminate (due to some abort signal).
bool compareElementWise(std::vector< T > const &left, std::vector< T > const &right, Comparator comp=std::less< T >())
Definition vector.h:172
void filterVectorInPlace(std::vector< Type > &v, storm::storage::BitVector const &filter)
Definition vector.h:1071
bool isZero(ValueType const &a)
Definition constants.cpp:39
ValueType abs(ValueType const &number)
ValueType zero()
Definition constants.cpp:24
std::string to_string(ValueType const &value)
ValueType one()
Definition constants.cpp:19
TargetType convertNumber(SourceType const &number)
ValueType maxProbabilityToSuccessorWithObs
The probability we move to the corresponding observation.
SuccessorObservationInformation(ValueType const &obsProb, ValueType const &maxProb, uint64_t const &count)
uint64_t successorWithObsCount
The maximal probability to move to a successor with the corresponding observation.
Struct to store the extreme bound values needed for the reward correction values when clipping is use...
Struct for storing precomputed values bounding the actual values on the POMDP.
std::optional< storm::models::sparse::ChoiceLabeling > choiceLabeling