Storm 1.13.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
NondeterministicBeliefTrackerTest.cpp
Go to the documentation of this file.
1#include "storm-config.h"
2#include "test/storm_gtest.h"
3
8#include "storm/api/storm.h"
10
11namespace {
12
13std::shared_ptr<storm::models::sparse::Pomdp<double>> buildMaze(std::string const& constants = "sl=0.0") {
14 storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/pomdp/maze2.prism");
15 program = storm::utility::prism::preprocess(program, constants);
16 auto formula = storm::api::parsePropertiesForPrismProgram("Pmax=? [F \"goal\" ]", program).front().getRawFormula();
19 return makeCanonic.transform();
20}
21
22TEST(BeliefStateManager, BasicProperties) {
23#ifndef STORM_HAVE_Z3
24 GTEST_SKIP() << "Z3 not available.";
25#endif
26 auto pomdp = buildMaze();
28
29 EXPECT_EQ(pomdp->getNumberOfStates(), manager.getNumberOfStates());
30
31 for (uint64_t state = 0; state < pomdp->getNumberOfStates(); ++state) {
32 EXPECT_EQ(pomdp->getObservation(state), manager.getObservation(state));
33 }
34
35 for (uint32_t obs = 0; obs < pomdp->getNrObservations(); ++obs) {
36 EXPECT_GT(manager.getActionsForObservation(obs), 0ul);
37 }
38}
39
40TEST(BeliefStateManager, ObservationOffsets) {
41#ifndef STORM_HAVE_Z3
42 GTEST_SKIP() << "Z3 not available.";
43#endif
44 auto pomdp = buildMaze();
46
47 // Verify that for each state, getState(obs, offset) round-trips back to the same observation.
48 for (uint64_t state = 0; state < pomdp->getNumberOfStates(); ++state) {
49 uint32_t obs = manager.getObservation(state);
50 uint64_t offset = manager.getObservationOffset(state);
51 EXPECT_LT(offset, manager.numberOfStatesPerObservation(obs));
52 EXPECT_EQ(obs, manager.getObservation(manager.getState(obs, offset)));
53 }
54}
55
56TEST(SparseBeliefTracker, ResetToInitial) {
57#ifndef STORM_HAVE_Z3
58 GTEST_SKIP() << "Z3 not available.";
59#endif
60 auto pomdp = buildMaze();
62 tracker.setRisk(std::vector<double>(pomdp->getNumberOfStates(), 0.0));
63
64 uint32_t initObs = pomdp->getObservation(*pomdp->getInitialStates().begin());
65 bool hit = tracker.reset(initObs);
66 EXPECT_TRUE(hit);
67 EXPECT_EQ(1ul, tracker.getNumberOfBeliefs());
68 EXPECT_EQ(initObs, tracker.getCurrentObservation());
69 EXPECT_EQ(1ul, tracker.getCurrentDimension());
70}
71
72TEST(SparseBeliefTracker, TrackValidObservation) {
73#ifndef STORM_HAVE_Z3
74 GTEST_SKIP() << "Z3 not available.";
75#endif
76 auto pomdp = buildMaze();
78 tracker.setRisk(std::vector<double>(pomdp->getNumberOfStates(), 0.0));
79
80 uint32_t initObs = pomdp->getObservation(*pomdp->getInitialStates().begin());
81 tracker.reset(initObs);
82
83 // Collect observations reachable from the initial state.
84 std::set<uint32_t> reachableObs;
85 uint64_t initState = *pomdp->getInitialStates().begin();
86 for (uint64_t row = pomdp->getNondeterministicChoiceIndices()[initState]; row < pomdp->getNondeterministicChoiceIndices()[initState + 1]; ++row) {
87 for (auto const& entry : pomdp->getTransitionMatrix().getRow(row)) {
88 reachableObs.insert(pomdp->getObservation(entry.getColumn()));
89 }
90 }
91 ASSERT_FALSE(reachableObs.empty());
92
93 // Tracking any reachable observation should yield a non-empty belief set.
94 uint32_t nextObs = *reachableObs.begin();
95 bool result = tracker.track(nextObs);
96 EXPECT_TRUE(result);
97 EXPECT_GT(tracker.getNumberOfBeliefs(), 0ul);
98 EXPECT_EQ(nextObs, tracker.getCurrentObservation());
99}
100
101TEST(SparseBeliefTracker, TrackImpossibleObservation) {
102#ifndef STORM_HAVE_Z3
103 GTEST_SKIP() << "Z3 not available.";
104#endif
105 auto pomdp = buildMaze();
107 tracker.setRisk(std::vector<double>(pomdp->getNumberOfStates(), 0.0));
108
109 uint32_t initObs = pomdp->getObservation(*pomdp->getInitialStates().begin());
110 tracker.reset(initObs);
111
112 // An observation beyond the valid range is never reachable.
113 uint64_t impossibleObs = pomdp->getNrObservations() + 100;
114 bool result = tracker.track(impossibleObs);
115 EXPECT_FALSE(result);
116 EXPECT_EQ(0ul, tracker.getNumberOfBeliefs());
117}
118
119TEST(SparseBeliefTracker, UniformRisk) {
120#ifndef STORM_HAVE_Z3
121 GTEST_SKIP() << "Z3 not available.";
122#endif
123 auto pomdp = buildMaze();
125
126 uint32_t initObs = pomdp->getObservation(*pomdp->getInitialStates().begin());
127
128 // All-zero risk.
129 std::vector<double> zeroRisk(pomdp->getNumberOfStates(), 0.0);
130 tracker.setRisk(zeroRisk);
131 tracker.reset(initObs);
132 EXPECT_NEAR(0.0, tracker.getCurrentRisk(true), 1e-9);
133 EXPECT_NEAR(0.0, tracker.getCurrentRisk(false), 1e-9);
134
135 // All-one risk.
136 std::vector<double> oneRisk(pomdp->getNumberOfStates(), 1.0);
137 tracker.setRisk(oneRisk);
138 tracker.reset(initObs);
139 EXPECT_NEAR(1.0, tracker.getCurrentRisk(true), 1e-9);
140 EXPECT_NEAR(1.0, tracker.getCurrentRisk(false), 1e-9);
141}
142
143TEST(SparseBeliefTracker, MixedRiskMaxMin) {
144#ifndef STORM_HAVE_Z3
145 GTEST_SKIP() << "Z3 not available.";
146#endif
147 // Use sl=0.4 so that slipping lets the system stay in the initial state, creating
148 // multiple beliefs from a single tracking step. We then assign heterogeneous risk
149 // and verify that getCurrentRisk correctly returns the max and the min over beliefs.
150 auto pomdp = buildMaze("sl=0.4");
152
153 // Assign risk 0.0 to the initial state and 1.0 to everything else.
154 uint64_t initState = *pomdp->getInitialStates().begin();
155 std::vector<double> mixedRisk(pomdp->getNumberOfStates(), 1.0);
156 mixedRisk[initState] = 0.0;
157 tracker.setRisk(mixedRisk);
158
159 uint32_t initObs = pomdp->getObservation(initState);
160 tracker.reset(initObs);
161
162 // After reset the sole belief sits on the initial state with risk 0.0.
163 EXPECT_NEAR(0.0, tracker.getCurrentRisk(true), 1e-9);
164 EXPECT_NEAR(0.0, tracker.getCurrentRisk(false), 1e-9);
165
166 // Track any observation that corresponds to a non-initial state to obtain a belief
167 // that has risk 1.0. We iterate until we either find one or exhaust observations.
168 bool movedToHighRisk = false;
169 for (uint32_t obs = 0; obs < static_cast<uint32_t>(pomdp->getNrObservations()); ++obs) {
170 if (obs == initObs)
171 continue;
173 t2.setRisk(mixedRisk);
174 t2.reset(initObs);
175 if (t2.track(obs)) {
176 EXPECT_NEAR(1.0, t2.getCurrentRisk(true), 1e-9);
177 movedToHighRisk = true;
178 break;
179 }
180 }
181 EXPECT_TRUE(movedToHighRisk) << "Could not find a non-initial reachable observation";
182}
183
184} // namespace
TEST(OrderTest, Simple)
Definition OrderTest.cpp:15
This class keeps track of common information of a set of beliefs.
This tracker implements state estimation for POMDPs.
This class represents a partially observable Markov decision process.
Definition Pomdp.h:13
static storm::prism::Program parse(std::string const &filename, bool prismCompatability=false)
Parses the given file into the PRISM storage classes assuming it complies with the PRISM syntax.
std::vector< storm::jani::Property > parsePropertiesForPrismProgram(std::string const &inputString, storm::prism::Program const &program, boost::optional< std::set< std::string > > const &propertyFilter)
std::shared_ptr< storm::models::sparse::Model< ValueType > > buildSparseModel(storm::storage::SymbolicModelDescription const &model, storm::builder::BuilderOptions const &options)
Definition builder.h:109
SettingsManager const & manager()
Retrieves the settings manager.
storm::prism::Program preprocess(storm::prism::Program const &program, std::map< storm::expressions::Variable, storm::expressions::Expression > const &constantDefinitions)
Definition prism.cpp:13