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