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
5
6#pragma clang diagnostic push
7#pragma clang diagnostic ignored "-Wthread-safety-negative"
8#pragma clang diagnostic ignored "-Wundefined-reinterpret-cast"
9#pragma clang diagnostic ignored "-Wunused-template"
10#include <carl/util/stringparser.h>
11#pragma clang diagnostic pop
12
22#include "storm/api/builder.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) {
76 lowerBoundaries2.emplace(std::make_pair(var, lb));
77 upperBoundaries2.emplace(std::make_pair(var, ub));
78 }
79 for (auto var : varsQ) {
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 = program.preprocess(constantsAsString);
128 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
130 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
133 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
134 model = simplifier.getSimplifiedModel();
135
136 // Apply bisimulation
138 ASSERT_EQ(99ul, model->getNumberOfStates());
139 ASSERT_EQ(195ul, model->getNumberOfTransitions());
140
141 // Create the region
142 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
143 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.9, 0.1<=pK<=0.9", modelParameters);
144 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
145
146 // Start testing
149 // Check if correct result size
150 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
151 EXPECT_EQ(1ul, result.size());
152
153 // Check if the order and general monotonicity result is correct.
154 auto order = result.front().order;
155 auto monotonicityResult = result.front().monotonicityResult;
156 EXPECT_TRUE(monotonicityResult->isDone());
157 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
158 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
159 auto assumptions = result.front().assumptions;
160 EXPECT_EQ(0ul, assumptions.size());
161
162 // Check if result for each variable is correct
163 auto monRes = monotonicityResult->getMonotonicityResult();
164 for (auto entry : monRes) {
166 }
167}
168
169TEST_F(MonotonicityHelperTest, Brp_with_bisimulation_samples) {
170 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
171 std::string formulaAsString = "P=? [true U s=4 & i=N ]";
172 std::string constantsAsString = ""; // e.g. pL=0.9,TOACK=0.5
173
174 // Program and formula
175 storm::prism::Program program = storm::api::parseProgram(programFile);
176 program = program.preprocess(constantsAsString);
177 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
179 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
182 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
183 model = simplifier.getSimplifiedModel();
184
185 // Apply bisimulation
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.front().order;
204 auto monotonicityResult = result.front().monotonicityResult;
205 EXPECT_TRUE(monotonicityResult->isDone());
206 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
207 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
208 auto assumptions = result.front().assumptions;
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 = program.preprocess(constantsAsString);
226 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
228 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
231 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
232 model = simplifier.getSimplifiedModel();
233
235 ASSERT_EQ(7ul, model->getNumberOfStates());
236 ASSERT_EQ(12ul, model->getNumberOfTransitions());
237
238 // Create region
239 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
240 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.9, 0.1<=pK<=0.9", modelParameters);
241 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
242
243 // Start testing
244 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(storm::Environment(), model, formulas, regions, 50);
245 // Check if correct result size
246 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
247 EXPECT_EQ(1ul, result.size());
248
249 // Check if the order and general monotonicity result is correct.
250 auto order = result.front().order;
251 auto monotonicityResult = result.front().monotonicityResult;
252 EXPECT_TRUE(monotonicityResult->isDone());
253 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
254 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
255 // TODO @Jip we have 1 assumption instead of 0 here
256 auto assumptions = result.front().assumptions;
257 EXPECT_EQ(0ul, assumptions.size());
258
259 // Check if result for each variable is correct
260 auto monRes = monotonicityResult->getMonotonicityResult();
261 for (auto entry : monRes) {
263 }
264}
265
267 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/simple1.pm";
268 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
269 std::string constantsAsString = "";
270
271 // Program and formula
272 storm::prism::Program program = storm::api::parseProgram(programFile);
273 program = program.preprocess(constantsAsString);
274 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
276 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
279 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
280 model = simplifier.getSimplifiedModel();
281 ASSERT_EQ(5ul, model->getNumberOfStates());
282 ASSERT_EQ(8ul, model->getNumberOfTransitions());
283
284 // Create region
285 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
286 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.49", modelParameters);
287 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
288
289 // Start testing
290 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(storm::Environment(), model, formulas, regions, 10);
291
292 // Check if correct result size
293 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
294 EXPECT_EQ(1ul, result.size());
295
296 // Check if the order and general monotonicity result is correct.
297 auto order = result.front().order;
298 auto monotonicityResult = result.front().monotonicityResult;
299 EXPECT_TRUE(monotonicityResult->isDone());
300 EXPECT_FALSE(monotonicityResult->existsMonotonicity());
301 EXPECT_FALSE(monotonicityResult->isAllMonotonicity());
302 auto assumptions = result.front().assumptions;
303 EXPECT_EQ(0ul, assumptions.size());
304
305 // Check if result for each variable is correct
306 auto monRes = monotonicityResult->getMonotonicityResult();
307 for (auto entry : monRes) {
309 }
310}
311
313 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy1.pm";
314 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
315 std::string constantsAsString = "";
316
317 // Program and formula
318 storm::prism::Program program = storm::api::parseProgram(programFile);
319 program = program.preprocess(constantsAsString);
320 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
322 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
325 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
326 model = simplifier.getSimplifiedModel();
327
328 // Create region
329 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
330 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
331 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
332
333 ASSERT_EQ(5ul, model->getNumberOfStates());
334 ASSERT_EQ(8ul, model->getNumberOfTransitions());
335
336 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(storm::Environment(), model, formulas, regions, 10);
337 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
338 ASSERT_EQ(1ul, result.size());
339
340 auto order = result.front().order;
341 auto monotonicityResult = result.front().monotonicityResult;
342 EXPECT_TRUE(monotonicityResult->isDone());
343 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
344 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
345 auto assumptions = result.front().assumptions;
346 EXPECT_EQ(0ul, assumptions.size());
347
348 auto monRes = monotonicityResult->getMonotonicityResult();
349 for (auto entry : monRes) {
351 }
352}
353
355 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy2.pm";
356 std::string formulaAsString = "P > 0.5 [ F s=4 ]";
357 std::string constantsAsString = "";
358
359 // Program and formula
360 storm::prism::Program program = storm::api::parseProgram(programFile);
361 program = program.preprocess(constantsAsString);
362 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
364 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
367 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
368 model = simplifier.getSimplifiedModel();
369
370 // Create region
371 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
372 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
373 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
374
375 ASSERT_EQ(6ul, model->getNumberOfStates());
376 ASSERT_EQ(12ul, model->getNumberOfTransitions());
377
378 // Start testing
379 auto monotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(storm::Environment(), model, formulas, regions, 10);
380
381 // Check if correct result size
382 auto result = monotonicityHelper.checkMonotonicityInBuild(std::cout, false);
383 EXPECT_EQ(1ul, result.size());
384 EXPECT_FALSE(result.front().order->getDoneBuilding());
385}
386
387TEST_F(MonotonicityHelperTest, Casestudy3_not_monotone) {
388 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy3.pm";
389 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
390 std::string constantsAsString = "";
391
392 // Program and formula
393 storm::prism::Program program = storm::api::parseProgram(programFile);
394 program = program.preprocess(constantsAsString);
395 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
397 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
400 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
401 model = simplifier.getSimplifiedModel();
402
403 // Create region
404 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
405 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.9", modelParameters);
406 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
407
408 ASSERT_EQ(5ul, model->getNumberOfStates());
409 ASSERT_EQ(8ul, model->getNumberOfTransitions());
410
411 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(storm::Environment(), model, formulas, regions, 10);
412 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
413
414 ASSERT_EQ(1ul, result.size());
415 auto order = result.front().order;
416
417 auto monotonicityResult = result.front().monotonicityResult;
418 EXPECT_TRUE(monotonicityResult->isDone());
419 EXPECT_FALSE(monotonicityResult->existsMonotonicity());
420 EXPECT_FALSE(monotonicityResult->isAllMonotonicity());
421 auto assumptions = result.front().assumptions;
422 EXPECT_EQ(0ul, assumptions.size());
423
424 auto monRes = monotonicityResult->getMonotonicityResult();
425 for (auto entry : monRes) {
427 }
428}
429
430TEST_F(MonotonicityHelperTest, Casestudy3_monotone) {
431 std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/casestudy3.pm";
432 std::string formulaAsString = "P > 0.5 [ F s=3 ]";
433 std::string constantsAsString = "";
434
435 // Program and formula
436 storm::prism::Program program = storm::api::parseProgram(programFile);
437 program = program.preprocess(constantsAsString);
438 std::vector<std::shared_ptr<const storm::logic::Formula>> formulas =
440 std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model =
443 ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
444 model = simplifier.getSimplifiedModel();
445
446 // Create region
447 auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
448 auto region = storm::api::parseRegion<storm::RationalFunction>("0.1<=p<=0.49", modelParameters);
449 std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
450
451 ASSERT_EQ(5ul, model->getNumberOfStates());
452 ASSERT_EQ(8ul, model->getNumberOfTransitions());
453
454 auto MonotonicityHelper = storm::analysis::MonotonicityHelper<storm::RationalFunction, double>(storm::Environment(), model, formulas, regions, 10);
455 auto result = MonotonicityHelper.checkMonotonicityInBuild(std::cout, false);
456
457 ASSERT_EQ(1ul, result.size());
458 auto order = result.front().order;
459
460 auto monotonicityResult = result.front().monotonicityResult;
461 EXPECT_TRUE(monotonicityResult->isDone());
462 EXPECT_TRUE(monotonicityResult->existsMonotonicity());
463 EXPECT_TRUE(monotonicityResult->isAllMonotonicity());
464 auto assumptions = result.front().assumptions;
465 EXPECT_EQ(0ul, assumptions.size());
466
467 auto monRes = monotonicityResult->getMonotonicityResult();
468 for (auto entry : monRes) {
470 }
471}
TEST_F(MonotonicityHelperTest, Derivative_checker)
std::vector< ExpectedMonotonicityResult > 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:16
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.
storm::storage::ParameterRegion< ValueType > parseRegion(std::string const &inputString, std::set< typename storm::storage::ParameterRegion< ValueType >::VariableType > const &consideredVariables)
Definition region.h:134
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::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::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::bisimulation::Options const &options={})
std::set< storm::RationalFunctionVariable > getProbabilityParameters(Model< storm::RationalFunction > const &model)
Get all probability parameters occurring on transitions.
Definition Model.cpp:732
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