Storm 1.14.0.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#pragma clang diagnostic push
5#pragma clang diagnostic ignored "-Wthread-safety-negative"
6#pragma clang diagnostic ignored "-Wundefined-reinterpret-cast"
7#pragma clang diagnostic ignored "-Wunused-template"
8#include <carl/util/stringparser.h>
9#pragma clang diagnostic pop
10
20#include "storm/api/builder.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) {
74 lowerBoundaries2.emplace(std::make_pair(var, lb));
75 upperBoundaries2.emplace(std::make_pair(var, ub));
76 }
77 for (auto var : varsQ) {
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 = program.preprocess(constantsAsString);
126 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
128 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
131 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
132 model = simplifier.getSimplifiedModel();
133
134 // Apply bisimulation
136
139 ASSERT_EQ(99ul, model->getNumberOfStates());
140 ASSERT_EQ(195ul, model->getNumberOfTransitions());
141
142 // Create the region
143 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
144 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.9, 0.1<=pK<=0.9", modelParameters);
145 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
146
147 // Start testing
150 // Check if correct result size
151 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
152 EXPECT_EQ(1ul, result.size());
153
154 // Check if the order and general monotonicity result is correct.
155 auto order = result.begin()->first;
156 auto monotonicityResult = result.begin()->second.first;
157 EXPECT_TRUE(monotonicityResult->isDone());
158 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
159 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
160 auto assumptions = result.begin()->second.second;
161 EXPECT_EQ(0ul, assumptions.size());
162
163 // Check if result for each variable is correct
164 auto monRes = monotonicityResult->getMonotonicityResult();
165 for (auto entry : monRes) {
167 }
168}
169
170TEST_F(MonotonicityHelperTest, Brp_with_bisimulation_samples) {
171 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
172 std::string formulaAsString = "P=? [true U s=4 & i=N ]";
173 std::string constantsAsString = ""; // e.g. pL=0.9,TOACK=0.5
174
175 // Program and formula
176 storm::prism::Program program = storm::api::parseProgram(programFile);
177 program = program.preprocess(constantsAsString);
178 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
180 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
183 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
184 model = simplifier.getSimplifiedModel();
185
186 // Apply bisimulation
188
191 ASSERT_EQ(99ul, model->getNumberOfStates());
192 ASSERT_EQ(195ul, model->getNumberOfTransitions());
193
194 // Create the region
195 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
196 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.9, 0.1<=pK<=0.9", modelParameters);
197 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
198
199 // Start testing
202 // Check if correct result size
203 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
204 EXPECT_EQ(1ul, result.size());
205
206 // Check if the order and general monotonicity result is correct.
207 auto order = result.begin()->first;
208 auto monotonicityResult = result.begin()->second.first;
209 EXPECT_TRUE(monotonicityResult->isDone());
210 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
211 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
212 auto assumptions = result.begin()->second.second;
213 EXPECT_EQ(0ul, assumptions.size());
214
215 // Check if result for each variable is correct
216 auto monRes = monotonicityResult->getMonotonicityResult();
217 for (auto entry : monRes) {
219 }
220}
221
223 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/zeroconf4.pm";
224 std::string formulaAsString = "P > 0.5 [ F s=5 ]";
225 std::string constantsAsString = "n = 4"; // e.g. pL=0.9,TOACK=0.5
226
227 // Program and formula
228 storm::prism::Program program = storm::api::parseProgram(programFile);
229 program = program.preprocess(constantsAsString);
230 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
232 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
235 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
236 model = simplifier.getSimplifiedModel();
237
239
242 ASSERT_EQ(7ul, model->getNumberOfStates());
243 ASSERT_EQ(12ul, model->getNumberOfTransitions());
244
245 // Create region
246 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
247 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.9, 0.1<=pK<=0.9", modelParameters);
248 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
249
250 // Start testing
251 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 50);
252 // Check if correct result size
253 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
254 EXPECT_EQ(1ul, result.size());
255
256 // Check if the order and general monotonicity result is correct.
257 auto order = result.begin()->first;
258 auto monotonicityResult = result.begin()->second.first;
259 EXPECT_TRUE(monotonicityResult->isDone());
260 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
261 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
262 // TODO @Jip we have 1 assumption instead of 0 here
263 auto assumptions = result.begin()->second.second;
264 EXPECT_EQ(0ul, assumptions.size());
265
266 // Check if result for each variable is correct
267 auto monRes = monotonicityResult->getMonotonicityResult();
268 for (auto entry : monRes) {
270 }
271}
272
274 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/simple1.pm";
275 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
276 std::string constantsAsString = "";
277
278 // Program and formula
279 storm::prism::Program program = storm::api::parseProgram(programFile);
280 program = program.preprocess(constantsAsString);
281 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
283 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
286 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
287 model = simplifier.getSimplifiedModel();
288 ASSERT_EQ(5ul, model->getNumberOfStates());
289 ASSERT_EQ(8ul, model->getNumberOfTransitions());
290
291 // Create region
292 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
293 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.49", modelParameters);
294 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
295
296 // Start testing
297 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
298
299 // Check if correct result size
300 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
301 EXPECT_EQ(1ul, result.size());
302
303 // Check if the order and general monotonicity result is correct.
304 auto order = result.begin()->first;
305 auto monotonicityResult = result.begin()->second.first;
306 EXPECT_TRUE(monotonicityResult->isDone());
307 EXPECT_FALSE(monotonicityResult->existsMonotonicity());
308 EXPECT_FALSE(monotonicityResult->isAllMonotonicity());
309 auto assumptions = result.begin()->second.second;
310 EXPECT_EQ(0ul, assumptions.size());
311
312 // Check if result for each variable is correct
313 auto monRes = monotonicityResult->getMonotonicityResult();
314 for (auto entry : monRes) {
316 }
317}
318
320 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy1.pm";
321 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
322 std::string constantsAsString = "";
323
324 // Program and formula
325 storm::prism::Program program = storm::api::parseProgram(programFile);
326 program = program.preprocess(constantsAsString);
327 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
329 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
332 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
333 model = simplifier.getSimplifiedModel();
334
335 // Create region
336 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
337 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
338 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
339
340 ASSERT_EQ(5ul, model->getNumberOfStates());
341 ASSERT_EQ(8ul, model->getNumberOfTransitions());
342
343 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
344 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
345 ASSERT_EQ(1ul, result.size());
346
347 auto order = result.begin()->first;
348 auto monotonicityResult = result.begin()->second.first;
349 EXPECT_TRUE(monotonicityResult->isDone());
350 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
351 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
352 auto assumptions = result.begin()->second.second;
353 EXPECT_EQ(0ul, assumptions.size());
354
355 auto monRes = monotonicityResult->getMonotonicityResult();
356 for (auto entry : monRes) {
358 }
359}
360
362 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy2.pm";
363 std::string formulaAsString = "P > 0.5 [ F s=4 ]";
364 std::string constantsAsString = "";
365
366 // Program and formula
367 storm::prism::Program program = storm::api::parseProgram(programFile);
368 program = program.preprocess(constantsAsString);
369 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
371 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
374 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
375 model = simplifier.getSimplifiedModel();
376
377 // Create region
378 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
379 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
380 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
381
382 ASSERT_EQ(6ul, model->getNumberOfStates());
383 ASSERT_EQ(12ul, model->getNumberOfTransitions());
384
385 // Start testing
386 auto monotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
387
388 // Check if correct result size
389 auto result = monotonicityHelper.checkMonotonicityInBuild(std::cout, false);
390 EXPECT_EQ(1ul, result.size());
391 EXPECT_FALSE(result.begin()->first->getDoneBuilding());
392}
393
394TEST_F(MonotonicityHelperTest, Casestudy3_not_monotone) {
395 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy3.pm";
396 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
397 std::string constantsAsString = "";
398
399 // Program and formula
400 storm::prism::Program program = storm::api::parseProgram(programFile);
401 program = program.preprocess(constantsAsString);
402 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
404 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
407 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
408 model = simplifier.getSimplifiedModel();
409
410 // Create region
411 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
412 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
413 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
414
415 ASSERT_EQ(5ul, model->getNumberOfStates());
416 ASSERT_EQ(8ul, model->getNumberOfTransitions());
417
418 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
419 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
420
421 ASSERT_EQ(1ul, result.size());
422 auto order = result.begin()->first;
423
424 auto monotonicityResult = result.begin()->second.first;
425 EXPECT_TRUE(monotonicityResult->isDone());
426 EXPECT_FALSE(monotonicityResult->existsMonotonicity());
427 EXPECT_FALSE(monotonicityResult->isAllMonotonicity());
428 auto assumptions = result.begin()->second.second;
429 EXPECT_EQ(0ul, assumptions.size());
430
431 auto monRes = monotonicityResult->getMonotonicityResult();
432 for (auto entry : monRes) {
434 }
435}
436
437TEST_F(MonotonicityHelperTest, Casestudy3_monotone) {
438 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy3.pm";
439 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
440 std::string constantsAsString = "";
441
442 // Program and formula
443 storm::prism::Program program = storm::api::parseProgram(programFile);
444 program = program.preprocess(constantsAsString);
445 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
447 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
450 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
451 model = simplifier.getSimplifiedModel();
452
453 // Create region
454 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
455 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.49", modelParameters);
456 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
457
458 ASSERT_EQ(5ul, model->getNumberOfStates());
459 ASSERT_EQ(8ul, model->getNumberOfTransitions());
460
461 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(model, formulas, regions, 10);
462 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
463
464 ASSERT_EQ(1ul, result.size());
465 auto order = result.begin()->first;
466
467 auto monotonicityResult = result.begin()->second.first;
468 EXPECT_TRUE(monotonicityResult->isDone());
469 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
470 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
471 auto assumptions = result.begin()->second.second;
472 EXPECT_EQ(0ul, assumptions.size());
473
474 auto monRes = monotonicityResult->getMonotonicityResult();
475 for (auto entry : monRes) {
477 }
478}
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.
This class represents a discrete-time Markov chain.
Definition Dtmc.h:13
Program preprocess(std::map< storm::expressions::Variable, storm::expressions::Expression > const &constantDefinitions) const
Preprocesses the program by defining the given constant definitions, substituting constants and formu...
Definition Program.cpp:1170
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)
std::shared_ptr< storm::models::sparse::Model< ValueType > > performBisimulationMinimization(std::shared_ptr< storm::models::sparse::Model< ValueType > > const &model, std::vector< std::shared_ptr< storm::logic::Formula const > > const &formulas, storm::storage::BisimulationType type=storm::storage::BisimulationType::Strong, bool graphPreserving=true, std::optional< double > const &tolerance=std::nullopt)
storm::storage::ParameterRegion< ValueType > parseRegion(std::string const &inputString, std::set< typename storm::storage::ParameterRegion< ValueType >::VariableType > const &consideredVariables)
Definition region.h:133
storm::prism::Program parseProgram(std::string const &filename, bool prismCompatibility, bool simplify)
std::shared_ptr< storm::models::sparse::Model< ValueType > > buildSparseModel(storm::storage::SymbolicModelDescription const &model, storm::builder::BuilderOptions const &options, typename storm::builder::ExplicitModelBuilder< ValueType >::Options const &explorationOptions=typename storm::builder::ExplicitModelBuilder< ValueType >::Options())
Definition builder.h:117
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:694
std::map< typename VariableType< FunctionType >::type, typename CoefficientType< FunctionType >::type > Valuation
Definition parametric.h:43
TargetType convertNumber(SourceType const &number)
carl::FactorizedPolynomial< RawPolynomial > Polynomial
carl::RationalFunction< Polynomial, true > RationalFunction