Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
QuantileQueryTest.cpp
Go to the documentation of this file.
1#include "storm-config.h"
2#include "test/storm_gtest.h"
3
4#include "test/storm_gtest.h"
5
8#include "storm/api/builder.h"
11
22
23namespace {
24
25enum class MdpEngine { PrismSparse, JaniSparse, Hybrid, PrismDd, JaniDd };
26
27class UnsoundEnvironment {
28 public:
29 typedef double ValueType;
30 static storm::Environment createEnvironment() {
32 env.solver().minMax().setPrecision(storm::utility::convertNumber<storm::RationalNumber>(1e-10));
33 return env;
34 }
35};
36
37class SoundEnvironment {
38 public:
39 typedef double ValueType;
40 static storm::Environment createEnvironment() {
42 env.solver().setForceSoundness(true);
43 return env;
44 }
45};
46
47class ExactEnvironment {
48 public:
49 typedef storm::RationalNumber ValueType;
50 static storm::Environment createEnvironment() {
52 return env;
53 }
54};
55
56template<typename TestType>
57class QuantileQueryTest : public ::testing::Test {
58 public:
59 typedef typename TestType::ValueType ValueType;
60 QuantileQueryTest() : _environment(TestType::createEnvironment()) {}
61
62 void SetUp() override {
63#ifndef STORM_HAVE_Z3
64 GTEST_SKIP() << "Z3 not available.";
65#endif
66 }
67
68 storm::Environment const& env() const {
69 return _environment;
70 }
71 ValueType parseNumber(std::string const& input) const {
72 if (input.find("inf") != std::string::npos) {
73 return storm::utility::infinity<ValueType>();
74 }
75 return storm::utility::convertNumber<ValueType>(input);
76 }
77
78 template<typename MT>
79 std::pair<std::shared_ptr<MT>, std::vector<std::shared_ptr<storm::logic::Formula const>>> buildModelFormulas(
80 std::string const& pathToPrismFile, std::string const& formulasAsString, std::string const& constantDefinitionString = "") const {
81 std::pair<std::shared_ptr<MT>, std::vector<std::shared_ptr<storm::logic::Formula const>>> result;
82 storm::prism::Program program = storm::api::parseProgram(pathToPrismFile);
83 program = storm::utility::prism::preprocess(program, constantDefinitionString);
85 result.first = storm::api::buildSparseModel<ValueType>(program, result.second)->template as<MT>();
86 return result;
87 }
88
89 std::vector<storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>> getTasks(
90 std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) const {
91 std::vector<storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>> result;
92 for (auto const& f : formulas) {
93 result.emplace_back(*f, true); // only initial states are relevant
94 }
95 return result;
96 }
97
98 template<typename MT>
99 typename std::enable_if<std::is_same<MT, storm::models::sparse::Mdp<ValueType>>::value,
100 std::shared_ptr<storm::modelchecker::AbstractModelChecker<MT>>>::type
101 createModelChecker(std::shared_ptr<MT> const& model) const {
102 return std::make_shared<storm::modelchecker::SparseMdpPrctlModelChecker<MT>>(*model);
103 }
104 template<typename MT>
105 typename std::enable_if<std::is_same<MT, storm::models::sparse::Dtmc<ValueType>>::value,
106 std::shared_ptr<storm::modelchecker::AbstractModelChecker<MT>>>::type
107 createModelChecker(std::shared_ptr<MT> const& model) const {
108 return std::make_shared<storm::modelchecker::SparseDtmcPrctlModelChecker<MT>>(*model);
109 }
110
111 std::pair<bool, std::string> compareResult(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model,
112 std::unique_ptr<storm::modelchecker::CheckResult>& result, std::vector<std::string> const& expected) {
113 bool equal = true;
114 std::string errorMessage = "";
115 ValueType comparePrecision =
116 std::is_same<ValueType, double>::value ? storm::utility::convertNumber<ValueType>(1e-10) : storm::utility::zero<ValueType>();
117 auto filter = getInitialStateFilter(model);
118 result->filter(*filter);
119 std::vector<std::vector<ValueType>> resultPoints;
120 if (result->isExplicitParetoCurveCheckResult()) {
121 resultPoints = result->asExplicitParetoCurveCheckResult<ValueType>().getPoints();
122 } else {
123 if (!result->isExplicitQuantitativeCheckResult()) {
124 return {false, "The CheckResult has unexpected type."};
125 }
126 resultPoints = {{result->asExplicitQuantitativeCheckResult<ValueType>().getMax()}};
127 }
128 std::vector<std::vector<ValueType>> expectedPoints;
129 for (auto const& pointAsString : expected) {
130 std::vector<ValueType> point;
131 for (auto const& entry : storm::parser::parseCommaSeperatedValues(pointAsString)) {
132 point.push_back(parseNumber(entry));
133 }
134 expectedPoints.push_back(std::move(point));
135 }
136 for (auto const& resPoint : resultPoints) {
137 bool contained = false;
138 for (auto const& expPoint : expectedPoints) {
139 if (storm::utility::vector::equalModuloPrecision(resPoint, expPoint, comparePrecision, true)) {
140 contained = true;
141 break;
142 }
143 }
144 if (!contained) {
145 equal = false;
146 errorMessage += "The result " + storm::utility::vector::toString(resPoint) + " is not contained in the expected solution. ";
147 }
148 }
149 for (auto const& expPoint : expectedPoints) {
150 bool contained = false;
151 for (auto const& resPoint : resultPoints) {
152 if (storm::utility::vector::equalModuloPrecision(resPoint, expPoint, comparePrecision, true)) {
153 contained = true;
154 break;
155 }
156 }
157 if (!contained) {
158 equal = false;
159 errorMessage += "The expected " + storm::utility::vector::toString(expPoint) + " is not contained in the obtained solution. ";
160 }
161 }
162 return {equal, errorMessage};
163 }
164
165 private:
166 storm::Environment _environment;
167
168 std::unique_ptr<storm::modelchecker::QualitativeCheckResult> getInitialStateFilter(
169 std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model) const {
170 return std::make_unique<storm::modelchecker::ExplicitQualitativeCheckResult>(model->getInitialStates());
171 }
172};
173
174typedef ::testing::Types<UnsoundEnvironment, SoundEnvironment, ExactEnvironment> TestingTypes;
175
176TYPED_TEST_SUITE(QuantileQueryTest, TestingTypes, );
177
178TYPED_TEST(QuantileQueryTest, simple_Dtmc) {
180
181 std::string formulasString = "quantile(max A, max B, P>0.95 [F{\"first\"}<=A,{\"second\"}<=B s=3]);\n";
182
183 auto modelFormulas = this->template buildModelFormulas<ModelType>(STORM_TEST_RESOURCES_DIR "/dtmc/quantiles_simple_dtmc.pm", formulasString);
184 auto model = std::move(modelFormulas.first);
185 auto tasks = this->getTasks(modelFormulas.second);
186 EXPECT_EQ(4ul, model->getNumberOfStates());
187 EXPECT_EQ(6ul, model->getNumberOfTransitions());
188 auto checker = this->template createModelChecker<ModelType>(model);
189 std::unique_ptr<storm::modelchecker::CheckResult> result;
190 std::vector<std::string> expectedResult;
191 std::pair<bool, std::string> compare;
192 uint64_t taskId = 0;
193
194 expectedResult.clear();
195 expectedResult.push_back("7, 18");
196 expectedResult.push_back("8, 16");
197 expectedResult.push_back("9, 14");
198 result = checker->check(this->env(), tasks[taskId++]);
199 compare = this->compareResult(model, result, expectedResult);
200 EXPECT_TRUE(compare.first) << compare.second;
201}
202
203TYPED_TEST(QuantileQueryTest, simple_Mdp) {
205
206 std::string formulasString = "quantile(B1, B2, Pmax>0.5 [F{\"first\"}>=B1,{\"second\"}>=B2 s=1]);\n";
207 formulasString += "quantile(B1, B2, Pmax>0.5 [F{\"first\"}<=B1,{\"second\"}<=B2 s=1]);\n";
208 formulasString += "quantile(B1, B2, Pmin>0.5 [F{\"first\"}<=B1,{\"second\"}<=B2 s=1]);\n";
209 formulasString += "quantile(B1, Pmax>0.5 [F{\"second\"}>=B1 s=1]);\n";
210 formulasString += "quantile(B1, B2, B3, Pmax>0.5 [F{\"first\"}<=B1,{\"second\"}<=B2,{\"third\"}<=B3 s=1]);\n";
211
212 auto modelFormulas = this->template buildModelFormulas<ModelType>(STORM_TEST_RESOURCES_DIR "/mdp/quantiles_simple_mdp.nm", formulasString);
213 auto model = std::move(modelFormulas.first);
214 auto tasks = this->getTasks(modelFormulas.second);
215 EXPECT_EQ(7ul, model->getNumberOfStates());
216 EXPECT_EQ(13ul, model->getNumberOfTransitions());
217 auto checker = this->template createModelChecker<ModelType>(model);
218 std::unique_ptr<storm::modelchecker::CheckResult> result;
219 std::vector<std::string> expectedResult;
220 std::pair<bool, std::string> compare;
221 uint64_t taskId = 0;
222
223 expectedResult.clear();
224 expectedResult.push_back(" 0, 6");
225 expectedResult.push_back(" 1, 5");
226 expectedResult.push_back(" 2, 4");
227 expectedResult.push_back(" 3, 3");
228 expectedResult.push_back("inf, 2");
229 result = checker->check(this->env(), tasks[taskId++]);
230 compare = this->compareResult(model, result, expectedResult);
231 EXPECT_TRUE(compare.first) << compare.second;
232
233 expectedResult.clear();
234 expectedResult.push_back(" 0, 2");
235 expectedResult.push_back(" 5, 1");
236 expectedResult.push_back(" 6, 0");
237 result = checker->check(this->env(), tasks[taskId++]);
238 compare = this->compareResult(model, result, expectedResult);
239 EXPECT_TRUE(compare.first) << compare.second;
240
241 expectedResult.clear();
242 result = checker->check(this->env(), tasks[taskId++]);
243 compare = this->compareResult(model, result, expectedResult);
244 EXPECT_TRUE(compare.first) << compare.second;
245
246 expectedResult.clear();
247 expectedResult.push_back(" 6");
248 result = checker->check(this->env(), tasks[taskId++]);
249 compare = this->compareResult(model, result, expectedResult);
250 EXPECT_TRUE(compare.first) << compare.second;
251
252 expectedResult.clear();
253 expectedResult.push_back(" 0, 2, 1.4");
254 expectedResult.push_back(" 5, 1, 9.8");
255 expectedResult.push_back(" 6, 0, 9.8");
256 result = checker->check(this->env(), tasks[taskId++]);
257 compare = this->compareResult(model, result, expectedResult);
258 EXPECT_TRUE(compare.first) << compare.second;
259}
260
261TYPED_TEST(QuantileQueryTest, firewire) {
263
264 std::string formulasString = "quantile(min TIME, min ROUNDS, Pmax>0.95 [F{\"time\"}<=TIME,{\"rounds\"}<=ROUNDS \"done\"]);\n";
265
266 auto modelFormulas = this->template buildModelFormulas<ModelType>(STORM_TEST_RESOURCES_DIR "/mdp/quantiles_firewire.nm", formulasString, "delay=36");
267 auto model = std::move(modelFormulas.first);
268 auto tasks = this->getTasks(modelFormulas.second);
269 EXPECT_EQ(776ul, model->getNumberOfStates());
270 EXPECT_EQ(1411ul, model->getNumberOfTransitions());
271 auto checker = this->template createModelChecker<ModelType>(model);
272 std::unique_ptr<storm::modelchecker::CheckResult> result;
273 std::vector<std::string> expectedResult;
274 std::pair<bool, std::string> compare;
275 uint64_t taskId = 0;
276
277 expectedResult.clear();
278 expectedResult.push_back("123, 1");
279 result = checker->check(this->env(), tasks[taskId++]);
280 compare = this->compareResult(model, result, expectedResult);
281 EXPECT_TRUE(compare.first) << compare.second;
282}
283
284TYPED_TEST(QuantileQueryTest, resources) {
286
287 std::string formulasString = "quantile(max GOLD, max GEM, Pmax>0.95 [F{\"gold\"}>=GOLD,{\"gem\"}>=GEM,{\"steps\"}<=100 true]);\n";
288
289 auto modelFormulas = this->template buildModelFormulas<ModelType>(STORM_TEST_RESOURCES_DIR "/mdp/quantiles_resources.nm", formulasString);
290 auto model = std::move(modelFormulas.first);
291 auto tasks = this->getTasks(modelFormulas.second);
292 EXPECT_EQ(94ul, model->getNumberOfStates());
293 EXPECT_EQ(326ul, model->getNumberOfTransitions());
294 auto checker = this->template createModelChecker<ModelType>(model);
295 std::unique_ptr<storm::modelchecker::CheckResult> result;
296 std::vector<std::string> expectedResult;
297 std::pair<bool, std::string> compare;
298 uint64_t taskId = 0;
299
300 expectedResult.clear();
301 expectedResult.push_back("0, 10");
302 expectedResult.push_back("1, 9");
303 expectedResult.push_back("4, 8");
304 expectedResult.push_back("7, 7");
305 expectedResult.push_back("8, 4");
306 expectedResult.push_back("9, 2");
307 expectedResult.push_back("10, 0");
308 result = checker->check(this->env(), tasks[taskId++]);
309 compare = this->compareResult(model, result, expectedResult);
310 EXPECT_TRUE(compare.first) << compare.second;
311}
312} // namespace
std::unique_ptr< storm::modelchecker::QualitativeCheckResult > getInitialStateFilter(std::shared_ptr< storm::models::sparse::Model< storm::Interval > > const &model)
SolverEnvironment & solver()
void setPrecision(storm::RationalNumber value)
MinMaxSolverEnvironment & minMax()
This class represents a discrete-time Markov chain.
Definition Dtmc.h:14
This class represents a (discrete-time) Markov decision process.
Definition Mdp.h:14
Base class for all sparse models.
Definition Model.h:33
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)
SFTBDDChecker::ValueType ValueType
NumberType parseNumber(std::string const &value)
Parse number from string.
std::vector< std::string > parseCommaSeperatedValues(std::string const &input)
Given a string seperated by commas, returns the values.
Definition CSVParser.cpp:11
storm::prism::Program preprocess(storm::prism::Program const &program, std::map< storm::expressions::Variable, storm::expressions::Expression > const &constantDefinitions)
Definition prism.cpp:19
storm::storage::BitVector filter(std::vector< T > const &values, std::function< bool(T const &value)> const &function)
Retrieves a bit vector containing all the indices for which the value at this position makes the give...
Definition vector.h:530
bool equalModuloPrecision(T const &val1, T const &val2, T const &precision, bool relativeError=true)
Compares the given elements and determines whether they are equal modulo the given precision.
Definition vector.h:884
std::string toString(std::vector< ValueType > const &vector)
Output vector as string.
Definition vector.h:1298
ValueType zero()
Definition constants.cpp:26
LabParser.cpp.
Definition cli.cpp:18
TYPED_TEST(GraphTestAR, SymbolicProb01StochasticGameDieSmall)
Definition GraphTest.cpp:49
TYPED_TEST_SUITE(GraphTestAR, TestingTypes,)
::testing::Types< Cudd, Sylvan > TestingTypes
Definition GraphTest.cpp:46