Storm 1.13.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
ConditionalMdpPrctlModelCheckerTest.cpp
Go to the documentation of this file.
1#include "storm-config.h"
2#include "test/storm_gtest.h"
3
6#include "storm/api/builder.h"
14
15namespace {
16
17class SparseDoubleRestartEnvironment {
18 public:
19 static const bool isExact = false;
20 typedef double ValueType;
21 typedef storm::models::sparse::Mdp<ValueType> ModelType;
22 static storm::Environment createEnvironment() {
23 storm::Environment env;
26 false); // restart algorithm requires a higher precision
27 return env;
28 }
29};
30
31class SparseDoubleBisectionEnvironment {
32 public:
33 static const bool isExact = false;
34 typedef double ValueType;
35 typedef storm::models::sparse::Mdp<ValueType> ModelType;
36 static storm::Environment createEnvironment() {
37 storm::Environment env;
39 return env;
40 }
41};
42
43class SparseDoubleBisectionAdvancedEnvironment {
44 public:
45 static const bool isExact = false;
46 typedef double ValueType;
47 typedef storm::models::sparse::Mdp<ValueType> ModelType;
48 static storm::Environment createEnvironment() {
49 storm::Environment env;
51 return env;
52 }
53};
54
55class SparseDoubleBisectionPtEnvironment {
56 public:
57 static const bool isExact = false;
58 typedef double ValueType;
59 typedef storm::models::sparse::Mdp<ValueType> ModelType;
60 static storm::Environment createEnvironment() {
61 storm::Environment env;
63 return env;
64 }
65};
66
67class SparseDoubleBisectionAdvancedPtEnvironment {
68 public:
69 static const bool isExact = false;
70 typedef double ValueType;
71 typedef storm::models::sparse::Mdp<ValueType> ModelType;
72 static storm::Environment createEnvironment() {
73 storm::Environment env;
75 return env;
76 }
77};
78
79class SparseDoublePiEnvironment {
80 public:
81 static const bool isExact = false;
82 typedef double ValueType;
83 typedef storm::models::sparse::Mdp<ValueType> ModelType;
84 static storm::Environment createEnvironment() {
85 storm::Environment env;
87 return env;
88 }
89};
90
91class SparseRationalNumberRestartEnvironment {
92 public:
93 static const bool isExact = true;
94 typedef storm::RationalNumber ValueType;
95 typedef storm::models::sparse::Mdp<ValueType> ModelType;
96 static storm::Environment createEnvironment() {
97 storm::Environment env;
100 false); // restart algorithm requires a higher precision
101 return env;
102 }
103};
104
105class SparseRationalNumberBisectionEnvironment {
106 public:
107 static const bool isExact = true;
108 typedef storm::RationalNumber ValueType;
109 typedef storm::models::sparse::Mdp<ValueType> ModelType;
110 static storm::Environment createEnvironment() {
111 storm::Environment env;
113 return env;
114 }
115};
116
117class SparseRationalNumberBisectionAdvancedEnvironment {
118 public:
119 static const bool isExact = true;
120 typedef storm::RationalNumber ValueType;
121 typedef storm::models::sparse::Mdp<ValueType> ModelType;
122 static storm::Environment createEnvironment() {
123 storm::Environment env;
125 return env;
126 }
127};
128
129class SparseRationalNumberBisectionPtEnvironment {
130 public:
131 static const bool isExact = true;
132 typedef storm::RationalNumber ValueType;
133 typedef storm::models::sparse::Mdp<ValueType> ModelType;
134 static storm::Environment createEnvironment() {
135 storm::Environment env;
137 return env;
138 }
139};
140
141class SparseRationalNumberBisectionAdvancedPtEnvironment {
142 public:
143 static const bool isExact = true;
144 typedef storm::RationalNumber ValueType;
145 typedef storm::models::sparse::Mdp<ValueType> ModelType;
146 static storm::Environment createEnvironment() {
147 storm::Environment env;
149 return env;
150 }
151};
152
153class SparseRationalNumberPiEnvironment {
154 public:
155 static const bool isExact = true;
156 typedef storm::RationalNumber ValueType;
157 typedef storm::models::sparse::Mdp<ValueType> ModelType;
158 static storm::Environment createEnvironment() {
159 storm::Environment env;
161 return env;
162 }
163};
164
165template<typename TestType>
166class ConditionalMdpPrctlModelCheckerTest : public ::testing::Test {
167 public:
168 typedef typename TestType::ValueType ValueType;
169 typedef typename storm::models::sparse::Mdp<ValueType> SparseModelType;
170
171 ConditionalMdpPrctlModelCheckerTest() : _environment(TestType::createEnvironment()) {}
172
173 void SetUp() override {
174#ifndef STORM_HAVE_Z3
175 GTEST_SKIP() << "Z3 not available.";
176#endif
177 }
178
179 storm::Environment const& env() const {
180 return _environment;
181 }
182 ValueType parseNumber(std::string const& input) const {
184 }
185 ValueType precision() const {
186 return TestType::isExact ? parseNumber("0") : parseNumber("1e-6");
187 }
188 bool isSparseModel() const {
189 return std::is_same<typename TestType::ModelType, SparseModelType>::value;
190 }
191
192 std::pair<std::shared_ptr<SparseModelType>, std::vector<std::shared_ptr<storm::logic::Formula const>>> buildModelFormulas(
193 storm::prism::Program const& inputProgram, std::string const& formulasAsString, std::string const& constantDefinitionString = "") const {
194 std::pair<std::shared_ptr<SparseModelType>, std::vector<std::shared_ptr<storm::logic::Formula const>>> result;
195 auto program = storm::utility::prism::preprocess(inputProgram, constantDefinitionString);
197 result.first = storm::api::buildSparseModel<ValueType>(program, result.second)->template as<SparseModelType>();
198 return result;
199 }
200
201 std::vector<storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>> getTasks(
202 std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) const {
203 std::vector<storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>> result;
204 for (auto const& f : formulas) {
205 result.emplace_back(*f, true); // Set onlyInitialStatesRelevant to true for conditional tasks
206 }
207 return result;
208 }
209
210 private:
211 storm::Environment _environment;
212};
213
214typedef ::testing::Types<SparseDoubleRestartEnvironment, SparseDoubleBisectionEnvironment, SparseDoubleBisectionAdvancedEnvironment,
215 SparseDoubleBisectionPtEnvironment, SparseDoubleBisectionAdvancedPtEnvironment, SparseDoublePiEnvironment,
216 SparseRationalNumberRestartEnvironment, SparseRationalNumberBisectionEnvironment, SparseRationalNumberBisectionAdvancedEnvironment,
217 SparseRationalNumberBisectionPtEnvironment, SparseRationalNumberBisectionAdvancedPtEnvironment, SparseRationalNumberPiEnvironment>
219
220TYPED_TEST_SUITE(ConditionalMdpPrctlModelCheckerTest, TestingTypes, );
221
222TYPED_TEST(ConditionalMdpPrctlModelCheckerTest, two_dice) {
223 typedef typename TestFixture::ValueType ValueType;
224
225 std::string const formulasString =
226 "Pmax=? [F \"twelve\" || F d1=6];"
227 "Pmin=? [F \"twelve\" || F d1=6];"
228 "Pmax=? [F \"seven\" || F d2=4];"
229 "Pmin=? [F \"seven\" || F d2=4];"
230 "Pmax=? [F \"two\" || F d2=2];"
231 "Pmin=? [F \"two\" || F d2=2];"
232 "Pmax=? [F d1=6 || F \"twelve\"];"
233 "Pmin=? [F d1=6 || F \"twelve\"];";
234
235 auto program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/two_dice.nm");
236 auto modelFormulas = this->buildModelFormulas(program, formulasString);
237 auto model = std::move(modelFormulas.first);
238 auto tasks = this->getTasks(modelFormulas.second);
239 EXPECT_EQ(169ul, model->getNumberOfStates());
240 EXPECT_EQ(436ul, model->getNumberOfTransitions());
241 ASSERT_EQ(model->getType(), storm::models::ModelType::Mdp);
242 auto mdp = model->template as<storm::models::sparse::Mdp<ValueType>>();
244
245 auto result = checker.check(this->env(), tasks[0])->template asExplicitQuantitativeCheckResult<ValueType>();
246 EXPECT_NEAR(this->parseNumber("1/6"), result[*mdp->getInitialStates().begin()], this->precision());
247 result = checker.check(this->env(), tasks[1])->template asExplicitQuantitativeCheckResult<ValueType>();
248 EXPECT_NEAR(this->parseNumber("1/6"), result[*mdp->getInitialStates().begin()], this->precision());
249 result = checker.check(this->env(), tasks[2])->template asExplicitQuantitativeCheckResult<ValueType>();
250 EXPECT_NEAR(this->parseNumber("1/6"), result[*mdp->getInitialStates().begin()], this->precision());
251 result = checker.check(this->env(), tasks[3])->template asExplicitQuantitativeCheckResult<ValueType>();
252 EXPECT_NEAR(this->parseNumber("1/6"), result[*mdp->getInitialStates().begin()], this->precision());
253 result = checker.check(this->env(), tasks[4])->template asExplicitQuantitativeCheckResult<ValueType>();
254 EXPECT_NEAR(this->parseNumber("0"), result[*mdp->getInitialStates().begin()], this->precision());
255 result = checker.check(this->env(), tasks[5])->template asExplicitQuantitativeCheckResult<ValueType>();
256 EXPECT_NEAR(this->parseNumber("0"), result[*mdp->getInitialStates().begin()], this->precision());
257
258 // This Environment depending on the platform fails or does not fail an assertion. Thus this env is skipped.
259 if constexpr (!std::is_same_v<TypeParam, SparseDoubleBisectionAdvancedPtEnvironment>) {
260 result = checker.check(this->env(), tasks[6])->template asExplicitQuantitativeCheckResult<ValueType>();
261 EXPECT_NEAR(this->parseNumber("1"), result[*mdp->getInitialStates().begin()], this->precision());
262 }
263
264 result = checker.check(this->env(), tasks[7])->template asExplicitQuantitativeCheckResult<ValueType>();
265 EXPECT_NEAR(this->parseNumber("1"), result[*mdp->getInitialStates().begin()], this->precision());
266}
267
268TYPED_TEST(ConditionalMdpPrctlModelCheckerTest, consensus) {
269 typedef typename TestFixture::ValueType ValueType;
270
271 std::string const formulasString =
272 "Pmax=? [F \"all_coins_equal_0\" & \"finished\" || F \"agree\" & \"finished\"];"
273 "Pmin=? [F \"all_coins_equal_0\" & \"finished\" || F \"agree\" & \"finished\"];"
274 "Pmax=? [F \"all_coins_equal_1\" & \"finished\" || F \"agree\" & \"finished\"];"
275 "Pmin=? [F \"all_coins_equal_1\" & \"finished\" || F \"agree\" & \"finished\"];"
276 "P<=560/953 [F \"all_coins_equal_1\" & \"finished\" || F \"agree\" & \"finished\"];"
277 "P<562/953 [F \"all_coins_equal_1\" & \"finished\" || F \"agree\" & \"finished\"];"
278 "P>393/953 [F \"all_coins_equal_1\" & \"finished\" || F \"agree\" & \"finished\"];"
279 "P>=391/953 [F \"all_coins_equal_1\" & \"finished\" || F \"agree\" & \"finished\"];";
280
281 auto program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/coin2-2.nm");
282 auto modelFormulas = this->buildModelFormulas(program, formulasString);
283 auto model = std::move(modelFormulas.first);
284 auto tasks = this->getTasks(modelFormulas.second);
285 EXPECT_EQ(272ul, model->getNumberOfStates());
286 EXPECT_EQ(492ul, model->getNumberOfTransitions());
287 ASSERT_EQ(model->getType(), storm::models::ModelType::Mdp);
288 auto mdp = model->template as<storm::models::sparse::Mdp<ValueType>>();
290
291 auto result = checker.check(this->env(), tasks[0])->template asExplicitQuantitativeCheckResult<ValueType>();
292 EXPECT_NEAR(this->parseNumber("561/953"), result[*mdp->getInitialStates().begin()], this->precision());
293 result = checker.check(this->env(), tasks[1])->template asExplicitQuantitativeCheckResult<ValueType>();
294 EXPECT_NEAR(this->parseNumber("392/953"), result[*mdp->getInitialStates().begin()], this->precision());
295 result = checker.check(this->env(), tasks[2])->template asExplicitQuantitativeCheckResult<ValueType>();
296 EXPECT_NEAR(this->parseNumber("561/953"), result[*mdp->getInitialStates().begin()], this->precision());
297 result = checker.check(this->env(), tasks[3])->template asExplicitQuantitativeCheckResult<ValueType>();
298 EXPECT_NEAR(this->parseNumber("392/953"), result[*mdp->getInitialStates().begin()], this->precision());
299 auto qualResult = checker.check(this->env(), tasks[4])->template asExplicitQualitativeCheckResult<ValueType>();
300 EXPECT_FALSE(qualResult[*mdp->getInitialStates().begin()]);
301 qualResult = checker.check(this->env(), tasks[5])->template asExplicitQualitativeCheckResult<ValueType>();
302 EXPECT_TRUE(qualResult[*mdp->getInitialStates().begin()]);
303 qualResult = checker.check(this->env(), tasks[6])->template asExplicitQualitativeCheckResult<ValueType>();
304 EXPECT_FALSE(qualResult[*mdp->getInitialStates().begin()]);
305 qualResult = checker.check(this->env(), tasks[7])->template asExplicitQualitativeCheckResult<ValueType>();
306 EXPECT_TRUE(qualResult[*mdp->getInitialStates().begin()]);
307}
308
309TYPED_TEST(ConditionalMdpPrctlModelCheckerTest, simple) {
310 typedef typename TestFixture::ValueType ValueType;
311
312 std::string const programAsString = R"(mdp
313module main
314 x : [0..2];
315 [] x=0 -> 0.7 : (x'=1) + 0.3 : (x'=2);
316 [] x=1 -> 1 : (x'=1);
317 [] x=2 -> 1 : (x'=1);
318endmodule
319)";
320
321 std::string const formulasString =
322 "Pmin=? [F x=2 || F x=1];"
323 "Pmax=? [F x=2 || F x=1];";
324
325 auto program = storm::parser::PrismParser::parseFromString(programAsString, "<no filename>");
326 auto modelFormulas = this->buildModelFormulas(program, formulasString);
327 auto model = std::move(modelFormulas.first);
328 auto tasks = this->getTasks(modelFormulas.second);
329 EXPECT_EQ(3ul, model->getNumberOfStates());
330 EXPECT_EQ(4ul, model->getNumberOfTransitions());
331 ASSERT_EQ(model->getType(), storm::models::ModelType::Mdp);
332 auto mdp = model->template as<storm::models::sparse::Mdp<ValueType>>();
334
335 auto result = checker.check(this->env(), tasks[0])->template asExplicitQuantitativeCheckResult<ValueType>();
336 EXPECT_NEAR(this->parseNumber("3/10"), result[*mdp->getInitialStates().begin()], this->precision());
337 result = checker.check(this->env(), tasks[1])->template asExplicitQuantitativeCheckResult<ValueType>();
338 EXPECT_NEAR(this->parseNumber("3/10"), result[*mdp->getInitialStates().begin()], this->precision());
339}
340
341} // namespace
void setPrecision(storm::RationalNumber const &value, bool setFromDefault)
ModelCheckerEnvironment & modelchecker()
ConditionalModelCheckerEnvironment & conditional()
static storm::prism::Program parseFromString(std::string const &input, std::string const &filename, bool prismCompatability=false)
Parses the given input stream into the PRISM storage classes assuming it complies with the PRISM synt...
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
std::vector< std::shared_ptr< storm::logic::Formula const > > extractFormulasFromProperties(std::vector< storm::jani::Property > const &properties)
SFTBDDChecker::ValueType ValueType
NumberType parseNumber(std::string const &value)
Parse number from string.
storm::prism::Program preprocess(storm::prism::Program const &program, std::map< storm::expressions::Variable, storm::expressions::Expression > const &constantDefinitions)
Definition prism.cpp:13
TargetType convertNumber(SourceType const &number)
TYPED_TEST(GraphTestAR, SymbolicProb01StochasticGameDieSmall)
Definition GraphTest.cpp:62
TYPED_TEST_SUITE(GraphTestAR, TestingTypes,)
::testing::Types< Cudd, Sylvan > TestingTypes
Definition GraphTest.cpp:59