Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
PomdpMemoryUnfolder.cpp
Go to the documentation of this file.
2
3#include <limits>
4
9
10namespace storm {
11namespace transformer {
12
13template<typename ValueType>
15 bool addMemoryLabels, bool keepStateValuations)
16 : pomdp(pomdp), memory(memory), addMemoryLabels(addMemoryLabels), keepStateValuations(keepStateValuations) {
17 // intentionally left empty
18}
19
20template<typename ValueType>
21std::shared_ptr<storm::models::sparse::Pomdp<ValueType>> PomdpMemoryUnfolder<ValueType>::transform(bool dropUnreachableStates) const {
22 // For simplicity we first build the 'full' product of pomdp and memory (with pomdp.numStates * memory.numStates states).
23 STORM_LOG_THROW(pomdp.isCanonic(), storm::exceptions::InvalidArgumentException, "POMDP must be canonical to unfold memory into it");
25 components.transitionMatrix = transformTransitions();
26 components.stateLabeling = transformStateLabeling();
27
28 // Now delete unreachable states.
29 storm::storage::BitVector allStates(components.transitionMatrix.getRowGroupCount(), true);
30
31 storm::storage::BitVector reachableStates = allStates;
32 if (dropUnreachableStates) {
33 reachableStates =
34 storm::utility::graph::getReachableStates(components.transitionMatrix, components.stateLabeling.getStates("init"), allStates, ~allStates);
35 components.transitionMatrix = components.transitionMatrix.getSubmatrix(true, reachableStates, reachableStates);
36 components.stateLabeling = components.stateLabeling.getSubLabeling(reachableStates);
37 if (keepStateValuations && pomdp.hasStateValuations()) {
38 std::vector<uint64_t> newToOldStates(pomdp.getNumberOfStates() * memory.getNumberOfStates(), 0);
39 for (uint64_t newState = 0; newState < newToOldStates.size(); newState++) {
40 newToOldStates[newState] = getModelState(newState);
41 }
42 components.stateValuations = pomdp.getStateValuations().blowup(newToOldStates).selectStates(reachableStates);
43 }
44 }
45
46 // build the remaining components
47 components.observabilityClasses = transformObservabilityClasses(reachableStates);
48 for (auto const& rewModel : pomdp.getRewardModels()) {
49 components.rewardModels.emplace(rewModel.first, transformRewardModel(rewModel.second, reachableStates));
50 }
51
52 return std::make_shared<storm::models::sparse::Pomdp<ValueType>>(std::move(components), true);
53}
54
55template<typename ValueType>
57 storm::storage::SparseMatrix<ValueType> const& origTransitions = pomdp.getTransitionMatrix();
58 uint64_t numRows = 0;
59 uint64_t numEntries = 0;
60 for (uint64_t modelState = 0; modelState < pomdp.getNumberOfStates(); ++modelState) {
61 for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) {
62 numRows += origTransitions.getRowGroupSize(modelState) * memory.getNumberOfOutgoingTransitions(memState);
63 numEntries += origTransitions.getRowGroup(modelState).getNumberOfEntries() * memory.getNumberOfOutgoingTransitions(memState);
64 }
65 }
66 storm::storage::SparseMatrixBuilder<ValueType> builder(numRows, pomdp.getNumberOfStates() * memory.getNumberOfStates(), numEntries, true, true,
67 pomdp.getNumberOfStates() * memory.getNumberOfStates());
68
69 uint64_t row = 0;
70 for (uint64_t modelState = 0; modelState < pomdp.getNumberOfStates(); ++modelState) {
71 for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) {
72 builder.newRowGroup(row);
73 for (uint64_t origRow = origTransitions.getRowGroupIndices()[modelState]; origRow < origTransitions.getRowGroupIndices()[modelState + 1];
74 ++origRow) {
75 for (auto const& memStatePrime : memory.getTransitions(memState)) {
76 for (auto const& entry : origTransitions.getRow(origRow)) {
77 builder.addNextValue(row, getUnfoldingState(entry.getColumn(), memStatePrime), entry.getValue());
78 }
79 ++row;
80 }
81 }
82 }
83 }
84 return builder.build();
85}
86
87template<typename ValueType>
88storm::models::sparse::StateLabeling PomdpMemoryUnfolder<ValueType>::transformStateLabeling() const {
89 storm::models::sparse::StateLabeling labeling(pomdp.getNumberOfStates() * memory.getNumberOfStates());
90 for (auto const& labelName : pomdp.getStateLabeling().getLabels()) {
91 storm::storage::BitVector newStates(pomdp.getNumberOfStates() * memory.getNumberOfStates(), false);
92
93 // The init label is only assigned to unfolding states with the initial memory state
94 if (labelName == "init") {
95 for (auto const& modelState : pomdp.getStateLabeling().getStates(labelName)) {
96 newStates.set(getUnfoldingState(modelState, memory.getInitialState()));
97 }
98 } else {
99 for (auto const& modelState : pomdp.getStateLabeling().getStates(labelName)) {
100 for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) {
101 newStates.set(getUnfoldingState(modelState, memState));
102 }
103 }
104 }
105 labeling.addLabel(labelName, std::move(newStates));
106 }
107 if (addMemoryLabels) {
108 for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) {
109 storm::storage::BitVector newStates(pomdp.getNumberOfStates() * memory.getNumberOfStates(), false);
110 for (uint64_t modelState = 0; modelState < pomdp.getNumberOfStates(); ++modelState) {
111 newStates.set(getUnfoldingState(modelState, memState));
112 }
113 labeling.addLabel("memstate_" + std::to_string(memState), newStates);
114 }
115 }
116 return labeling;
117}
118
119template<typename ValueType>
120std::vector<uint32_t> PomdpMemoryUnfolder<ValueType>::transformObservabilityClasses(storm::storage::BitVector const& reachableStates) const {
121 std::vector<uint32_t> observations;
122 observations.reserve(pomdp.getNumberOfStates() * memory.getNumberOfStates());
123 for (uint64_t modelState = 0; modelState < pomdp.getNumberOfStates(); ++modelState) {
124 for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) {
125 if (reachableStates.get(getUnfoldingState(modelState, memState))) {
126 observations.push_back(getUnfoldingObersvation(pomdp.getObservation(modelState), memState));
127 }
128 }
129 }
130
131 // Eliminate observations that are not in use (as they are not reachable).
132 std::set<uint32_t> occuringObservations(observations.begin(), observations.end());
133 uint32_t highestObservation = *occuringObservations.rbegin();
134 std::vector<uint32_t> oldToNewObservationMapping(highestObservation + 1, std::numeric_limits<uint32_t>::max());
135 uint32_t newObs = 0;
136 for (auto const& oldObs : occuringObservations) {
137 oldToNewObservationMapping[oldObs] = newObs;
138 ++newObs;
139 }
140 for (auto& obs : observations) {
141 obs = oldToNewObservationMapping[obs];
142 }
143
144 return observations;
145}
146
147template<typename ValueType>
148storm::models::sparse::StandardRewardModel<ValueType> PomdpMemoryUnfolder<ValueType>::transformRewardModel(
149 storm::models::sparse::StandardRewardModel<ValueType> const& rewardModel, storm::storage::BitVector const& reachableStates) const {
150 std::optional<std::vector<ValueType>> stateRewards, actionRewards;
151 if (rewardModel.hasStateRewards()) {
152 stateRewards = std::vector<ValueType>();
153 stateRewards->reserve(pomdp.getNumberOfStates() * memory.getNumberOfStates());
154 for (uint64_t modelState = 0; modelState < pomdp.getNumberOfStates(); ++modelState) {
155 for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) {
156 if (reachableStates.get(getUnfoldingState(modelState, memState))) {
157 stateRewards->push_back(rewardModel.getStateReward(modelState));
158 }
159 }
160 }
161 }
162 if (rewardModel.hasStateActionRewards()) {
163 actionRewards = std::vector<ValueType>();
164 for (uint64_t modelState = 0; modelState < pomdp.getNumberOfStates(); ++modelState) {
165 for (uint64_t memState = 0; memState < memory.getNumberOfStates(); ++memState) {
166 if (reachableStates.get(getUnfoldingState(modelState, memState))) {
167 for (uint64_t origRow = pomdp.getTransitionMatrix().getRowGroupIndices()[modelState];
168 origRow < pomdp.getTransitionMatrix().getRowGroupIndices()[modelState + 1]; ++origRow) {
169 ValueType const& actionReward = rewardModel.getStateActionReward(origRow);
170 actionRewards->insert(actionRewards->end(), memory.getNumberOfOutgoingTransitions(memState), actionReward);
171 }
172 }
173 }
174 }
175 }
176 STORM_LOG_THROW(!rewardModel.hasTransitionRewards(), storm::exceptions::NotSupportedException, "Transition rewards are currently not supported.");
177 return storm::models::sparse::StandardRewardModel<ValueType>(std::move(stateRewards), std::move(actionRewards));
178}
179
180template<typename ValueType>
181uint64_t PomdpMemoryUnfolder<ValueType>::getUnfoldingState(uint64_t modelState, uint64_t memoryState) const {
182 return modelState * memory.getNumberOfStates() + memoryState;
183}
184
185template<typename ValueType>
186uint64_t PomdpMemoryUnfolder<ValueType>::getModelState(uint64_t unfoldingState) const {
187 return unfoldingState / memory.getNumberOfStates();
188}
189
190template<typename ValueType>
191uint64_t PomdpMemoryUnfolder<ValueType>::getMemoryState(uint64_t unfoldingState) const {
192 return unfoldingState % memory.getNumberOfStates();
193}
194
195template<typename ValueType>
196uint32_t PomdpMemoryUnfolder<ValueType>::getUnfoldingObersvation(uint32_t modelObservation, uint64_t memoryState) const {
197 return modelObservation * memory.getNumberOfStates() + memoryState;
198}
199
200template<typename ValueType>
201uint32_t PomdpMemoryUnfolder<ValueType>::getModelObersvation(uint32_t unfoldingObservation) const {
202 return unfoldingObservation / memory.getNumberOfStates();
203}
204
205template<typename ValueType>
206uint64_t PomdpMemoryUnfolder<ValueType>::getMemoryStateFromObservation(uint32_t unfoldingObservation) const {
207 return unfoldingObservation % memory.getNumberOfStates();
208}
209
210template class PomdpMemoryUnfolder<double>;
211template class PomdpMemoryUnfolder<storm::RationalNumber>;
212template class PomdpMemoryUnfolder<storm::RationalFunction>;
213} // namespace transformer
214} // namespace storm
This class represents a partially observable Markov decision process.
Definition Pomdp.h:13
bool hasTransitionRewards() const
Retrieves whether the reward model has transition rewards.
ValueType const & getStateReward(uint_fast64_t state) const
ValueType const & getStateActionReward(uint_fast64_t choiceIndex) const
Retrieves the state-action reward for the given choice.
bool hasStateRewards() const
Retrieves whether the reward model has state rewards.
bool hasStateActionRewards() const
Retrieves whether the reward model has state-action rewards.
This class manages the labeling of the state space with a number of (atomic) labels.
storm::storage::BitVector const & getStates(std::string const &label) const
Returns the labeling of states associated with the given label.
StateLabeling getSubLabeling(storm::storage::BitVector const &states) const
Retrieves the sub labeling that represents the same labeling as the current one for all selected stat...
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
bool get(uint64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
index_type getNumberOfEntries() const
Retrieves the number of entries in the rows.
A class that can be used to build a sparse matrix by adding value by value.
A class that holds a possibly non-square matrix in the compressed row storage format.
const_rows getRowGroup(index_type rowGroup) const
Returns an object representing the given row group.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
index_type getRowGroupSize(index_type group) const
Returns the size of the given row group.
PomdpMemoryUnfolder(storm::models::sparse::Pomdp< ValueType > const &pomdp, storm::storage::PomdpMemory const &memory, bool addMemoryLabels=false, bool keepStateValuations=false)
std::shared_ptr< storm::models::sparse::Pomdp< ValueType > > transform(bool dropUnreachableStates=true) const
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
SFTBDDChecker::ValueType ValueType
storm::storage::BitVector getStates(storm::logic::Formula const &propositionalFormula, bool formulaInverted, PomdpType const &pomdp)
RewardModelType transformRewardModel(RewardModelType const &originalRewardModel, storm::storage::BitVector const &subsystem, storm::storage::BitVector const &subsystemActions, bool makeRowGroupingTrivial)
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
std::optional< storm::storage::sparse::StateValuations > stateValuations
std::unordered_map< std::string, RewardModelType > rewardModels
storm::storage::SparseMatrix< ValueType > transitionMatrix
storm::models::sparse::StateLabeling stateLabeling
std::optional< std::vector< uint32_t > > observabilityClasses