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