Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
BeliefMdpBuilder.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <unordered_map>
5#include <utility>
6#include <vector>
7
9
16
19
20namespace storm::pomdp::beliefs {
21
22std::shared_ptr<storm::logic::Formula const> createFormulaForBeliefMdp(PropertyInformation const& propertyInformation) {
26 "Unexpected kind of property.");
27 switch (propertyInformation.kind) {
29 auto target = std::make_shared<storm::logic::AtomicLabelFormula const>("target");
30 auto eventuallyTarget = std::make_shared<storm::logic::EventuallyFormula const>(target, storm::logic::FormulaContext::Probability);
31 return std::make_shared<storm::logic::ProbabilityOperatorFormula const>(eventuallyTarget,
32 storm::logic::OperatorInformation(propertyInformation.dir));
33 }
35 auto bottom = std::make_shared<storm::logic::AtomicLabelFormula const>("target");
36 auto eventuallyBottom = std::make_shared<storm::logic::EventuallyFormula const>(bottom, storm::logic::FormulaContext::Reward,
37 storm::logic::RewardAccumulation(true, false, false));
38 return std::make_shared<storm::logic::RewardOperatorFormula const>(eventuallyBottom, propertyInformation.rewardModelName.value(),
39 storm::logic::OperatorInformation(propertyInformation.dir));
40 }
42 auto target = std::make_shared<storm::logic::AtomicLabelFormula const>("target");
43 auto trueFormula = std::make_shared<storm::logic::BooleanLiteralFormula const>(true);
44
45 std::vector<std::optional<logic::TimeBound>> lowerBounds;
46 std::vector<std::optional<logic::TimeBound>> upperBounds;
47 std::vector<logic::TimeBoundReference> timeBoundReferences;
48
49 for (auto const& rewardBound : propertyInformation.rewardBounds) {
50 if (rewardBound.rewardModelName.empty()) {
51 timeBoundReferences.emplace_back();
52 } else {
53 timeBoundReferences.emplace_back(rewardBound.rewardModelName);
54 }
55 if (rewardBound.lowerBound.has_value()) {
56 lowerBounds.emplace_back(rewardBound.lowerBound.value());
57 } else {
58 lowerBounds.emplace_back(std::nullopt);
59 }
60 if (rewardBound.upperBound.has_value()) {
61 upperBounds.emplace_back(rewardBound.upperBound.value());
62 } else {
63 upperBounds.emplace_back(std::nullopt);
64 }
65 }
66 auto eventuallyTarget =
67 std::make_shared<storm::logic::BoundedUntilFormula const>(trueFormula, target, lowerBounds, upperBounds, timeBoundReferences);
68 return std::make_shared<storm::logic::ProbabilityOperatorFormula const>(eventuallyTarget,
69 storm::logic::OperatorInformation(propertyInformation.dir));
70 }
71 }
72 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unhandled case.");
73}
74
75template<typename MatrixType>
76bool hasUniqueTransitionRewardsInChoice(MatrixType const& matrix, uint64_t choice, uint64_t numRewardModels) {
77 std::unordered_map<BeliefId, bool> targetHasReward;
78 for (auto i = matrix.rowIndications[choice]; i < matrix.rowIndications[choice + 1]; ++i) {
79 auto const& entry = matrix.transitions[i];
80 bool hasReward = false;
81 for (uint64_t rewardIndex = 0; rewardIndex < numRewardModels; ++rewardIndex) {
82 if (!storm::utility::isZero(entry.data[rewardIndex])) {
83 hasReward = true;
84 break;
85 }
86 }
87 auto [it, inserted] = targetHasReward.emplace(entry.targetBelief, hasReward);
88 if (!inserted && (hasReward || it->second)) {
89 return false;
90 }
91 }
92 return true;
93}
94
95template<typename BeliefMdpValueType, typename BeliefType, typename... ExtraTransitionData>
96std::pair<std::shared_ptr<models::sparse::Mdp<BeliefMdpValueType>>, std::unordered_map<uint64_t, BeliefId>> buildBeliefMdp(
98 PropertyInformation const& propertyInformation,
99 std::function<std::unordered_map<std::string, BeliefMdpValueType>(BeliefType const&)> const& computeCutOffValueMap) {
100 bool const isReachProb = propertyInformation.kind == PropertyInformation::Kind::ReachabilityProbability;
101 bool const isTotRew = propertyInformation.kind == PropertyInformation::Kind::ExpectedTotalReachabilityReward;
102 bool const isRewBndReachProb = propertyInformation.kind == PropertyInformation::Kind::RewardBoundedReachabilityProbability;
103 STORM_LOG_ASSERT(isReachProb || isTotRew || isRewBndReachProb, "Unexpected kind of property.");
104
105 bool constexpr extraDataCompatibleWithRewardAwareness =
106 sizeof...(ExtraTransitionData) == 1 && (std::is_same_v<std::vector<BeliefMdpValueType>, ExtraTransitionData> || ...);
107
108 // A rewarding cut-off loop may leave a two-sided interval before all dimensions satisfy their bounds.
109 // TODO: Support two-sided Pmin bounds by splitting each such dimension into lower-only and upper-only copies with distinct
110 // internal reward-model names. Keep identical original rewards in both copies on ordinary transitions. On the successful
111 // cut-off transition to the target, add enough reward only to lower-bound copies to satisfy all lower bounds immediately
112 // (including strict ones), and zero reward to upper-bound copies. This is an optimistic continuation: upper-bound violations
113 // incurred before the cut-off still fail. Splitting the formula bounds alone is insufficient because the copies need
114 // different cut-off rewards.
115 STORM_LOG_THROW(!(isRewBndReachProb && propertyInformation.dir == storm::OptimizationDirection::Minimize &&
116 std::any_of(propertyInformation.rewardBounds.begin(), propertyInformation.rewardBounds.end(),
117 [](RewardBound const& bound) { return bound.lowerBound.has_value() && bound.upperBound.has_value(); })),
118 storm::exceptions::NotSupportedException,
119 "Reward-bounded probability minimisation does not support dimensions with both lower and upper reward bounds.");
120 auto const frontierBeliefs = explorationInformation.getFrontierBeliefs();
121 bool const initialBeliefIsTerminal = explorationInformation.terminalBeliefValues.contains(explorationInformation.initialBeliefId);
122
123 // First gather all cut-off information
124 uint64_t nrCutOffChoices = 0ull;
125 std::unordered_map<BeliefId, std::unordered_map<std::string, BeliefMdpValueType>> cutOffInformationMap;
126 for (auto const& frontierBeliefId : frontierBeliefs) {
127 auto const& frontierBelief = explorationInformation.discoveredBeliefs.getBeliefFromId(frontierBeliefId);
128 cutOffInformationMap[frontierBeliefId] = computeCutOffValueMap(frontierBelief);
129 nrCutOffChoices += cutOffInformationMap[frontierBeliefId].size();
130 }
131
132 constexpr bool clippingUsed = std::is_same_v<ExplorationInformation<BeliefMdpValueType, BeliefType, ExtraTransitionData...>,
134
135 // Reachability probabilities and reward-bounded cut-offs get dedicated target and bottom states.
136 // The target state used for reward-bounded cut-offs is distinct from ordinary target beliefs, which are not terminal
137 // (e.g. because of lower reward bounds).
138 uint64_t const numBottomTargetStates = isReachProb || isRewBndReachProb || clippingUsed ? 2ull : 1ull;
139 uint64_t const numInitialTerminalStates = initialBeliefIsTerminal ? 1ull : 0ull;
140 uint64_t const numExtraStates = numBottomTargetStates + frontierBeliefs.size() + numInitialTerminalStates;
141 uint64_t const numStates = explorationInformation.matrix.groups() + numExtraStates;
142 uint64_t const numChoices = explorationInformation.matrix.rows() + numBottomTargetStates + nrCutOffChoices + numInitialTerminalStates;
143 uint64_t const targetState = numStates - numBottomTargetStates;
144 uint64_t const bottomState = numStates - 1;
145 std::optional<models::sparse::ChoiceLabeling> optionalChoiceLabeling;
146 if (explorationInformation.matrix.hasChoiceLabels()) {
147 optionalChoiceLabeling = models::sparse::ChoiceLabeling(numChoices);
148 }
149
150 std::vector<BeliefMdpValueType> actionRewards;
151 if (isTotRew) {
152 actionRewards.reserve(numChoices);
153 actionRewards.insert(actionRewards.end(), explorationInformation.actionRewards.begin(), explorationInformation.actionRewards.end());
154 // Insert 0 for all cut-off choices, an optional initial terminal state, and bottom/target states.
155 actionRewards.insert(actionRewards.end(), nrCutOffChoices + numInitialTerminalStates + numBottomTargetStates,
157 STORM_LOG_ASSERT(numChoices == actionRewards.size(),
158 "Unexpected size of action rewards: Expected " << numChoices << " got " << actionRewards.size() << ".");
159 }
160
161 std::unordered_map<BeliefId, uint64_t> frontierBeliefToStateMap;
162 std::unordered_map<uint64_t, BeliefId> stateToFrontierBeliefMap;
163 uint64_t nextStateId = numStates - numExtraStates;
164 std::optional<uint64_t> initialTerminalState;
165 if (initialBeliefIsTerminal) {
166 initialTerminalState = nextStateId++;
167 }
168 for (auto const& frontierBeliefId : frontierBeliefs) {
169 frontierBeliefToStateMap.emplace(frontierBeliefId, nextStateId);
170 stateToFrontierBeliefMap.emplace(nextStateId, frontierBeliefId);
171 ++nextStateId;
172 }
173 STORM_LOG_ASSERT(nextStateId == targetState, "Unexpected state layout.");
174
175 std::vector<storm::storage::SparseMatrixBuilder<BeliefMdpValueType>> transitionRewardBuilderVector;
176
177 if constexpr (extraDataCompatibleWithRewardAwareness) {
178 if (isRewBndReachProb) {
179 for (uint64_t i = 0; i < propertyInformation.rewardBounds.size(); ++i) {
180 transitionRewardBuilderVector.emplace_back(numChoices, numStates, 0, true, true, numStates);
181 }
182 }
183 }
184
185 storm::storage::SparseMatrixBuilder<BeliefMdpValueType> transitionBuilder(numChoices, numStates, 0, true, true, numStates);
186 // Keep source indices so probabilities and reward vectors share the same successor ordering without copying the data.
187 std::vector<std::pair<uint64_t, uint64_t>> rowSuccessors;
188 // Treat explored beliefs
189 for (uint64_t state = 0; state < numStates - numExtraStates; ++state) {
190 uint64_t choice = explorationInformation.matrix.rowGroupIndices[state];
191 transitionBuilder.newRowGroup(choice);
192 for (auto& transitionRewardBuilder : transitionRewardBuilderVector) {
193 transitionRewardBuilder.newRowGroup(choice);
194 }
195 for (uint64_t const groupEnd = explorationInformation.matrix.rowGroupIndices[state + 1]; choice < groupEnd; ++choice) {
196 if constexpr (extraDataCompatibleWithRewardAwareness) {
198 !isRewBndReachProb || hasUniqueTransitionRewardsInChoice(explorationInformation.matrix, choice, propertyInformation.rewardBounds.size()),
199 "Duplicate transition reward in choice " << choice << ".");
200 }
201 auto probabilityToBottom = storm::utility::zero<BeliefMdpValueType>();
202 auto probabilityToTarget = storm::utility::zero<BeliefMdpValueType>();
203 rowSuccessors.clear();
204 for (uint64_t entryIndex = explorationInformation.matrix.rowIndications[choice];
205 entryIndex < explorationInformation.matrix.rowIndications[choice + 1]; ++entryIndex) {
206 auto const& entry = explorationInformation.matrix.transitions[entryIndex];
207 if (auto explIt = explorationInformation.exploredBeliefs.find(entry.targetBelief); explIt != explorationInformation.exploredBeliefs.end()) {
208 // Transition to explored belief
209 rowSuccessors.emplace_back(explIt->second, entryIndex);
210 } else {
211 // Transition to unexplored belief (either terminal or cut-off)
212 BeliefMdpValueType successorValue;
213 // Reward-aware exploration never inserts terminal beliefs: whether a target observation satisfies a
214 // reward bound depends on the transition reward. Those beliefs stay explored or on the frontier.
215 if (auto terminalIt = explorationInformation.terminalBeliefValues.find(entry.targetBelief);
216 // Transition to terminal belief
217 terminalIt != explorationInformation.terminalBeliefValues.end()) {
218 successorValue = entry.probability * terminalIt->second; // terminal value determined during exploration
219 if (isReachProb) {
220 probabilityToTarget += successorValue;
221 probabilityToBottom += entry.probability - successorValue;
222 } else {
223 STORM_LOG_THROW(isTotRew, storm::exceptions::UnexpectedException,
224 "Terminal reward accumulation requires an expected total reachability reward property.");
225 probabilityToTarget += entry.probability;
226 actionRewards[choice] += successorValue;
227 }
228 } else {
229 // Transition to frontier belief
230 auto const frontierIt = frontierBeliefToStateMap.find(entry.targetBelief);
231 STORM_LOG_ASSERT(frontierIt != frontierBeliefToStateMap.end(), "Unknown frontier belief.");
232 rowSuccessors.emplace_back(frontierIt->second, entryIndex);
233 }
234 }
235 if constexpr (clippingUsed) {
236 // Apply clipping metadata regardless of whether the successor is explored, terminal, or on the frontier.
237 auto const& clippingProbability = std::get<0>(entry.data);
238 auto const& rewardPenalty = std::get<1>(entry.data);
239
240 if (clippingProbability) {
241 if (isReachProb) {
242 if (storm::solver::minimize(propertyInformation.dir)) {
243 probabilityToTarget += *clippingProbability;
244 } else {
245 probabilityToBottom += *clippingProbability;
246 }
247 } else if (rewardPenalty) {
248 if (storm::utility::isInfinity(*rewardPenalty)) {
249 /* Infinite reward on transitions is not correctly handled by the model checker. Therefore, we treat it by adding a
250 * transition to the bottom state which due to the semantics of expected reward until reaching a target has infinite
251 * expected reward.This causes the expected reward for the transition to become infinite. */
252 probabilityToBottom += *clippingProbability;
253 } else {
254 actionRewards[choice] += *rewardPenalty;
255 probabilityToTarget += *clippingProbability;
256 }
257 } else {
258 probabilityToTarget += *clippingProbability;
259 }
260 }
261 }
262 }
263 // Sort each choice once by its final state IDs, preserving source order for duplicate successors.
264 if (!std::is_sorted(rowSuccessors.begin(), rowSuccessors.end())) {
265 std::sort(rowSuccessors.begin(), rowSuccessors.end());
266 }
267 for (auto const& [successorState, entryIndex] : rowSuccessors) {
268 auto const& entry = explorationInformation.matrix.transitions[entryIndex];
269 transitionBuilder.addNextValue(choice, successorState, entry.probability);
270 if constexpr (extraDataCompatibleWithRewardAwareness) {
271 if (isRewBndReachProb) {
272 for (uint64_t i = 0; i < propertyInformation.rewardBounds.size(); ++i) {
273 if (!storm::utility::isZero(entry.data[i])) {
274 transitionRewardBuilderVector.at(i).addNextValue(choice, successorState, entry.data[i]);
275 }
276 }
277 }
278 }
279 }
280 // Sink state IDs follow all ordinary successors, so these insertions remain ordered.
281 if (!storm::utility::isZero(probabilityToTarget)) {
282 transitionBuilder.addNextValue(choice, targetState, probabilityToTarget);
283 }
284 if (!storm::utility::isZero(probabilityToBottom)) {
285 transitionBuilder.addNextValue(choice, bottomState, probabilityToBottom);
286 }
287 if (optionalChoiceLabeling.has_value()) {
288 for (auto const& label : explorationInformation.matrix.choiceLabels.at(choice)) {
289 if (!optionalChoiceLabeling.value().containsLabel(label)) {
290 optionalChoiceLabeling.value().addLabel(label);
291 }
292 optionalChoiceLabeling.value().addLabelToChoice(label, choice);
293 }
294 }
295 }
296 }
297 // Treat frontier beliefs
298 uint64_t choice = explorationInformation.matrix.rows();
299 uint64_t const firstFrontierState = numStates - numExtraStates + numInitialTerminalStates;
300 for (uint64_t state = firstFrontierState; state < numStates - numBottomTargetStates; ++state) {
301 transitionBuilder.newRowGroup(choice);
302 for (auto& transitionRewardBuilder : transitionRewardBuilderVector) {
303 transitionRewardBuilder.newRowGroup(choice);
304 }
305 std::unordered_map<std::string, BeliefMdpValueType> cutOffInformationForBelief = cutOffInformationMap.at(stateToFrontierBeliefMap.at(state));
306 for (auto const& entry : cutOffInformationForBelief) {
307 if (isReachProb || isRewBndReachProb) {
308 if (!storm::utility::isZero(entry.second)) {
309 transitionBuilder.addNextValue(choice, targetState, entry.second);
310 }
311 BeliefMdpValueType const probabilityToBottom = storm::utility::one<BeliefMdpValueType>() - entry.second;
312 if (!storm::utility::isZero(probabilityToBottom)) {
313 transitionBuilder.addNextValue(choice, bottomState, probabilityToBottom);
314 }
315 } else {
316 transitionBuilder.addNextValue(choice, targetState, storm::utility::one<BeliefMdpValueType>());
317 if (isTotRew) {
318 actionRewards[choice] += entry.second;
319 }
320 }
321 if (optionalChoiceLabeling.has_value()) {
322 if (!optionalChoiceLabeling.value().containsLabel(entry.first)) {
323 optionalChoiceLabeling.value().addLabel(entry.first);
324 }
325 optionalChoiceLabeling.value().addLabelToChoice(entry.first, choice);
326 }
327 ++choice;
328 }
329 }
330 if (initialTerminalState.has_value()) {
331 transitionBuilder.newRowGroup(choice);
332 BeliefMdpValueType const terminalValue = explorationInformation.terminalBeliefValues.at(explorationInformation.initialBeliefId);
333 if (isReachProb) {
334 if (!storm::utility::isZero(terminalValue)) {
335 transitionBuilder.addNextValue(choice, targetState, terminalValue);
336 }
337 BeliefMdpValueType const probabilityToBottom = storm::utility::one<BeliefMdpValueType>() - terminalValue;
338 if (!storm::utility::isZero(probabilityToBottom)) {
339 transitionBuilder.addNextValue(choice, bottomState, probabilityToBottom);
340 }
341 } else {
342 STORM_LOG_ASSERT(isTotRew, "Unexpected terminal initial belief for this property type.");
343 transitionBuilder.addNextValue(choice, targetState, storm::utility::one<BeliefMdpValueType>());
344 actionRewards[choice] += terminalValue;
345 }
346 ++choice;
347 }
348 STORM_LOG_ASSERT(choice == numChoices - numBottomTargetStates, "Unexpected choice layout.");
349
350 // Treat extra states
351 transitionBuilder.newRowGroup(numChoices - numBottomTargetStates);
352 if (optionalChoiceLabeling.has_value()) {
353 if (!optionalChoiceLabeling.value().containsLabel("__loop__")) {
354 optionalChoiceLabeling.value().addLabel("__loop__");
355 }
356 optionalChoiceLabeling.value().addLabelToChoice("__loop__", numChoices - numBottomTargetStates);
357 }
358 transitionBuilder.addNextValue(numChoices - numBottomTargetStates, targetState, storm::utility::one<BeliefMdpValueType>());
359 for (uint64_t i = 0; i < transitionRewardBuilderVector.size(); ++i) {
360 auto& transitionRewardBuilder = transitionRewardBuilderVector[i];
361 transitionRewardBuilder.newRowGroup(numChoices - numBottomTargetStates);
362 // Optimistic Pmin cut-offs must eventually satisfy every lower bound without consuming upper-only budgets.
363 if (propertyInformation.dir == storm::OptimizationDirection::Minimize && propertyInformation.rewardBounds[i].lowerBound.has_value()) {
364 transitionRewardBuilder.addNextValue(numChoices - numBottomTargetStates, targetState, storm::utility::one<BeliefMdpValueType>());
365 }
366 }
367 if (isReachProb || isRewBndReachProb || clippingUsed) {
368 transitionBuilder.newRowGroup(numChoices - 1);
369 transitionBuilder.addNextValue(numChoices - 1, bottomState, storm::utility::one<BeliefMdpValueType>());
370 for (auto& transitionRewardBuilder : transitionRewardBuilderVector) {
371 transitionRewardBuilder.newRowGroup(numChoices - 1);
372 }
373 if (optionalChoiceLabeling.has_value()) {
374 if (!optionalChoiceLabeling.value().containsLabel("__loop__")) {
375 optionalChoiceLabeling.value().addLabel("__loop__");
376 }
377 optionalChoiceLabeling.value().addLabelToChoice("__loop__", numChoices - 1);
378 }
379 }
380
381 storm::models::sparse::StateLabeling stateLabeling(numStates);
382 stateLabeling.addLabel("target");
383 if (isRewBndReachProb) {
384 stateLabeling.addLabelToState("target", targetState);
385 // A belief observation may encode an action observation as actionObservation * nrObservationsInPomdp + pomdpObservation.
386 // The modulo recovers the current POMDP observation ID, which is also the ID stored in targetObservations.
387 // After reward-aware transformation, that ID identifies a (target observation, reward vector) pair.
388 for (auto const& [belId, state] : explorationInformation.exploredBeliefs) {
389 if (propertyInformation.targetObservations.contains(explorationInformation.discoveredBeliefs.getBeliefFromId(belId).observation() %
390 explorationInformation.nrObservationsInPomdp)) {
391 stateLabeling.addLabelToState("target", state);
392 }
393 }
394 for (auto const& belId : frontierBeliefs) {
395 if (propertyInformation.targetObservations.contains(explorationInformation.discoveredBeliefs.getBeliefFromId(belId).observation() %
396 explorationInformation.nrObservationsInPomdp)) {
397 stateLabeling.addLabelToState("target", frontierBeliefToStateMap.at(belId));
398 }
399 }
400 } else {
401 stateLabeling.addLabelToState("target", targetState);
402 }
403 stateLabeling.addLabel("init");
404 if (auto const initialExploredIt = explorationInformation.exploredBeliefs.find(explorationInformation.initialBeliefId);
405 initialExploredIt != explorationInformation.exploredBeliefs.end()) {
406 stateLabeling.addLabelToState("init", initialExploredIt->second);
407 } else if (initialTerminalState.has_value()) {
408 stateLabeling.addLabelToState("init", initialTerminalState.value());
409 } else {
410 stateLabeling.addLabelToState("init", frontierBeliefToStateMap.at(explorationInformation.initialBeliefId));
411 }
412 stateLabeling.addLabel("truncated");
413 for (uint64_t state = firstFrontierState; state < numStates - numBottomTargetStates; ++state) {
414 stateLabeling.addLabelToState("truncated", state);
415 }
416
417 if (isReachProb || isRewBndReachProb || clippingUsed) {
418 stateLabeling.addLabel("bottom");
419 stateLabeling.addLabelToState("bottom", bottomState);
420 }
421 storm::storage::sparse::ModelComponents<BeliefMdpValueType> components(transitionBuilder.build(), std::move(stateLabeling));
422
423 if (isTotRew) {
424 storm::models::sparse::StandardRewardModel<BeliefMdpValueType> rewardModel(std::nullopt, std::move(actionRewards));
425 components.rewardModels.emplace(propertyInformation.rewardModelName.value(), std::move(rewardModel));
426 } else if (isRewBndReachProb) {
427 uint64_t i = 0ul;
428 for (auto& transitionRewardBuilder : transitionRewardBuilderVector) {
429 storm::models::sparse::StandardRewardModel<BeliefMdpValueType> rewardModel(std::nullopt, std::nullopt, transitionRewardBuilder.build());
430 components.rewardModels.emplace(propertyInformation.rewardBounds.at(i).rewardModelName, std::move(rewardModel));
431 ++i;
432 }
433 }
434 if (optionalChoiceLabeling.has_value()) {
435 components.choiceLabeling = optionalChoiceLabeling.value();
436 }
437
438 // If requested, populate the stateToBeliefMap for the generic buildBeliefMdp variant
439 std::unordered_map<uint64_t, BeliefId> stateToBeliefMap;
440 // Explored beliefs
441 for (auto const& [beliefId, stateIndex] : explorationInformation.exploredBeliefs) {
442 stateToBeliefMap[stateIndex] = beliefId;
443 }
444 // Frontier beliefs: mapping was built as stateToFrontierBeliefMap
445 for (auto const& [stateIndex, beliefId] : stateToFrontierBeliefMap) {
446 stateToBeliefMap[stateIndex] = beliefId;
447 }
448 if (initialTerminalState.has_value()) {
449 stateToBeliefMap[initialTerminalState.value()] = explorationInformation.initialBeliefId;
450 }
451
452 return std::make_pair(std::make_shared<storm::models::sparse::Mdp<BeliefMdpValueType>>(std::move(components)), std::move(stateToBeliefMap));
453}
454
455template std::pair<std::shared_ptr<models::sparse::Mdp<double>>, std::unordered_map<uint64_t, BeliefId>> buildBeliefMdp(
456 ExplorationInformation<double, Belief<double>> const& explorationInformation, PropertyInformation const& propertyInformation,
457 std::function<std::unordered_map<std::string, double>(Belief<double> const&)> const& computeCutOffValueMap);
458
459template std::pair<std::shared_ptr<models::sparse::Mdp<storm::RationalNumber>>, std::unordered_map<uint64_t, BeliefId>> buildBeliefMdp(
460 ExplorationInformation<storm::RationalNumber, Belief<double>> const& explorationInformation, PropertyInformation const& propertyInformation,
461 std::function<std::unordered_map<std::string, storm::RationalNumber>(Belief<double> const&)> const& computeCutOffValueMap);
462
463template std::pair<std::shared_ptr<models::sparse::Mdp<double>>, std::unordered_map<uint64_t, BeliefId>> buildBeliefMdp(
464 ExplorationInformation<double, Belief<storm::RationalNumber>> const& explorationInformation, PropertyInformation const& propertyInformation,
465 std::function<std::unordered_map<std::string, double>(Belief<storm::RationalNumber> const&)> const& computeCutOffValueMap);
466
467template std::pair<std::shared_ptr<models::sparse::Mdp<storm::RationalNumber>>, std::unordered_map<uint64_t, BeliefId>> buildBeliefMdp(
468 ExplorationInformation<storm::RationalNumber, Belief<storm::RationalNumber>> const& explorationInformation, PropertyInformation const& propertyInformation,
469 std::function<std::unordered_map<std::string, storm::RationalNumber>(Belief<storm::RationalNumber> const&)> const& computeCutOffValueMap);
470
471template std::pair<std::shared_ptr<models::sparse::Mdp<double>>, std::unordered_map<uint64_t, BeliefId>> buildBeliefMdp(
472 ClippingExplorationInformation<double, Belief<double>> const& explorationInformation, PropertyInformation const& propertyInformation,
473 std::function<std::unordered_map<std::string, double>(Belief<double> const&)> const& computeCutOffValueMap);
474
475template std::pair<std::shared_ptr<models::sparse::Mdp<storm::RationalNumber>>, std::unordered_map<uint64_t, BeliefId>> buildBeliefMdp(
476 ClippingExplorationInformation<storm::RationalNumber, Belief<double>> const& explorationInformation, PropertyInformation const& propertyInformation,
477 std::function<std::unordered_map<std::string, storm::RationalNumber>(Belief<double> const&)> const& computeCutOffValueMap);
478
479template std::pair<std::shared_ptr<models::sparse::Mdp<double>>, std::unordered_map<uint64_t, BeliefId>> buildBeliefMdp(
480 ClippingExplorationInformation<double, Belief<storm::RationalNumber>> const& explorationInformation, PropertyInformation const& propertyInformation,
481 std::function<std::unordered_map<std::string, double>(Belief<storm::RationalNumber> const&)> const& computeCutOffValueMap);
482
483template std::pair<std::shared_ptr<models::sparse::Mdp<storm::RationalNumber>>, std::unordered_map<uint64_t, BeliefId>> buildBeliefMdp(
484 ClippingExplorationInformation<storm::RationalNumber, Belief<storm::RationalNumber>> const& explorationInformation,
485 PropertyInformation const& propertyInformation,
486 std::function<std::unordered_map<std::string, storm::RationalNumber>(Belief<storm::RationalNumber> const&)> const& computeCutOffValueMap);
487
488template std::pair<std::shared_ptr<models::sparse::Mdp<double>>, std::unordered_map<uint64_t, BeliefId>> buildBeliefMdp(
489 RewardAwareExplorationInformation<double, Belief<double>> const& explorationInformation, PropertyInformation const& propertyInformation,
490 std::function<std::unordered_map<std::string, double>(Belief<double> const&)> const& computeCutOffValueMap);
491
492template std::pair<std::shared_ptr<models::sparse::Mdp<storm::RationalNumber>>, std::unordered_map<uint64_t, BeliefId>> buildBeliefMdp(
493 RewardAwareExplorationInformation<storm::RationalNumber, Belief<double>> const& explorationInformation, PropertyInformation const& propertyInformation,
494 std::function<std::unordered_map<std::string, storm::RationalNumber>(Belief<double> const&)> const& computeCutOffValueMap);
495
496template std::pair<std::shared_ptr<models::sparse::Mdp<double>>, std::unordered_map<uint64_t, BeliefId>> buildBeliefMdp(
497 RewardAwareExplorationInformation<double, Belief<storm::RationalNumber>> const& explorationInformation, PropertyInformation const& propertyInformation,
498 std::function<std::unordered_map<std::string, double>(Belief<storm::RationalNumber> const&)> const& computeCutOffValueMap);
499
500template std::pair<std::shared_ptr<models::sparse::Mdp<storm::RationalNumber>>, std::unordered_map<uint64_t, BeliefId>> buildBeliefMdp(
501 RewardAwareExplorationInformation<storm::RationalNumber, Belief<storm::RationalNumber>> const& explorationInformation,
502 PropertyInformation const& propertyInformation,
503 std::function<std::unordered_map<std::string, storm::RationalNumber>(Belief<storm::RationalNumber> const&)> const& computeCutOffValueMap);
504} // namespace storm::pomdp::beliefs
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.
This class represents a (discrete-time) Markov decision process.
Definition Mdp.h:16
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.
std::vector< uint64_t > rowIndications
Start indices of action rows in transitions.
std::vector< BeliefExplorationTransition< ValueType, ExtraTransitionData... > > transitions
Successor entries, grouped by rowIndications.
std::vector< uint64_t > rowGroupIndices
Start indices of belief row groups in the action rows.
std::vector< std::set< std::string > > choiceLabels
Optional labels for the action rows.
Represents a belief of a Pomdp, i.e.
Definition Belief.h:21
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)
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:39
bool hasUniqueTransitionRewardsInChoice(MatrixType const &matrix, uint64_t choice, uint64_t numRewardModels)
std::shared_ptr< storm::logic::Formula const > createFormulaForBeliefMdp(PropertyInformation const &propertyInformation)
ExplorationInformation< BeliefMdpValueType, BeliefType, std::optional< BeliefMdpValueType >, std::optional< BeliefMdpValueType > > ClippingExplorationInformation
Exploration information that stores optional clipping probability and reward-adjustment metadata.
std::pair< std::shared_ptr< models::sparse::Mdp< BeliefMdpValueType > >, std::unordered_map< uint64_t, BeliefId > > buildBeliefMdp(ExplorationInformation< BeliefMdpValueType, BeliefType, ExtraTransitionData... > const &explorationInformation, PropertyInformation const &propertyInformation, std::function< std::unordered_map< std::string, BeliefMdpValueType >(BeliefType const &)> const &computeCutOffValueMap)
Builds a belief MDP from the given exploration information and property information.
ExplorationInformation< BeliefMdpValueType, BeliefType, std::vector< BeliefMdpValueType > > RewardAwareExplorationInformation
Exploration information that stores a reward vector on each transition.
bool constexpr minimize(OptimizationDirection d)
bool isZero(ValueType const &a)
Definition constants.cpp:44
ValueType zero()
Definition constants.cpp:26
ValueType one()
Definition constants.cpp:21
bool isInfinity(ValueType const &a)
Mutable state of one belief-MDP exploration.
storm::pomdp::beliefs::BeliefCollector< BeliefType > discoveredBeliefs
std::vector< BeliefMdpValueType > actionRewards
BeliefExplorationMatrix< BeliefMdpValueType, ExtraTransitionData... > matrix
std::unordered_set< BeliefId > getFrontierBeliefs() const
std::unordered_map< BeliefId, BeliefStateType > exploredBeliefs
std::unordered_map< BeliefId, BeliefMdpValueType > terminalBeliefValues
Property data consumed by the belief MDP construction.
std::set< BeliefObservationType > targetObservations
One reward dimension of a reward-bounded reachability property.
std::unordered_map< std::string, RewardModelType > rewardModels
std::optional< storm::models::sparse::ChoiceLabeling > choiceLabeling