1#include "storm-config.h"
22class DoubleViEnvironment {
33class DoubleSoundViEnvironment {
45class DoublePIEnvironment {
56class RationalPIEnvironment {
75template<
typename TestType>
76class SchedulerGenerationMdpPrctlModelCheckerTest :
public ::testing::Test {
78 typedef typename TestType::ValueType
ValueType;
79 SchedulerGenerationMdpPrctlModelCheckerTest() : _environment(TestType::createEnvironment()) {}
81 void SetUp()
override {
83 GTEST_SKIP() <<
"Z3 not available.";
91 std::pair<std::shared_ptr<storm::models::sparse::Mdp<ValueType>>, std::vector<std::shared_ptr<storm::logic::Formula const>>> buildModelFormulas(
92 std::string
const& pathToPrismFile, std::string
const& formulasAsString, std::string
const& constantDefinitionString =
"")
const {
93 std::pair<std::shared_ptr<storm::models::sparse::Mdp<ValueType>>, std::vector<std::shared_ptr<storm::logic::Formula const>>> result;
97 result.first = storm::api::buildSparseModel<ValueType>(program, result.second)->template as<storm::models::sparse::Mdp<ValueType>>();
101 std::vector<storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>> getTasks(
102 std::vector<std::shared_ptr<storm::logic::Formula const>>
const& formulas)
const {
103 std::vector<storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>> result;
104 for (
auto const& f : formulas) {
105 result.emplace_back(*f);
106 result.back().setProduceSchedulers(
true);
112 return storm::utility::convertNumber<ValueType>(input);
119typedef ::testing::Types<DoubleViEnvironment, DoubleSoundViEnvironment, DoublePIEnvironment, RationalPIEnvironment
126TYPED_TEST(SchedulerGenerationMdpPrctlModelCheckerTest, reachability) {
127 typedef typename TestFixture::ValueType
ValueType;
129 std::string formulasString =
"Pmin=? [F \"target\"]; Pmax=? [F \"target\"];";
130 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/scheduler_generation.nm", formulasString);
131 auto mdp = std::move(modelFormulas.first);
132 auto tasks = this->getTasks(modelFormulas.second);
133 EXPECT_EQ(4ull, mdp->getNumberOfStates());
134 EXPECT_EQ(11ull, mdp->getNumberOfTransitions());
136 EXPECT_EQ(7ull, mdp->getNumberOfChoices());
140 auto result = checker.check(this->env(), tasks[0]);
141 ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
142 ASSERT_TRUE(result->template asExplicitQuantitativeCheckResult<ValueType>().hasScheduler());
144 EXPECT_EQ(0ull, scheduler.
getChoice(0).getDeterministicChoice());
145 EXPECT_EQ(1ull, scheduler.
getChoice(1).getDeterministicChoice());
146 EXPECT_EQ(0ull, scheduler.
getChoice(2).getDeterministicChoice());
147 EXPECT_EQ(0ull, scheduler.
getChoice(3).getDeterministicChoice());
149 result = checker.check(tasks[1]);
150 ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
151 ASSERT_TRUE(result->template asExplicitQuantitativeCheckResult<ValueType>().hasScheduler());
153 EXPECT_EQ(1ull, scheduler2.
getChoice(0).getDeterministicChoice());
154 EXPECT_EQ(2ull, scheduler2.
getChoice(1).getDeterministicChoice());
155 EXPECT_EQ(0ull, scheduler2.
getChoice(2).getDeterministicChoice());
156 EXPECT_EQ(0ull, scheduler2.
getChoice(3).getDeterministicChoice());
159TYPED_TEST(SchedulerGenerationMdpPrctlModelCheckerTest, total_reward) {
160 typedef typename TestFixture::ValueType
ValueType;
162 std::string formulasString =
"Rmin=? [ C ];";
164 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/tiny_rewards.nm", formulasString);
165 auto mdp = std::move(modelFormulas.first);
166 auto tasks = this->getTasks(modelFormulas.second);
167 EXPECT_EQ(3ul, mdp->getNumberOfStates());
168 EXPECT_EQ(4ul, mdp->getNumberOfTransitions());
169 EXPECT_EQ(4ul, mdp->getNumberOfChoices());
174 auto result = checker.check(this->env(), tasks[0]);
175 ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
176 EXPECT_NEAR(this->
parseNumber(
"0"), result->template asExplicitQuantitativeCheckResult<ValueType>()[*mdp->getInitialStates().begin()],
177 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
178 ASSERT_TRUE(result->template asExplicitQuantitativeCheckResult<ValueType>().hasScheduler());
184 auto inducedModel = mdp->applyScheduler(scheduler);
186 auto const& inducedDtmc = inducedModel->template as<storm::models::sparse::Dtmc<ValueType>>();
187 EXPECT_EQ(inducedDtmc->getNumberOfChoices(), inducedDtmc->getNumberOfStates());
189 auto inducedResult = inducedChecker.check(this->env(), tasks[0]);
190 ASSERT_TRUE(inducedResult->isExplicitQuantitativeCheckResult());
191 EXPECT_NEAR(this->
parseNumber(
"0"), inducedResult->template asExplicitQuantitativeCheckResult<ValueType>()[*mdp->getInitialStates().begin()],
192 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
196TYPED_TEST(SchedulerGenerationMdpPrctlModelCheckerTest, lra) {
197 typedef typename TestFixture::ValueType
ValueType;
199 std::string formulasString =
"R{\"grants\"}max=? [ MP ]; R{\"grants\"}min=? [ MP ];";
201 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/cs_nfail3.nm", formulasString);
202 auto mdp = std::move(modelFormulas.first);
203 auto tasks = this->getTasks(modelFormulas.second);
204 EXPECT_EQ(184ul, mdp->getNumberOfStates());
205 EXPECT_EQ(541ul, mdp->getNumberOfTransitions());
206 EXPECT_EQ(439ul, mdp->getNumberOfChoices());
210 if (!std::is_same<ValueType, double>::value) {
211 GTEST_SKIP() <<
"Lra scheduler extraction not supported for LP based method";
214 auto result = checker.check(this->env(), tasks[0]);
215 ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
216 EXPECT_NEAR(this->
parseNumber(
"333/1000"), result->template asExplicitQuantitativeCheckResult<ValueType>()[*mdp->getInitialStates().begin()],
217 storm::utility::convertNumber<ValueType>(this->env().solver().lra().getPrecision()));
218 ASSERT_TRUE(result->template asExplicitQuantitativeCheckResult<ValueType>().hasScheduler());
224 auto inducedModel = mdp->applyScheduler(scheduler);
226 auto const& inducedMdp = inducedModel->template as<storm::models::sparse::Dtmc<ValueType>>();
227 EXPECT_EQ(inducedMdp->getNumberOfChoices(), inducedMdp->getNumberOfStates());
229 auto inducedResult = inducedChecker.check(this->env(), tasks[0]);
230 ASSERT_TRUE(inducedResult->isExplicitQuantitativeCheckResult());
231 EXPECT_NEAR(this->
parseNumber(
"333/1000"), inducedResult->template asExplicitQuantitativeCheckResult<ValueType>()[*mdp->getInitialStates().begin()],
232 storm::utility::convertNumber<ValueType>(this->env().solver().lra().getPrecision()));
235 auto result = checker.check(this->env(), tasks[1]);
236 ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
237 EXPECT_NEAR(this->
parseNumber(
"0"), result->template asExplicitQuantitativeCheckResult<ValueType>()[*mdp->getInitialStates().begin()],
238 storm::utility::convertNumber<ValueType>(this->env().solver().lra().getPrecision()));
239 ASSERT_TRUE(result->template asExplicitQuantitativeCheckResult<ValueType>().hasScheduler());
244 auto inducedModel = mdp->applyScheduler(scheduler);
246 auto const& inducedMdp = inducedModel->template as<storm::models::sparse::Dtmc<ValueType>>();
247 EXPECT_EQ(inducedMdp->getNumberOfChoices(), inducedMdp->getNumberOfStates());
249 auto inducedResult = inducedChecker.check(this->env(), tasks[1]);
250 ASSERT_TRUE(inducedResult->isExplicitQuantitativeCheckResult());
251 EXPECT_NEAR(this->
parseNumber(
"0"), inducedResult->template asExplicitQuantitativeCheckResult<ValueType>()[*mdp->getInitialStates().begin()],
252 storm::utility::convertNumber<ValueType>(this->env().solver().lra().getPrecision()));
256TYPED_TEST(SchedulerGenerationMdpPrctlModelCheckerTest, ltl) {
257 typedef typename TestFixture::ValueType
ValueType;
259#ifdef STORM_HAVE_LTL_MODELCHECKING_SUPPORT
260 std::string formulasString =
"Pmax=? [X X s=0]; Pmin=? [G F \"target\"]; Pmax=? [(G F s>2) & (F G !(s=3))];";
261 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/scheduler_generation.nm", formulasString);
262 auto mdp = std::move(modelFormulas.first);
263 auto tasks = this->getTasks(modelFormulas.second);
264 EXPECT_EQ(4ull, mdp->getNumberOfStates());
265 EXPECT_EQ(11ull, mdp->getNumberOfTransitions());
267 EXPECT_EQ(7ull, mdp->getNumberOfChoices());
272 tasks[0].setOnlyInitialStatesRelevant(
true);
273 auto result = checker.check(this->env(), tasks[0]);
274 ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
275 EXPECT_NEAR(this->
parseNumber(
"81/100"), result->template asExplicitQuantitativeCheckResult<ValueType>()[*mdp->getInitialStates().begin()],
276 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
277 ASSERT_TRUE(result->template asExplicitQuantitativeCheckResult<ValueType>().hasScheduler());
283 auto inducedModel = mdp->applyScheduler(scheduler);
286 auto const& inducedMdp = inducedModel->template as<storm::models::sparse::Mdp<ValueType>>();
287 EXPECT_EQ(inducedMdp->getNumberOfChoices(), inducedMdp->getNumberOfStates());
290 auto inducedResult = inducedChecker.check(this->env(), tasks[0]);
291 ASSERT_TRUE(inducedResult->isExplicitQuantitativeCheckResult());
293 inducedResult->template asExplicitQuantitativeCheckResult<ValueType>()[*inducedMdp->getInitialStates().begin()],
294 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
297 tasks[1].setOnlyInitialStatesRelevant(
true);
298 auto result = checker.check(this->env(), tasks[1]);
299 ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
300 EXPECT_NEAR(this->
parseNumber(
"1/2"), result->template asExplicitQuantitativeCheckResult<ValueType>()[*mdp->getInitialStates().begin()],
301 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
302 ASSERT_TRUE(result->template asExplicitQuantitativeCheckResult<ValueType>().hasScheduler());
308 auto inducedModel = mdp->applyScheduler(scheduler);
311 auto const& inducedMdp = inducedModel->template as<storm::models::sparse::Mdp<ValueType>>();
312 EXPECT_EQ(inducedMdp->getNumberOfChoices(), inducedMdp->getNumberOfStates());
315 auto inducedResult = inducedChecker.check(this->env(), tasks[1]);
316 ASSERT_TRUE(inducedResult->isExplicitQuantitativeCheckResult());
318 EXPECT_NEAR(this->
parseNumber(
"1/2"), inducedResult->template asExplicitQuantitativeCheckResult<ValueType>()[*inducedMdp->getInitialStates().begin()],
319 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
322 tasks[2].setOnlyInitialStatesRelevant(
false);
323 auto result = checker.check(this->env(), tasks[2]);
324 ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
325 EXPECT_NEAR(this->
parseNumber(
"1/2"), result->template asExplicitQuantitativeCheckResult<ValueType>()[*mdp->getInitialStates().begin()],
326 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
327 ASSERT_TRUE(result->template asExplicitQuantitativeCheckResult<ValueType>().hasScheduler());
333 auto inducedModel = mdp->applyScheduler(scheduler);
336 auto const& inducedMdp = inducedModel->template as<storm::models::sparse::Mdp<ValueType>>();
337 EXPECT_EQ(inducedMdp->getNumberOfChoices(), inducedMdp->getNumberOfStates());
340 auto inducedResult = inducedChecker.check(this->env(), tasks[2]);
341 ASSERT_TRUE(inducedResult->isExplicitQuantitativeCheckResult());
343 auto test = inducedResult->template asExplicitQuantitativeCheckResult<ValueType>().getValueVector();
344 EXPECT_NEAR(this->
parseNumber(
"1/2"), inducedResult->template asExplicitQuantitativeCheckResult<ValueType>()[0],
345 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
346 EXPECT_NEAR(this->
parseNumber(
"1"), inducedResult->template asExplicitQuantitativeCheckResult<ValueType>()[1],
347 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
348 EXPECT_NEAR(this->
parseNumber(
"0"), inducedResult->template asExplicitQuantitativeCheckResult<ValueType>()[2],
349 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
356TYPED_TEST(SchedulerGenerationMdpPrctlModelCheckerTest, ltlNondetChoice) {
357 typedef typename TestFixture::ValueType
ValueType;
358#ifdef STORM_HAVE_LTL_MODELCHECKING_SUPPORT
360 std::string formulasString =
"Pmax=? [X X !(x=0)];";
361 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/prism-mec-example1.nm", formulasString);
363 auto mdp = std::move(modelFormulas.first);
364 auto tasks = this->getTasks(modelFormulas.second);
365 EXPECT_EQ(3ull, mdp->getNumberOfStates());
366 EXPECT_EQ(5ull, mdp->getNumberOfTransitions());
368 EXPECT_EQ(4ull, mdp->getNumberOfChoices());
373 tasks[0].setOnlyInitialStatesRelevant(
true);
374 auto result = checker.check(this->env(), tasks[0]);
375 ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
376 EXPECT_NEAR(this->
parseNumber(
"1"), result->template asExplicitQuantitativeCheckResult<ValueType>()[*mdp->getInitialStates().begin()],
377 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
378 ASSERT_TRUE(result->template asExplicitQuantitativeCheckResult<ValueType>().hasScheduler());
384 auto inducedModel = mdp->applyScheduler(scheduler);
387 auto const& inducedMdp = inducedModel->template as<storm::models::sparse::Mdp<ValueType>>();
388 EXPECT_EQ(inducedMdp->getNumberOfChoices(), inducedMdp->getNumberOfStates());
391 auto inducedResult = inducedChecker.check(this->env(), tasks[0]);
392 ASSERT_TRUE(inducedResult->isExplicitQuantitativeCheckResult());
393 EXPECT_NEAR(this->
parseNumber(
"1"), inducedResult->template asExplicitQuantitativeCheckResult<ValueType>()[*inducedMdp->getInitialStates().begin()],
394 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
401TYPED_TEST(SchedulerGenerationMdpPrctlModelCheckerTest, ltlUnsat) {
402 typedef typename TestFixture::ValueType
ValueType;
403#ifdef STORM_HAVE_LTL_MODELCHECKING_SUPPORT
405 std::string formulasString =
"Pmax=? [(X X !(s=0)) & (X X (s=0))]; Pmin=? [(X X !(s=0)) | (X X (s=0))];";
406 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/scheduler_generation.nm", formulasString);
408 auto mdp = std::move(modelFormulas.first);
409 auto tasks = this->getTasks(modelFormulas.second);
410 EXPECT_EQ(4ull, mdp->getNumberOfStates());
411 EXPECT_EQ(11ull, mdp->getNumberOfTransitions());
413 EXPECT_EQ(7ull, mdp->getNumberOfChoices());
418 tasks[0].setOnlyInitialStatesRelevant(
true);
419 auto result = checker.check(this->env(), tasks[0]);
420 ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
421 EXPECT_NEAR(this->
parseNumber(
"0"), result->template asExplicitQuantitativeCheckResult<ValueType>()[*mdp->getInitialStates().begin()],
422 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
423 ASSERT_TRUE(result->template asExplicitQuantitativeCheckResult<ValueType>().hasScheduler());
429 auto inducedModel = mdp->applyScheduler(scheduler);
432 auto const& inducedMdp = inducedModel->template as<storm::models::sparse::Dtmc<ValueType>>();
433 EXPECT_EQ(inducedMdp->getNumberOfChoices(), inducedMdp->getNumberOfStates());
436 auto inducedResult = inducedChecker.check(this->env(), tasks[0]);
437 ASSERT_TRUE(inducedResult->isExplicitQuantitativeCheckResult());
438 EXPECT_NEAR(this->
parseNumber(
"0"), inducedResult->template asExplicitQuantitativeCheckResult<ValueType>()[*inducedMdp->getInitialStates().begin()],
439 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
443 tasks[1].setOnlyInitialStatesRelevant(
true);
444 auto result = checker.check(this->env(), tasks[1]);
445 ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
446 ASSERT_TRUE(result->template asExplicitQuantitativeCheckResult<ValueType>().hasScheduler());
447 EXPECT_NEAR(this->
parseNumber(
"1"), result->template asExplicitQuantitativeCheckResult<ValueType>()[*mdp->getInitialStates().begin()],
448 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
454 auto inducedModel = mdp->applyScheduler(scheduler);
457 auto const& inducedMdp = inducedModel->template as<storm::models::sparse::Dtmc<ValueType>>();
458 EXPECT_EQ(inducedMdp->getNumberOfChoices(), inducedMdp->getNumberOfStates());
461 auto inducedResult = inducedChecker.check(this->env(), tasks[1]);
462 ASSERT_TRUE(inducedResult->isExplicitQuantitativeCheckResult());
463 EXPECT_NEAR(this->
parseNumber(
"1"), inducedResult->template asExplicitQuantitativeCheckResult<ValueType>()[*inducedMdp->getInitialStates().begin()],
464 storm::utility::convertNumber<ValueType>(this->env().solver().minMax().getPrecision()));
SolverEnvironment & solver()
void setNondetLraMethod(storm::solver::LraMethod value, bool isSetFromDefault=false)
void setPrecision(storm::RationalNumber value)
void setMethod(storm::solver::MinMaxMethod value, bool isSetFromDefault=false)
MinMaxSolverEnvironment & minMax()
void setForceSoundness(bool value)
LongRunAverageSolverEnvironment & lra()
This class defines which action is chosen in a particular state of a non-deterministic model.
bool isDeterministicScheduler() const
Retrieves whether all defined choices are deterministic.
bool isPartialScheduler() const
Retrieves whether there is a reachable pair of model and memory state for which the choice is undefin...
SchedulerChoice< ValueType > const & getChoice(uint_fast64_t modelState, uint_fast64_t memoryState=0) const
Gets the choice defined by the scheduler for the given model and memory state.
bool isMemorylessScheduler() const
Retrieves whether the scheduler considers a trivial memory structure (i.e., a memory structure with j...
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.
storm::prism::Program preprocess(storm::prism::Program const &program, std::map< storm::expressions::Variable, storm::expressions::Expression > const &constantDefinitions)
TYPED_TEST(GraphTestAR, SymbolicProb01StochasticGameDieSmall)
TYPED_TEST_SUITE(GraphTestAR, TestingTypes,)
::testing::Types< Cudd, Sylvan > TestingTypes