Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
FreudenthalTriangulationBeliefAbstraction.h
Go to the documentation of this file.
1#pragma once
2
3#include <vector>
4
10
11namespace storm::pomdp::beliefs {
14
27template<typename BeliefType>
29 public:
30 using BeliefValueType = typename BeliefType::ValueType;
31
34
40 template<typename AbstractCallback>
41 void abstract(BeliefType&& belief, BeliefValueType&& probabilityFactor, AbstractCallback const& callback) const {
42 // Quickly triangulate Dirac beliefs
43 if (belief.size() == 1u) {
44 callback(std::move(belief), std::move(probabilityFactor));
45 } else {
46 auto observationResolutionFindRes = observationResolutions.find(belief.observation());
47 auto observationResolution =
48 observationResolutionFindRes != observationResolutions.end() ? observationResolutionFindRes->second : defaultResolution;
49 switch (mode) {
51 abstractStatic(probabilityFactor, belief, callback, observationResolution);
52 break;
54 abstractDynamic(probabilityFactor, belief, callback, observationResolution);
55 break;
56 default:
57 STORM_LOG_ASSERT(false, "Invalid triangulation mode.");
58 }
59 }
60 }
61
62 private:
63 template<typename AbstractCallback>
64 void abstractStatic(BeliefValueType const& probabilityFactor, BeliefType const& belief, AbstractCallback& callback,
65 BeliefValueType const& staticResolution) const {
66 struct FreudenthalDiff {
67 BeliefValueType diff; // d[i]
68 BeliefStateType dimension; // i
69 bool operator>(FreudenthalDiff const& other) const {
70 if (diff != other.diff) {
71 return diff > other.diff;
72 } else {
73 return dimension < other.dimension;
74 }
75 }
76 };
77
78 STORM_LOG_ASSERT(storm::utility::isInteger(staticResolution), "Expected an integer resolution");
79 STORM_LOG_ASSERT(staticResolution > 0, "Expected a positive resolution");
80 BeliefStateType numEntries = belief.size();
81 // This is the Freudenthal Triangulation as described in Lovejoy (a whole lotta math)
82 // Probabilities will be triangulated to values in 0/N, 1/N, 2/N, ..., N/N
83 // Variable names are mostly based on the paper
84 // However, we speed this up a little by exploiting that belief states usually have sparse support (i.e. numEntries is much smaller than
85 // pomdp.getNumberOfStates()). Initialize diffs and the first row of the 'qs' matrix (aka v)
86 std::set<FreudenthalDiff, std::greater<>> sorted_diffs; // d (and p?) in the paper
87 std::vector<BeliefValueType> qsRow; // Row of the 'qs' matrix from the paper (initially corresponds to v
88 qsRow.reserve(numEntries);
89 std::vector<BeliefStateType> toOriginalIndicesMap; // Maps 'local' indices to the original pomdp state indices
90 toOriginalIndicesMap.reserve(numEntries);
91 BeliefValueType x = staticResolution;
92 belief.forEach([&qsRow, &sorted_diffs, &toOriginalIndicesMap, &x, &staticResolution](auto const& state, auto const& value) {
93 qsRow.push_back(storm::utility::floor(x)); // v
94 sorted_diffs.insert(FreudenthalDiff({x - qsRow.back(), toOriginalIndicesMap.size()})); // x-v
95 toOriginalIndicesMap.push_back(state);
96 x -= value * staticResolution;
97 });
98 // Insert a dummy 0 column in the qs matrix so the loops below are a bit simpler
100
101 auto currentSortedDiff = sorted_diffs.begin();
102 auto previousSortedDiff = sorted_diffs.end();
103 --previousSortedDiff;
104 for (BeliefStateType i = 0; i < numEntries; ++i) {
105 // Compute the weight for the grid points
106 BeliefValueType weight = previousSortedDiff->diff - currentSortedDiff->diff;
107 if (i == 0) {
108 // The first weight is a bit different
110 } else {
111 // 'compute' the next row of the qs matrix
112 qsRow[previousSortedDiff->dimension] += storm::utility::one<BeliefValueType>();
113 }
115 // build the grid point
116 BeliefBuilder<BeliefType> builder;
117 builder.reserve(numEntries);
118 builder.setObservation(belief.observation());
119 for (BeliefStateType j = 0; j < numEntries; ++j) {
120 BeliefValueType gridPointEntry = qsRow[j] - qsRow[j + 1];
121 if (!BeliefNumerics<BeliefValueType>::isZero(gridPointEntry)) {
122 builder.addValue(toOriginalIndicesMap[j], gridPointEntry / staticResolution);
123 }
124 }
125 callback(builder.build(), static_cast<BeliefValueType>(weight * probabilityFactor));
126 }
127 previousSortedDiff = currentSortedDiff++;
128 }
129 }
130
131 template<typename AbstractCallback>
132 void abstractDynamic(BeliefValueType const& probabilityFactor, BeliefType const& belief, AbstractCallback& callback,
133 BeliefValueType const& maxResolution) const {
134 // Find the best resolution for this belief, i.e., N such that the largest distance between one of the belief values to a value in {i/N | 0 ≤ i ≤ N} is
135 // minimal
136 STORM_LOG_ASSERT(storm::utility::isInteger(maxResolution), "Expected an integer resolution");
137 BeliefValueType const halfResolution = maxResolution / storm::utility::convertNumber<BeliefValueType, uint64_t>(2);
138 BeliefValueType const initialDist = storm::utility::one<BeliefValueType>() / maxResolution;
139 // We take 1/maxResolution as initial distance. This means that coarser maxResolution are only chosen if they are clearly better suited for the given
140 // belief.
141
142 BeliefValueType resolution = maxResolution;
143 BeliefValueType resolutionDist = initialDist;
144 // We don't need to check resolutions that are smaller than the maximal resolution divided by 2 as we already checked multiples of these
145 for (BeliefValueType currResolution = maxResolution; currResolution > halfResolution; --currResolution) {
147 bool const newBest = belief.allOf([&currDist, &currResolution, &resolutionDist](BeliefStateType const&, BeliefValueType const& val) {
148 currDist += storm::utility::abs<BeliefValueType>(val - storm::utility::round<BeliefValueType>(val * currResolution) / currResolution);
149 return currDist <= resolutionDist; // continue as long as the current dist is still smaller than the smallest dist
150 });
151 if (newBest) {
152 STORM_LOG_ASSERT(currDist <= resolutionDist, "Expected a smaller resolution");
153 resolution = currResolution;
154 resolutionDist = currDist;
155 if (BeliefNumerics<BeliefValueType>::isZero(resolutionDist)) {
156 break;
157 }
158 }
159 }
160 abstractStatic(probabilityFactor, belief, callback, resolution);
161 }
162
163 private:
164 BeliefValueType const defaultResolution;
166 std::map<BeliefObservationType, BeliefValueType> observationResolutions;
167};
168} // namespace storm::pomdp::beliefs
FreudenthalTriangulationBeliefAbstraction(BeliefValueType const &initialResolution, FreudenthalTriangulationMode mode)
Creates an abstraction with the default grid resolution and resolution-selection mode.
void abstract(BeliefType &&belief, BeliefValueType &&probabilityFactor, AbstractCallback const &callback) const
Emits the grid beliefs and weights whose convex combination represents belief.
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
FreudenthalTriangulationMode
Selects a fixed grid resolution or a suitable coarser resolution per belief.
uint64_t BeliefStateType
Shared identifiers and sparse-container types used by the belief subsystem.
Definition types.h:10
ValueType floor(ValueType const &number)
bool isInteger(ValueType const &number)
ValueType abs(ValueType const &number)
ValueType zero()
Definition constants.cpp:26
ValueType one()
Definition constants.cpp:21
ValueType round(ValueType const &number)
TargetType convertNumber(SourceType const &number)
static bool isZero(ValueType const &val)