Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
MonotonicityHelperTest.cpp
Go to the documentation of this file.
1#include "storm-config.h"
5#include "test/storm_gtest.h"
6
10#include "storm/api/builder.h"
16
18
20#include "storm/api/storm.h"
21
23
24#include "carl/util/stringparser.h"
25
26class MonotonicityHelperTest : public ::testing::Test {
27 protected:
28 void SetUp() override {
29#ifndef STORM_HAVE_Z3
30 GTEST_SKIP() << "Z3 not available.";
31#endif
32 }
33};
34
35TEST_F(MonotonicityHelperTest, Derivative_checker) {
36 // Create the region
39 auto region = storm::storage::ParameterRegion<storm::RationalFunction>(std::move(lowerBoundaries), std::move(upperBoundaries));
40
41 // Derivative 0
42 auto constFunction = storm::RationalFunction(0);
44 EXPECT_TRUE(constFunctionRes.first);
45 EXPECT_TRUE(constFunctionRes.second);
46
47 // Derivative 5
48 constFunction = storm::RationalFunction(5);
50 EXPECT_TRUE(constFunctionRes.first);
51 EXPECT_FALSE(constFunctionRes.second);
52
53 // Derivative -4
54 constFunction = storm::RationalFunction(storm::RationalFunction(1) - constFunction);
56 EXPECT_FALSE(constFunctionRes.first);
57 EXPECT_TRUE(constFunctionRes.second);
58
59 std::shared_ptr<storm::RawPolynomialCache> cache = std::make_shared<storm::RawPolynomialCache>();
60 carl::StringParser parser;
61 parser.setVariables({"p", "q"});
62
63 // Create the region
64 auto functionP = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial<storm::RationalFunctionCoefficient>("p"), cache));
65 auto functionQ = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial<storm::RationalFunctionCoefficient>("q"), cache));
66
67 auto varsP = functionP.gatherVariables();
68 auto varsQ = functionQ.gatherVariables();
71 for (auto var : varsP) {
73 storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(0 + 0.000001);
75 storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(1 - 0.000001);
76 lowerBoundaries2.emplace(std::make_pair(var, lb));
77 upperBoundaries2.emplace(std::make_pair(var, ub));
78 }
79 for (auto var : varsQ) {
81 storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(0 + 0.000001);
83 storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(1 - 0.000001);
84 lowerBoundaries2.emplace(std::make_pair(var, lb));
85 upperBoundaries2.emplace(std::make_pair(var, ub));
86 }
87 region = storm::storage::ParameterRegion<storm::RationalFunction>(std::move(lowerBoundaries2), std::move(upperBoundaries2));
88
89 // Derivative p
90 auto function = functionP;
92 EXPECT_TRUE(functionRes.first);
93 EXPECT_FALSE(functionRes.second);
94
95 // Derivative 1-p
96 auto functionDecr = storm::RationalFunction(storm::RationalFunction(1) - function);
98 EXPECT_TRUE(functionDecrRes.first);
99 EXPECT_FALSE(functionDecrRes.second);
100
101 // Derivative 1-2p
102 auto functionNonMonotonic = storm::RationalFunction(storm::RationalFunction(1) - storm::RationalFunction(2) * function);
103 auto functionNonMonotonicRes = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>::checkDerivative(functionNonMonotonic, region);
104 EXPECT_FALSE(functionNonMonotonicRes.first);
105 EXPECT_FALSE(functionNonMonotonicRes.second);
106
107 // Derivative -p
108 functionDecr = storm::RationalFunction(storm::RationalFunction(0) - function);
110 EXPECT_FALSE(functionDecrRes.first);
111 EXPECT_TRUE(functionDecrRes.second);
112
113 // Derivative p*q
114 function = functionP * functionQ;
116 EXPECT_TRUE(functionRes.first);
117 EXPECT_FALSE(functionRes.second);
118}
119
120TEST_F(MonotonicityHelperTest, Brp_with_bisimulation_no_samples) {
121 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
122 std::string formulaAsString = "P=? [true U s=4 & i=N ]";
123 std::string constantsAsString = ""; // e.g. pL=0.9,TOACK=0.5
124
125 // Program and formula
126 storm::prism::Program program = storm::api::parseProgram(programFile);
127 program = storm::utility::prism::preprocess(program, constantsAsString);
128 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
130 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
131 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
133 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
134 model = simplifier.getSimplifiedModel();
135
136 // Apply bisimulation
140 }
141
142 model = storm::api::performBisimulationMinimization<storm::RationalFunction>(model, formulas, bisimType)
144 ASSERT_EQ(99ul, model->getNumberOfStates());
145 ASSERT_EQ(195ul, model->getNumberOfTransitions());
146
147 // Create the region
148 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
149 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.9, 0.1<=pK<=0.9", modelParameters);
150 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
151
152 // Start testing
155 // Check if correct result size
156 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
157 EXPECT_EQ(1ul, result.size());
158
159 // Check if the order and general monotonicity result is correct.
160 auto order = result.begin()->first;
161 auto monotonicityResult = result.begin()->second.first;
162 EXPECT_TRUE(monotonicityResult->isDone());
163 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
164 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
165 auto assumptions = result.begin()->second.second;
166 EXPECT_EQ(0ul, assumptions.size());
167
168 // Check if result for each variable is correct
169 auto monRes = monotonicityResult->getMonotonicityResult();
170 for (auto entry : monRes) {
172 }
173}
174
175TEST_F(MonotonicityHelperTest, Brp_with_bisimulation_samples) {
176 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
177 std::string formulaAsString = "P=? [true U s=4 & i=N ]";
178 std::string constantsAsString = ""; // e.g. pL=0.9,TOACK=0.5
179
180 // Program and formula
181 storm::prism::Program program = storm::api::parseProgram(programFile);
182 program = storm::utility::prism::preprocess(program, constantsAsString);
183 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
185 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
186 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
188 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
189 model = simplifier.getSimplifiedModel();
190
191 // Apply bisimulation
195 }
196
197 model = storm::api::performBisimulationMinimization<storm::RationalFunction>(model, formulas, bisimType)
199 ASSERT_EQ(99ul, model->getNumberOfStates());
200 ASSERT_EQ(195ul, model->getNumberOfTransitions());
201
202 // Create the region
203 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
204 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.9, 0.1<=pK<=0.9", modelParameters);
205 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
206
207 // Start testing
210 // Check if correct result size
211 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
212 EXPECT_EQ(1ul, result.size());
213
214 // Check if the order and general monotonicity result is correct.
215 auto order = result.begin()->first;
216 auto monotonicityResult = result.begin()->second.first;
217 EXPECT_TRUE(monotonicityResult->isDone());
218 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
219 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
220 auto assumptions = result.begin()->second.second;
221 EXPECT_EQ(0ul, assumptions.size());
222
223 // Check if result for each variable is correct
224 auto monRes = monotonicityResult->getMonotonicityResult();
225 for (auto entry : monRes) {
227 }
228}
229
231 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/zeroconf4.pm";
232 std::string formulaAsString = "P > 0.5 [ F s=5 ]";
233 std::string constantsAsString = "n = 4"; // e.g. pL=0.9,TOACK=0.5
234
235 // Program and formula
236 storm::prism::Program program = storm::api::parseProgram(programFile);
237 program = storm::utility::prism::preprocess(program, constantsAsString);
238 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
240 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
241 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
243 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
244 model = simplifier.getSimplifiedModel();
245
249 }
250
251 model = storm::api::performBisimulationMinimization<storm::RationalFunction>(model, formulas, bisimType)
253 ASSERT_EQ(7ul, model->getNumberOfStates());
254 ASSERT_EQ(12ul, model->getNumberOfTransitions());
255
256 // Create region
257 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
258 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.9, 0.1<=pK<=0.9", modelParameters);
259 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
260
261 // Start testing
262 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 50);
263 // Check if correct result size
264 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
265 EXPECT_EQ(1ul, result.size());
266
267 // Check if the order and general monotonicity result is correct.
268 auto order = result.begin()->first;
269 auto monotonicityResult = result.begin()->second.first;
270 EXPECT_TRUE(monotonicityResult->isDone());
271 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
272 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
273 // TODO @Jip we have 1 assumption instead of 0 here
274 auto assumptions = result.begin()->second.second;
275 EXPECT_EQ(0ul, assumptions.size());
276
277 // Check if result for each variable is correct
278 auto monRes = monotonicityResult->getMonotonicityResult();
279 for (auto entry : monRes) {
281 }
282}
283
285 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/simple1.pm";
286 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
287 std::string constantsAsString = "";
288
289 // Program and formula
290 storm::prism::Program program = storm::api::parseProgram(programFile);
291 program = storm::utility::prism::preprocess(program, constantsAsString);
292 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
294 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
295 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
297 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
298 model = simplifier.getSimplifiedModel();
299 ASSERT_EQ(5ul, model->getNumberOfStates());
300 ASSERT_EQ(8ul, model->getNumberOfTransitions());
301
302 // Create region
303 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
304 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.49", modelParameters);
305 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
306
307 // Start testing
308 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
309
310 // Check if correct result size
311 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
312 EXPECT_EQ(1ul, result.size());
313
314 // Check if the order and general monotonicity result is correct.
315 auto order = result.begin()->first;
316 auto monotonicityResult = result.begin()->second.first;
317 EXPECT_TRUE(monotonicityResult->isDone());
318 EXPECT_FALSE(monotonicityResult->existsMonotonicity());
319 EXPECT_FALSE(monotonicityResult->isAllMonotonicity());
320 auto assumptions = result.begin()->second.second;
321 EXPECT_EQ(0ul, assumptions.size());
322
323 // Check if result for each variable is correct
324 auto monRes = monotonicityResult->getMonotonicityResult();
325 for (auto entry : monRes) {
327 }
328}
329
331 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy1.pm";
332 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
333 std::string constantsAsString = "";
334
335 // Program and formula
336 storm::prism::Program program = storm::api::parseProgram(programFile);
337 program = storm::utility::prism::preprocess(program, constantsAsString);
338 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
340 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
341 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
343 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
344 model = simplifier.getSimplifiedModel();
345
346 // Create region
347 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
348 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
349 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
350
351 ASSERT_EQ(5ul, model->getNumberOfStates());
352 ASSERT_EQ(8ul, model->getNumberOfTransitions());
353
354 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
355 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
356 ASSERT_EQ(1ul, result.size());
357
358 auto order = result.begin()->first;
359 auto monotonicityResult = result.begin()->second.first;
360 EXPECT_TRUE(monotonicityResult->isDone());
361 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
362 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
363 auto assumptions = result.begin()->second.second;
364 EXPECT_EQ(0ul, assumptions.size());
365
366 auto monRes = monotonicityResult->getMonotonicityResult();
367 for (auto entry : monRes) {
369 }
370}
371
373 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy2.pm";
374 std::string formulaAsString = "P > 0.5 [ F s=4 ]";
375 std::string constantsAsString = "";
376
377 // Program and formula
378 storm::prism::Program program = storm::api::parseProgram(programFile);
379 program = storm::utility::prism::preprocess(program, constantsAsString);
380 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
382 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
383 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
385 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
386 model = simplifier.getSimplifiedModel();
387
388 // Create region
389 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
390 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
391 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
392
393 ASSERT_EQ(6ul, model->getNumberOfStates());
394 ASSERT_EQ(12ul, model->getNumberOfTransitions());
395
396 // Start testing
397 auto monotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
398
399 // Check if correct result size
400 auto result = monotonicityHelper.checkMonotonicityInBuild(std::cout, false);
401 EXPECT_EQ(1ul, result.size());
402 EXPECT_FALSE(result.begin()->first->getDoneBuilding());
403}
404
405TEST_F(MonotonicityHelperTest, Casestudy3_not_monotone) {
406 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy3.pm";
407 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
408 std::string constantsAsString = "";
409
410 // Program and formula
411 storm::prism::Program program = storm::api::parseProgram(programFile);
412 program = storm::utility::prism::preprocess(program, constantsAsString);
413 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
415 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
416 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
418 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
419 model = simplifier.getSimplifiedModel();
420
421 // Create region
422 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
423 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
424 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
425
426 ASSERT_EQ(5ul, model->getNumberOfStates());
427 ASSERT_EQ(8ul, model->getNumberOfTransitions());
428
429 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
430 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
431
432 ASSERT_EQ(1ul, result.size());
433 auto order = result.begin()->first;
434
435 auto monotonicityResult = result.begin()->second.first;
436 EXPECT_TRUE(monotonicityResult->isDone());
437 EXPECT_FALSE(monotonicityResult->existsMonotonicity());
438 EXPECT_FALSE(monotonicityResult->isAllMonotonicity());
439 auto assumptions = result.begin()->second.second;
440 EXPECT_EQ(0ul, assumptions.size());
441
442 auto monRes = monotonicityResult->getMonotonicityResult();
443 for (auto entry : monRes) {
445 }
446}
447
448TEST_F(MonotonicityHelperTest, Casestudy3_monotone) {
449 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy3.pm";
450 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
451 std::string constantsAsString = "";
452
453 // Program and formula
454 storm::prism::Program program = storm::api::parseProgram(programFile);
455 program = storm::utility::prism::preprocess(program, constantsAsString);
456 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
458 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
459 storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
461 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
462 model = simplifier.getSimplifiedModel();
463
464 // Create region
465 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
466 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.49", modelParameters);
467 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
468
469 ASSERT_EQ(5ul, model->getNumberOfStates());
470 ASSERT_EQ(8ul, model->getNumberOfTransitions());
471
472 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
473 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
474
475 ASSERT_EQ(1ul, result.size());
476 auto order = result.begin()->first;
477
478 auto monotonicityResult = result.begin()->second.first;
479 EXPECT_TRUE(monotonicityResult->isDone());
480 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
481 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
482 auto assumptions = result.begin()->second.second;
483 EXPECT_EQ(0ul, assumptions.size());
484
485 auto monRes = monotonicityResult->getMonotonicityResult();
486 for (auto entry : monRes) {
488 }
489}
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:36
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
SettingsType const & getModule()
Get module.
std::map< typename VariableType< FunctionType >::type, typename CoefficientType< FunctionType >::type > Valuation
Definition parametric.h:41
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