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