Storm 1.13.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
ObservationTraceUnfolder.cpp
Go to the documentation of this file.
2#include <algorithm>
3
10
11#undef _VERBOSE_OBSERVATION_UNFOLDING
12
13namespace storm {
14namespace pomdp {
15template<typename ValueType>
17 std::shared_ptr<storm::expressions::ExpressionManager>& exprManager,
19 : model(model), risk(risk), exprManager(exprManager), options(options) {
20 svvar = exprManager->declareFreshIntegerVariable(false, "_s");
21 tsvar = exprManager->declareFreshIntegerVariable(false, "_t");
22}
23
24template<typename ValueType>
25std::shared_ptr<storm::models::sparse::Mdp<ValueType>> ObservationTraceUnfolder<ValueType>::transform(const std::vector<uint32_t>& observations) {
26 std::vector<uint32_t> modifiedObservations = observations;
27 // First observation should be special.
28 // This just makes the algorithm simpler because we do not treat the first step as a special case later.
29 // We overwrite the observation with a non-existing obs z*
30 modifiedObservations[0] = model.getNrObservations();
31
32 storm::storage::BitVector initialStates = model.getInitialStates();
33 storm::storage::BitVector actualInitialStates = initialStates;
34 for (uint64_t state : initialStates) {
35 if (model.getObservation(state) != observations[0]) {
36 actualInitialStates.set(state, false);
37 }
38 }
39 STORM_LOG_THROW(actualInitialStates.getNumberOfSetBits() == 1, storm::exceptions::InvalidArgumentException,
40 "Must have unique initial state matching the observation");
41
42#ifdef _VERBOSE_OBSERVATION_UNFOLDING
43 std::cout << "build valution builder..\n";
44#endif
46 svbuilder.addVariable(svvar);
47 svbuilder.addVariable(tsvar);
48
49 std::unordered_map<uint64_t, uint64_t> unfoldedToOld;
50 std::unordered_map<uint64_t, uint64_t> unfoldedToOldNextStep;
51 std::unordered_map<uint64_t, uint64_t> oldToUnfolded;
52
53#ifdef _VERBOSE_OBSERVATION_UNFOLDING
54 std::cout << "start buildiing matrix...\n";
55#endif
56
57 uint64_t newStateIndex = 0;
58 uint64_t const violatedState = newStateIndex;
59 if (!options.useRestartSemantics) {
60 // The violated state is only used if we do no use the rejection semantics.
61 ++newStateIndex;
62 }
63 // Add this initial state:
64 uint64_t const initialState = newStateIndex;
65 ++newStateIndex;
66
67 unfoldedToOldNextStep[initialState] = actualInitialStates.getNextSetIndex(0);
68
69 uint64_t const resetDestination = options.useRestartSemantics ? initialState : violatedState; // Should be initial state for the standard semantics.
70 storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, true, true);
71
72 if (!options.useRestartSemantics) {
73 // the violated state (only used when no rejection sampling) is a sink state
74 transitionMatrixBuilder.newRowGroup(violatedState);
75 transitionMatrixBuilder.addNextValue(violatedState, violatedState, storm::utility::one<ValueType>());
76 svbuilder.addState(violatedState, {}, {-1, -1});
77 }
78
79 // Now we are starting to build the MDP from the initial state onwards.
80 uint64_t newRowGroupStart = initialState;
81 uint64_t newRowCount = initialState;
82
83 // Notice that we are going to use a special last step
84 for (uint64_t step = 0; step < observations.size() - 1; ++step) {
85 oldToUnfolded.clear();
86 unfoldedToOld = unfoldedToOldNextStep;
87 unfoldedToOldNextStep.clear();
88
89 for (auto const& unfoldedToOldEntry : unfoldedToOld) {
90 transitionMatrixBuilder.newRowGroup(newRowGroupStart);
91#ifdef _VERBOSE_OBSERVATION_UNFOLDING
92 std::cout << "\tconsider new state " << unfoldedToOldEntry.first << '\n';
93#endif
94 STORM_LOG_ASSERT(step == 0 || newRowCount == transitionMatrixBuilder.getLastRow() + 1,
95 "step " << step << " newRowCount " << newRowCount << " lastRow " << transitionMatrixBuilder.getLastRow());
96 svbuilder.addState(unfoldedToOldEntry.first, {}, {static_cast<int64_t>(unfoldedToOldEntry.second), static_cast<int64_t>(step)});
97 uint64_t oldRowIndexStart = model.getNondeterministicChoiceIndices()[unfoldedToOldEntry.second];
98 uint64_t oldRowIndexEnd = model.getNondeterministicChoiceIndices()[unfoldedToOldEntry.second + 1];
99
100 for (uint64_t oldRowIndex = oldRowIndexStart; oldRowIndex != oldRowIndexEnd; oldRowIndex++) {
101#ifdef _VERBOSE_OBSERVATION_UNFOLDING
102 std::cout << "\t\tconsider old action " << oldRowIndex << '\n';
103 std::cout << "\t\tconsider new row nr " << newRowCount << '\n';
104#endif
105
106 ValueType resetProb = storm::utility::zero<ValueType>();
107 // We first find the reset probability
108 for (auto const& oldRowEntry : model.getTransitionMatrix().getRow(oldRowIndex)) {
109 if (model.getObservation(oldRowEntry.getColumn()) != observations[step + 1]) {
110 resetProb += oldRowEntry.getValue();
111 if constexpr (std::is_same_v<ValueType, storm::Interval>) {
112 resetProb.setUpper(std::min(resetProb.upper(), 1.0));
113 resetProb.setLower(std::max(resetProb.lower(), 0.0));
114 } else if constexpr (std::is_same_v<ValueType, storm::RationalInterval>) {
115 resetProb.setUpper(std::min(resetProb.upper(), utility::one<storm::RationalNumber>()));
116 resetProb.setLower(std::max(resetProb.lower(), utility::zero<storm::RationalNumber>()));
117 }
118 }
119 }
120#ifdef _VERBOSE_OBSERVATION_UNFOLDING
121 std::cout << "\t\t\t add reset with probability " << resetProb << '\n';
122#endif
123
124 // Add the resets
125 if (resetProb != storm::utility::zero<ValueType>()) {
126 transitionMatrixBuilder.addNextValue(newRowCount, resetDestination, resetProb);
127 }
128#ifdef _VERBOSE_OBSERVATION_UNFOLDING
129 std::cout << "\t\t\t add other transitions...\n";
130#endif
131
132 // Now, we build the outgoing transitions.
133 for (auto const& oldRowEntry : model.getTransitionMatrix().getRow(oldRowIndex)) {
134 if (model.getObservation(oldRowEntry.getColumn()) != observations[step + 1]) {
135 continue; // already handled.
136 }
137 uint64_t column = 0;
138
139 auto entryIt = oldToUnfolded.find(oldRowEntry.getColumn());
140 if (entryIt == oldToUnfolded.end()) {
141 column = newStateIndex;
142 oldToUnfolded[oldRowEntry.getColumn()] = column;
143 unfoldedToOldNextStep[column] = oldRowEntry.getColumn();
144 newStateIndex++;
145 } else {
146 column = entryIt->second;
147 }
148#ifdef _VERBOSE_OBSERVATION_UNFOLDING
149 std::cout << "\t\t\t\t transition to " << column << "with probability " << oldRowEntry.getValue() << '\n';
150#endif
151 transitionMatrixBuilder.addNextValue(newRowCount, column, oldRowEntry.getValue());
152 }
153 newRowCount++;
154 }
155 newRowGroupStart = transitionMatrixBuilder.getLastRow() + 1;
156 }
157 }
158 // Now, take care of the last step.
159 uint64_t sinkState = newStateIndex;
160 uint64_t targetState = newStateIndex + 1;
161 for (auto const& unfoldedToOldEntry : unfoldedToOldNextStep) {
162 svbuilder.addState(unfoldedToOldEntry.first, {}, {static_cast<int64_t>(unfoldedToOldEntry.second), static_cast<int64_t>(observations.size() - 1)});
163
164 transitionMatrixBuilder.newRowGroup(newRowGroupStart);
165 STORM_LOG_ASSERT(risk.size() > unfoldedToOldEntry.second, "Must be a state");
167 "Risk must be a probability");
168 // std::cout << "risk is" << risk[unfoldedToOldEntry.second] << '\n';
169 if (!storm::utility::isOne(risk[unfoldedToOldEntry.second])) {
170 transitionMatrixBuilder.addNextValue(newRowGroupStart, sinkState, storm::utility::one<ValueType>() - risk[unfoldedToOldEntry.second]);
171 }
172 if (!storm::utility::isZero(risk[unfoldedToOldEntry.second])) {
173 transitionMatrixBuilder.addNextValue(newRowGroupStart, targetState, risk[unfoldedToOldEntry.second]);
174 }
175 newRowGroupStart++;
176 }
177 // sink state
178 transitionMatrixBuilder.newRowGroup(newRowGroupStart);
179 transitionMatrixBuilder.addNextValue(newRowGroupStart, sinkState, storm::utility::one<ValueType>());
180 svbuilder.addState(sinkState, {}, {-1, -1});
181
182 newRowGroupStart++;
183 transitionMatrixBuilder.newRowGroup(newRowGroupStart);
184 // target state
185 transitionMatrixBuilder.addNextValue(newRowGroupStart, targetState, storm::utility::one<ValueType>());
186 svbuilder.addState(targetState, {}, {-1, -1});
187#ifdef _VERBOSE_OBSERVATION_UNFOLDING
188 std::cout << "build matrix...\n";
189#endif
190
192 components.transitionMatrix = transitionMatrixBuilder.build();
193#ifdef _VERBOSE_OBSERVATION_UNFOLDING
194 // std::cout << components.transitionMatrix << '\n';
195#endif
196
197 storm::models::sparse::StateLabeling labeling(components.transitionMatrix.getRowGroupCount());
198 labeling.addLabel("_goal");
199 labeling.addLabelToState("_goal", targetState);
200 if (!options.useRestartSemantics) {
201 labeling.addLabel("_violated");
202 labeling.addLabelToState("_violated", violatedState);
203 }
204 labeling.addLabel("_end");
205 labeling.addLabelToState("_end", sinkState);
206 labeling.addLabelToState("_end", targetState);
207 labeling.addLabel("init");
208 labeling.addLabelToState("init", initialState);
209 components.stateLabeling = labeling;
210 components.stateValuations = svbuilder.build();
211 return std::make_shared<storm::models::sparse::Mdp<ValueType>>(std::move(components));
212}
213
214template<typename ValueType>
215std::shared_ptr<storm::models::sparse::Mdp<ValueType>> ObservationTraceUnfolder<ValueType>::extend(std::vector<uint32_t> const& observations) {
216 traceSoFar.insert(traceSoFar.end(), observations.begin(), observations.end());
217 return transform(traceSoFar);
218}
219
220template<typename ValueType>
222 traceSoFar = {observation};
223}
224
225template<typename ValueType>
227 return options.useRestartSemantics;
228}
229
235} // namespace pomdp
236} // namespace storm
void addLabel(std::string const &label)
Adds a new label to the labelings.
This class represents a partially observable Markov decision process.
Definition Pomdp.h:13
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.
Observation-trace unrolling to allow model checking for monitoring.
std::shared_ptr< storm::models::sparse::Mdp< ValueType > > extend(std::vector< uint32_t > const &observations)
Transform incrementaly.
void reset(uint32_t observation)
When using the incremental approach, reset the observations made so far.
std::shared_ptr< storm::models::sparse::Mdp< ValueType > > transform(std::vector< uint32_t > const &observations)
Transform in one shot.
ObservationTraceUnfolder(storm::models::sparse::Pomdp< ValueType > const &model, std::vector< ValueType > const &risk, std::shared_ptr< storm::expressions::ExpressionManager > &exprManager, ObservationTraceUnfolderOptions const &options)
Initialize.
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
uint64_t getNextSetIndex(uint64_t startingIndex) const
Retrieves the index of the bit that is the next bit set to true in the bit vector.
uint64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
A class that can be used to build a sparse matrix by adding value by value.
index_type getLastRow() const
Retrieves the most recently used row.
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)
void addState(storm::storage::sparse::state_type const &state, std::vector< bool > &&booleanValues={}, std::vector< int64_t > &&integerValues={})
Adds a new state.
StateValuations build()
Creates the finalized state valuations object.
void addVariable(storm::expressions::Variable const &variable)
Adds a new variable to keep track of for the state valuations.
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
bool isOne(ValueType const &a)
Definition constants.cpp:34
bool isBetween(ValueType const &a, ValueType const &b, ValueType const &c, bool strict)
Compare whether a <= b <= c or a < b < c, based on the strictness parameter.
Definition constants.cpp:82
bool isZero(ValueType const &a)
Definition constants.cpp:39
ValueType zero()
Definition constants.cpp:24
ValueType one()
Definition constants.cpp:19
std::optional< storm::storage::sparse::StateValuations > stateValuations
storm::storage::SparseMatrix< ValueType > transitionMatrix
storm::models::sparse::StateLabeling stateLabeling