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
14#include "storm/api/builder.h"
15#include "storm/api/storm.h"
23
24class MonotonicityHelperTest : public ::testing::Test {
25 protected:
26 void SetUp() override {
27#ifndef STORM_HAVE_Z3
28 GTEST_SKIP() << "Z3 not available.";
29#endif
30 }
31};
32
33TEST_F(MonotonicityHelperTest, Derivative_checker) {
34 // Create the region
37 auto region = storm::storage::ParameterRegion<storm::RationalFunction>(std::move(lowerBoundaries), std::move(upperBoundaries));
38
39 // Derivative 0
40 auto constFunction = storm::RationalFunction(0);
42 EXPECT_TRUE(constFunctionRes.first);
43 EXPECT_TRUE(constFunctionRes.second);
44
45 // Derivative 5
46 constFunction = storm::RationalFunction(5);
48 EXPECT_TRUE(constFunctionRes.first);
49 EXPECT_FALSE(constFunctionRes.second);
50
51 // Derivative -4
52 constFunction = storm::RationalFunction(storm::RationalFunction(1) - constFunction);
54 EXPECT_FALSE(constFunctionRes.first);
55 EXPECT_TRUE(constFunctionRes.second);
56
57 std::shared_ptr<storm::RawPolynomialCache> cache = std::make_shared<storm::RawPolynomialCache>();
58 carl::StringParser parser;
59 parser.setVariables({"p", "q"});
60
61 // Create the region
62 auto functionP = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial<storm::RationalFunctionCoefficient>("p"), cache));
63 auto functionQ = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial<storm::RationalFunctionCoefficient>("q"), cache));
64
65 auto varsP = functionP.gatherVariables();
66 auto varsQ = functionQ.gatherVariables();
69 for (auto var : varsP) {
71 storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(0 + 0.000001);
73 storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(1 - 0.000001);
74 lowerBoundaries2.emplace(std::make_pair(var, lb));
75 upperBoundaries2.emplace(std::make_pair(var, ub));
76 }
77 for (auto var : varsQ) {
79 storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(0 + 0.000001);
81 storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(1 - 0.000001);
82 lowerBoundaries2.emplace(std::make_pair(var, lb));
83 upperBoundaries2.emplace(std::make_pair(var, ub));
84 }
85 region = storm::storage::ParameterRegion<storm::RationalFunction>(std::move(lowerBoundaries2), std::move(upperBoundaries2));
86
87 // Derivative p
88 auto function = functionP;
90 EXPECT_TRUE(functionRes.first);
91 EXPECT_FALSE(functionRes.second);
92
93 // Derivative 1-p
94 auto functionDecr = storm::RationalFunction(storm::RationalFunction(1) - function);
96 EXPECT_TRUE(functionDecrRes.first);
97 EXPECT_FALSE(functionDecrRes.second);
98
99 // Derivative 1-2p
100 auto functionNonMonotonic = storm::RationalFunction(storm::RationalFunction(1) - storm::RationalFunction(2) * function);
101 auto functionNonMonotonicRes = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>::checkDerivative(functionNonMonotonic, region);
102 EXPECT_FALSE(functionNonMonotonicRes.first);
103 EXPECT_FALSE(functionNonMonotonicRes.second);
104
105 // Derivative -p
106 functionDecr = storm::RationalFunction(storm::RationalFunction(0) - function);
108 EXPECT_FALSE(functionDecrRes.first);
109 EXPECT_TRUE(functionDecrRes.second);
110
111 // Derivative p*q
112 function = functionP * functionQ;
114 EXPECT_TRUE(functionRes.first);
115 EXPECT_FALSE(functionRes.second);
116}
117
118TEST_F(MonotonicityHelperTest, Brp_with_bisimulation_no_samples) {
119 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
120 std::string formulaAsString = "P=? [true U s=4 & i=N ]";
121 std::string constantsAsString = ""; // e.g. pL=0.9,TOACK=0.5
122
123 // Program and formula
124 storm::prism::Program program = storm::api::parseProgram(programFile);
125 program = storm::utility::prism::preprocess(program, constantsAsString);
126 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
128 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
129 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
131 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
132 model = simplifier.getSimplifiedModel();
133
134 // Apply bisimulation
136 if (storm::settings::getModule<storm::settings::modules::BisimulationSettings>().isWeakBisimulationSet()) {
138 }
139
140 model = storm::api::performBisimulationMinimization<storm::RationalFunction>(model, formulas, bisimType)
142 ASSERT_EQ(99ul, model->getNumberOfStates());
143 ASSERT_EQ(195ul, model->getNumberOfTransitions());
144
145 // Create the region
146 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
147 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.9, 0.1<=pK<=0.9", modelParameters);
148 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
149
150 // Start testing
153 // Check if correct result size
154 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
155 EXPECT_EQ(1ul, result.size());
156
157 // Check if the order and general monotonicity result is correct.
158 auto order = result.begin()->first;
159 auto monotonicityResult = result.begin()->second.first;
160 EXPECT_TRUE(monotonicityResult->isDone());
161 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
162 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
163 auto assumptions = result.begin()->second.second;
164 EXPECT_EQ(0ul, assumptions.size());
165
166 // Check if result for each variable is correct
167 auto monRes = monotonicityResult->getMonotonicityResult();
168 for (auto entry : monRes) {
170 }
171}
172
173TEST_F(MonotonicityHelperTest, Brp_with_bisimulation_samples) {
174 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
175 std::string formulaAsString = "P=? [true U s=4 & i=N ]";
176 std::string constantsAsString = ""; // e.g. pL=0.9,TOACK=0.5
177
178 // Program and formula
179 storm::prism::Program program = storm::api::parseProgram(programFile);
180 program = storm::utility::prism::preprocess(program, constantsAsString);
181 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
183 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
184 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
186 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
187 model = simplifier.getSimplifiedModel();
188
189 // Apply bisimulation
191 if (storm::settings::getModule<storm::settings::modules::BisimulationSettings>().isWeakBisimulationSet()) {
193 }
194
195 model = storm::api::performBisimulationMinimization<storm::RationalFunction>(model, formulas, bisimType)
197 ASSERT_EQ(99ul, model->getNumberOfStates());
198 ASSERT_EQ(195ul, model->getNumberOfTransitions());
199
200 // Create the region
201 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
202 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.9, 0.1<=pK<=0.9", modelParameters);
203 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
204
205 // Start testing
208 // Check if correct result size
209 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
210 EXPECT_EQ(1ul, result.size());
211
212 // Check if the order and general monotonicity result is correct.
213 auto order = result.begin()->first;
214 auto monotonicityResult = result.begin()->second.first;
215 EXPECT_TRUE(monotonicityResult->isDone());
216 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
217 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
218 auto assumptions = result.begin()->second.second;
219 EXPECT_EQ(0ul, assumptions.size());
220
221 // Check if result for each variable is correct
222 auto monRes = monotonicityResult->getMonotonicityResult();
223 for (auto entry : monRes) {
225 }
226}
227
229 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/zeroconf4.pm";
230 std::string formulaAsString = "P > 0.5 [ F s=5 ]";
231 std::string constantsAsString = "n = 4"; // e.g. pL=0.9,TOACK=0.5
232
233 // Program and formula
234 storm::prism::Program program = storm::api::parseProgram(programFile);
235 program = storm::utility::prism::preprocess(program, constantsAsString);
236 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
238 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
239 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
241 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
242 model = simplifier.getSimplifiedModel();
243
245 if (storm::settings::getModule<storm::settings::modules::BisimulationSettings>().isWeakBisimulationSet()) {
247 }
248
249 model = storm::api::performBisimulationMinimization<storm::RationalFunction>(model, formulas, bisimType)
251 ASSERT_EQ(7ul, model->getNumberOfStates());
252 ASSERT_EQ(12ul, model->getNumberOfTransitions());
253
254 // Create region
255 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
256 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.9, 0.1<=pK<=0.9", modelParameters);
257 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
258
259 // Start testing
260 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 50);
261 // Check if correct result size
262 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
263 EXPECT_EQ(1ul, result.size());
264
265 // Check if the order and general monotonicity result is correct.
266 auto order = result.begin()->first;
267 auto monotonicityResult = result.begin()->second.first;
268 EXPECT_TRUE(monotonicityResult->isDone());
269 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
270 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
271 // TODO @Jip we have 1 assumption instead of 0 here
272 auto assumptions = result.begin()->second.second;
273 EXPECT_EQ(0ul, assumptions.size());
274
275 // Check if result for each variable is correct
276 auto monRes = monotonicityResult->getMonotonicityResult();
277 for (auto entry : monRes) {
279 }
280}
281
283 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/simple1.pm";
284 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
285 std::string constantsAsString = "";
286
287 // Program and formula
288 storm::prism::Program program = storm::api::parseProgram(programFile);
289 program = storm::utility::prism::preprocess(program, constantsAsString);
290 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
292 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
293 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
295 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
296 model = simplifier.getSimplifiedModel();
297 ASSERT_EQ(5ul, model->getNumberOfStates());
298 ASSERT_EQ(8ul, model->getNumberOfTransitions());
299
300 // Create region
301 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
302 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.49", modelParameters);
303 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
304
305 // Start testing
306 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
307
308 // Check if correct result size
309 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
310 EXPECT_EQ(1ul, result.size());
311
312 // Check if the order and general monotonicity result is correct.
313 auto order = result.begin()->first;
314 auto monotonicityResult = result.begin()->second.first;
315 EXPECT_TRUE(monotonicityResult->isDone());
316 EXPECT_FALSE(monotonicityResult->existsMonotonicity());
317 EXPECT_FALSE(monotonicityResult->isAllMonotonicity());
318 auto assumptions = result.begin()->second.second;
319 EXPECT_EQ(0ul, assumptions.size());
320
321 // Check if result for each variable is correct
322 auto monRes = monotonicityResult->getMonotonicityResult();
323 for (auto entry : monRes) {
325 }
326}
327
329 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy1.pm";
330 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
331 std::string constantsAsString = "";
332
333 // Program and formula
334 storm::prism::Program program = storm::api::parseProgram(programFile);
335 program = storm::utility::prism::preprocess(program, constantsAsString);
336 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
338 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
339 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
341 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
342 model = simplifier.getSimplifiedModel();
343
344 // Create region
345 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
346 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
347 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
348
349 ASSERT_EQ(5ul, model->getNumberOfStates());
350 ASSERT_EQ(8ul, model->getNumberOfTransitions());
351
352 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
353 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
354 ASSERT_EQ(1ul, result.size());
355
356 auto order = result.begin()->first;
357 auto monotonicityResult = result.begin()->second.first;
358 EXPECT_TRUE(monotonicityResult->isDone());
359 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
360 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
361 auto assumptions = result.begin()->second.second;
362 EXPECT_EQ(0ul, assumptions.size());
363
364 auto monRes = monotonicityResult->getMonotonicityResult();
365 for (auto entry : monRes) {
367 }
368}
369
371 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy2.pm";
372 std::string formulaAsString = "P > 0.5 [ F s=4 ]";
373 std::string constantsAsString = "";
374
375 // Program and formula
376 storm::prism::Program program = storm::api::parseProgram(programFile);
377 program = storm::utility::prism::preprocess(program, constantsAsString);
378 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
380 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
381 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
383 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
384 model = simplifier.getSimplifiedModel();
385
386 // Create region
387 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
388 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
389 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
390
391 ASSERT_EQ(6ul, model->getNumberOfStates());
392 ASSERT_EQ(12ul, model->getNumberOfTransitions());
393
394 // Start testing
395 auto monotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
396
397 // Check if correct result size
398 auto result = monotonicityHelper.checkMonotonicityInBuild(std::cout, false);
399 EXPECT_EQ(1ul, result.size());
400 EXPECT_FALSE(result.begin()->first->getDoneBuilding());
401}
402
403TEST_F(MonotonicityHelperTest, Casestudy3_not_monotone) {
404 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy3.pm";
405 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
406 std::string constantsAsString = "";
407
408 // Program and formula
409 storm::prism::Program program = storm::api::parseProgram(programFile);
410 program = storm::utility::prism::preprocess(program, constantsAsString);
411 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
413 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
414 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
416 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
417 model = simplifier.getSimplifiedModel();
418
419 // Create region
420 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
421 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
422 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
423
424 ASSERT_EQ(5ul, model->getNumberOfStates());
425 ASSERT_EQ(8ul, model->getNumberOfTransitions());
426
427 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
428 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
429
430 ASSERT_EQ(1ul, result.size());
431 auto order = result.begin()->first;
432
433 auto monotonicityResult = result.begin()->second.first;
434 EXPECT_TRUE(monotonicityResult->isDone());
435 EXPECT_FALSE(monotonicityResult->existsMonotonicity());
436 EXPECT_FALSE(monotonicityResult->isAllMonotonicity());
437 auto assumptions = result.begin()->second.second;
438 EXPECT_EQ(0ul, assumptions.size());
439
440 auto monRes = monotonicityResult->getMonotonicityResult();
441 for (auto entry : monRes) {
443 }
444}
445
446TEST_F(MonotonicityHelperTest, Casestudy3_monotone) {
447 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy3.pm";
448 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
449 std::string constantsAsString = "";
450
451 // Program and formula
452 storm::prism::Program program = storm::api::parseProgram(programFile);
453 program = storm::utility::prism::preprocess(program, constantsAsString);
454 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
456 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
457 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
459 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
460 model = simplifier.getSimplifiedModel();
461
462 // Create region
463 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
464 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.49", modelParameters);
465 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
466
467 ASSERT_EQ(5ul, model->getNumberOfStates());
468 ASSERT_EQ(8ul, model->getNumberOfTransitions());
469
470 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
471 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
472
473 ASSERT_EQ(1ul, result.size());
474 auto order = result.begin()->first;
475
476 auto monotonicityResult = result.begin()->second.first;
477 EXPECT_TRUE(monotonicityResult->isDone());
478 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
479 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
480 auto assumptions = result.begin()->second.second;
481 EXPECT_EQ(0ul, assumptions.size());
482
483 auto monRes = monotonicityResult->getMonotonicityResult();
484 for (auto entry : monRes) {
486 }
487}
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:38
This class represents a discrete-time Markov chain.
Definition Dtmc.h:14
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:703
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:19
carl::RationalFunction< Polynomial, true > RationalFunction