Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
MonotonicityHelperTest.cpp
Go to the documentation of this file.
1#include "storm-config.h"
2#include "test/storm_gtest.h"
3
4#include <carl/util/stringparser.h>
5
11#include "storm/api/builder.h"
12#include "storm/api/storm.h"
13
14class MonotonicityHelperTest : public ::testing::Test {
15 protected:
16 void SetUp() override {
17#ifndef STORM_HAVE_Z3
18 GTEST_SKIP() << "Z3 not available.";
19#endif
20 }
21};
22
23TEST_F(MonotonicityHelperTest, Derivative_checker) {
24 // Create the region
27 auto region = storm::storage::ParameterRegion<storm::RationalFunction>(std::move(lowerBoundaries), std::move(upperBoundaries));
28
29 // Derivative 0
30 auto constFunction = storm::RationalFunction(0);
32 EXPECT_TRUE(constFunctionRes.first);
33 EXPECT_TRUE(constFunctionRes.second);
34
35 // Derivative 5
36 constFunction = storm::RationalFunction(5);
38 EXPECT_TRUE(constFunctionRes.first);
39 EXPECT_FALSE(constFunctionRes.second);
40
41 // Derivative -4
42 constFunction = storm::RationalFunction(storm::RationalFunction(1) - constFunction);
44 EXPECT_FALSE(constFunctionRes.first);
45 EXPECT_TRUE(constFunctionRes.second);
46
47 std::shared_ptr<storm::RawPolynomialCache> cache = std::make_shared<storm::RawPolynomialCache>();
48 carl::StringParser parser;
49 parser.setVariables({"p", "q"});
50
51 // Create the region
52 auto functionP = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial<storm::RationalFunctionCoefficient>("p"), cache));
53 auto functionQ = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial<storm::RationalFunctionCoefficient>("q"), cache));
54
55 auto varsP = functionP.gatherVariables();
56 auto varsQ = functionQ.gatherVariables();
59 for (auto var : varsP) {
61 storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(0 + 0.000001);
63 storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(1 - 0.000001);
64 lowerBoundaries2.emplace(std::make_pair(var, lb));
65 upperBoundaries2.emplace(std::make_pair(var, ub));
66 }
67 for (auto var : varsQ) {
69 storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(0 + 0.000001);
71 storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(1 - 0.000001);
72 lowerBoundaries2.emplace(std::make_pair(var, lb));
73 upperBoundaries2.emplace(std::make_pair(var, ub));
74 }
75 region = storm::storage::ParameterRegion<storm::RationalFunction>(std::move(lowerBoundaries2), std::move(upperBoundaries2));
76
77 // Derivative p
78 auto function = functionP;
80 EXPECT_TRUE(functionRes.first);
81 EXPECT_FALSE(functionRes.second);
82
83 // Derivative 1-p
84 auto functionDecr = storm::RationalFunction(storm::RationalFunction(1) - function);
86 EXPECT_TRUE(functionDecrRes.first);
87 EXPECT_FALSE(functionDecrRes.second);
88
89 // Derivative 1-2p
90 auto functionNonMonotonic = storm::RationalFunction(storm::RationalFunction(1) - storm::RationalFunction(2) * function);
91 auto functionNonMonotonicRes = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>::checkDerivative(functionNonMonotonic, region);
92 EXPECT_FALSE(functionNonMonotonicRes.first);
93 EXPECT_FALSE(functionNonMonotonicRes.second);
94
95 // Derivative -p
96 functionDecr = storm::RationalFunction(storm::RationalFunction(0) - function);
98 EXPECT_FALSE(functionDecrRes.first);
99 EXPECT_TRUE(functionDecrRes.second);
100
101 // Derivative p*q
102 function = functionP * functionQ;
104 EXPECT_TRUE(functionRes.first);
105 EXPECT_FALSE(functionRes.second);
106}
107
108TEST_F(MonotonicityHelperTest, Brp_with_bisimulation_no_samples) {
109 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
110 std::string formulaAsString = "P=? [true U s=4 & i=N ]";
111 std::string constantsAsString = ""; // e.g. pL=0.9,TOACK=0.5
112
113 // Program and formula
114 storm::prism::Program program = storm::api::parseProgram(programFile);
115 program = storm::utility::prism::preprocess(program, constantsAsString);
116 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
118 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
119 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
121 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
122 model = simplifier.getSimplifiedModel();
123
124 // Apply bisimulation
126 if (storm::settings::getModule<storm::settings::modules::BisimulationSettings>().isWeakBisimulationSet()) {
128 }
129
130 model = storm::api::performBisimulationMinimization<storm::RationalFunction>(model, formulas, bisimType)
132 ASSERT_EQ(99ul, model->getNumberOfStates());
133 ASSERT_EQ(195ul, model->getNumberOfTransitions());
134
135 // Create the region
136 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
137 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.9, 0.1<=pK<=0.9", modelParameters);
138 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
139
140 // Start testing
143 // Check if correct result size
144 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
145 EXPECT_EQ(1ul, result.size());
146
147 // Check if the order and general monotonicity result is correct.
148 auto order = result.begin()->first;
149 auto monotonicityResult = result.begin()->second.first;
150 EXPECT_TRUE(monotonicityResult->isDone());
151 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
152 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
153 auto assumptions = result.begin()->second.second;
154 EXPECT_EQ(0ul, assumptions.size());
155
156 // Check if result for each variable is correct
157 auto monRes = monotonicityResult->getMonotonicityResult();
158 for (auto entry : monRes) {
160 }
161}
162
163TEST_F(MonotonicityHelperTest, Brp_with_bisimulation_samples) {
164 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
165 std::string formulaAsString = "P=? [true U s=4 & i=N ]";
166 std::string constantsAsString = ""; // e.g. pL=0.9,TOACK=0.5
167
168 // Program and formula
169 storm::prism::Program program = storm::api::parseProgram(programFile);
170 program = storm::utility::prism::preprocess(program, constantsAsString);
171 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
173 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
174 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
176 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
177 model = simplifier.getSimplifiedModel();
178
179 // Apply bisimulation
181 if (storm::settings::getModule<storm::settings::modules::BisimulationSettings>().isWeakBisimulationSet()) {
183 }
184
185 model = storm::api::performBisimulationMinimization<storm::RationalFunction>(model, formulas, bisimType)
187 ASSERT_EQ(99ul, model->getNumberOfStates());
188 ASSERT_EQ(195ul, model->getNumberOfTransitions());
189
190 // Create the region
191 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
192 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.9, 0.1<=pK<=0.9", modelParameters);
193 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
194
195 // Start testing
198 // Check if correct result size
199 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
200 EXPECT_EQ(1ul, result.size());
201
202 // Check if the order and general monotonicity result is correct.
203 auto order = result.begin()->first;
204 auto monotonicityResult = result.begin()->second.first;
205 EXPECT_TRUE(monotonicityResult->isDone());
206 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
207 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
208 auto assumptions = result.begin()->second.second;
209 EXPECT_EQ(0ul, assumptions.size());
210
211 // Check if result for each variable is correct
212 auto monRes = monotonicityResult->getMonotonicityResult();
213 for (auto entry : monRes) {
215 }
216}
217
219 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/zeroconf4.pm";
220 std::string formulaAsString = "P > 0.5 [ F s=5 ]";
221 std::string constantsAsString = "n = 4"; // e.g. pL=0.9,TOACK=0.5
222
223 // Program and formula
224 storm::prism::Program program = storm::api::parseProgram(programFile);
225 program = storm::utility::prism::preprocess(program, constantsAsString);
226 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
228 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
229 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
231 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
232 model = simplifier.getSimplifiedModel();
233
235 if (storm::settings::getModule<storm::settings::modules::BisimulationSettings>().isWeakBisimulationSet()) {
237 }
238
239 model = storm::api::performBisimulationMinimization<storm::RationalFunction>(model, formulas, bisimType)
241 ASSERT_EQ(7ul, model->getNumberOfStates());
242 ASSERT_EQ(12ul, model->getNumberOfTransitions());
243
244 // Create region
245 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
246 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.9, 0.1<=pK<=0.9", modelParameters);
247 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
248
249 // Start testing
250 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 50);
251 // Check if correct result size
252 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
253 EXPECT_EQ(1ul, result.size());
254
255 // Check if the order and general monotonicity result is correct.
256 auto order = result.begin()->first;
257 auto monotonicityResult = result.begin()->second.first;
258 EXPECT_TRUE(monotonicityResult->isDone());
259 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
260 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
261 // TODO @Jip we have 1 assumption instead of 0 here
262 auto assumptions = result.begin()->second.second;
263 EXPECT_EQ(0ul, assumptions.size());
264
265 // Check if result for each variable is correct
266 auto monRes = monotonicityResult->getMonotonicityResult();
267 for (auto entry : monRes) {
269 }
270}
271
273 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/simple1.pm";
274 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
275 std::string constantsAsString = "";
276
277 // Program and formula
278 storm::prism::Program program = storm::api::parseProgram(programFile);
279 program = storm::utility::prism::preprocess(program, constantsAsString);
280 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
282 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
283 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
285 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
286 model = simplifier.getSimplifiedModel();
287 ASSERT_EQ(5ul, model->getNumberOfStates());
288 ASSERT_EQ(8ul, model->getNumberOfTransitions());
289
290 // Create region
291 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
292 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.49", modelParameters);
293 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
294
295 // Start testing
296 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
297
298 // Check if correct result size
299 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
300 EXPECT_EQ(1ul, result.size());
301
302 // Check if the order and general monotonicity result is correct.
303 auto order = result.begin()->first;
304 auto monotonicityResult = result.begin()->second.first;
305 EXPECT_TRUE(monotonicityResult->isDone());
306 EXPECT_FALSE(monotonicityResult->existsMonotonicity());
307 EXPECT_FALSE(monotonicityResult->isAllMonotonicity());
308 auto assumptions = result.begin()->second.second;
309 EXPECT_EQ(0ul, assumptions.size());
310
311 // Check if result for each variable is correct
312 auto monRes = monotonicityResult->getMonotonicityResult();
313 for (auto entry : monRes) {
315 }
316}
317
319 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy1.pm";
320 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
321 std::string constantsAsString = "";
322
323 // Program and formula
324 storm::prism::Program program = storm::api::parseProgram(programFile);
325 program = storm::utility::prism::preprocess(program, constantsAsString);
326 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
328 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
329 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
331 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
332 model = simplifier.getSimplifiedModel();
333
334 // Create region
335 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
336 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
337 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
338
339 ASSERT_EQ(5ul, model->getNumberOfStates());
340 ASSERT_EQ(8ul, model->getNumberOfTransitions());
341
342 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
343 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
344 ASSERT_EQ(1ul, result.size());
345
346 auto order = result.begin()->first;
347 auto monotonicityResult = result.begin()->second.first;
348 EXPECT_TRUE(monotonicityResult->isDone());
349 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
350 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
351 auto assumptions = result.begin()->second.second;
352 EXPECT_EQ(0ul, assumptions.size());
353
354 auto monRes = monotonicityResult->getMonotonicityResult();
355 for (auto entry : monRes) {
357 }
358}
359
361 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy2.pm";
362 std::string formulaAsString = "P > 0.5 [ F s=4 ]";
363 std::string constantsAsString = "";
364
365 // Program and formula
366 storm::prism::Program program = storm::api::parseProgram(programFile);
367 program = storm::utility::prism::preprocess(program, constantsAsString);
368 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
370 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
371 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
373 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
374 model = simplifier.getSimplifiedModel();
375
376 // Create region
377 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
378 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
379 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
380
381 ASSERT_EQ(6ul, model->getNumberOfStates());
382 ASSERT_EQ(12ul, model->getNumberOfTransitions());
383
384 // Start testing
385 auto monotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
386
387 // Check if correct result size
388 auto result = monotonicityHelper.checkMonotonicityInBuild(std::cout, false);
389 EXPECT_EQ(1ul, result.size());
390 EXPECT_FALSE(result.begin()->first->getDoneBuilding());
391}
392
393TEST_F(MonotonicityHelperTest, Casestudy3_not_monotone) {
394 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy3.pm";
395 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
396 std::string constantsAsString = "";
397
398 // Program and formula
399 storm::prism::Program program = storm::api::parseProgram(programFile);
400 program = storm::utility::prism::preprocess(program, constantsAsString);
401 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
403 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
404 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
406 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
407 model = simplifier.getSimplifiedModel();
408
409 // Create region
410 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
411 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
412 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
413
414 ASSERT_EQ(5ul, model->getNumberOfStates());
415 ASSERT_EQ(8ul, model->getNumberOfTransitions());
416
417 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
418 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
419
420 ASSERT_EQ(1ul, result.size());
421 auto order = result.begin()->first;
422
423 auto monotonicityResult = result.begin()->second.first;
424 EXPECT_TRUE(monotonicityResult->isDone());
425 EXPECT_FALSE(monotonicityResult->existsMonotonicity());
426 EXPECT_FALSE(monotonicityResult->isAllMonotonicity());
427 auto assumptions = result.begin()->second.second;
428 EXPECT_EQ(0ul, assumptions.size());
429
430 auto monRes = monotonicityResult->getMonotonicityResult();
431 for (auto entry : monRes) {
433 }
434}
435
436TEST_F(MonotonicityHelperTest, Casestudy3_monotone) {
437 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy3.pm";
438 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
439 std::string constantsAsString = "";
440
441 // Program and formula
442 storm::prism::Program program = storm::api::parseProgram(programFile);
443 program = storm::utility::prism::preprocess(program, constantsAsString);
444 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
446 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
447 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
449 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
450 model = simplifier.getSimplifiedModel();
451
452 // Create region
453 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
454 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.49", modelParameters);
455 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
456
457 ASSERT_EQ(5ul, model->getNumberOfStates());
458 ASSERT_EQ(8ul, model->getNumberOfTransitions());
459
460 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
461 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
462
463 ASSERT_EQ(1ul, result.size());
464 auto order = result.begin()->first;
465
466 auto monotonicityResult = result.begin()->second.first;
467 EXPECT_TRUE(monotonicityResult->isDone());
468 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
469 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
470 auto assumptions = result.begin()->second.second;
471 EXPECT_EQ(0ul, assumptions.size());
472
473 auto monRes = monotonicityResult->getMonotonicityResult();
474 for (auto entry : monRes) {
476 }
477}
TEST_F(MonotonicityHelperTest, Derivative_checker)
std::map< std::shared_ptr< Order >, std::pair< std::shared_ptr< MonotonicityResult< VariableType > >, std::vector< std::shared_ptr< expressions::BinaryRelationExpression > > > > checkMonotonicityInBuild(std::ostream &outfile, bool usePLA=false, std::string dotOutfileName="dotOutput")
Builds Reachability Orders for the given model and simultaneously uses them to check for Monotonicity...
static std::pair< bool, bool > checkDerivative(ValueType derivative, storage::ParameterRegion< ValueType > reg)
Checks if a derivative >=0 or/and <=0.
std::shared_ptr< ModelType > as()
Casts the model into the model type given by the template parameter.
Definition ModelBase.h:37
This class represents a discrete-time Markov chain.
Definition Dtmc.h:13
storm::utility::parametric::CoefficientType< ParametricType >::type CoefficientType
storm::utility::parametric::Valuation< ParametricType > Valuation
This class performs different steps to simplify the given (parametric) model.
std::vector< storm::jani::Property > parsePropertiesForPrismProgram(std::string const &inputString, storm::prism::Program const &program, boost::optional< std::set< std::string > > const &propertyFilter)
storm::prism::Program parseProgram(std::string const &filename, bool prismCompatibility, bool simplify)
std::vector< std::shared_ptr< storm::logic::Formula const > > extractFormulasFromProperties(std::vector< storm::jani::Property > const &properties)
std::set< storm::RationalFunctionVariable > getProbabilityParameters(Model< storm::RationalFunction > const &model)
Get all probability parameters occurring on transitions.
Definition Model.cpp:695
std::map< typename VariableType< FunctionType >::type, typename CoefficientType< FunctionType >::type > Valuation
Definition parametric.h:43
storm::prism::Program preprocess(storm::prism::Program const &program, std::map< storm::expressions::Variable, storm::expressions::Expression > const &constantDefinitions)
Definition prism.cpp:13
carl::RationalFunction< Polynomial, true > RationalFunction