1#include "storm-config.h"
31enum class MdpEngine { PrismSparse, JaniSparse,
Hybrid, PrismDd, JaniDd };
33class SparseDoubleValueIterationViOpGaussSeidelMultEnvironment {
36 static const MdpEngine engine = MdpEngine::PrismSparse;
37 static const bool isExact =
false;
38 typedef double ValueType;
39 typedef storm::models::sparse::Mdp<ValueType> ModelType;
40 static storm::Environment createEnvironment() {
41 storm::Environment env;
50class SparseDoubleValueIterationViOpRegularMultEnvironment {
53 static const MdpEngine engine = MdpEngine::PrismSparse;
54 static const bool isExact =
false;
55 typedef double ValueType;
56 typedef storm::models::sparse::Mdp<ValueType> ModelType;
57 static storm::Environment createEnvironment() {
58 storm::Environment env;
67class SparseDoubleValueIterationNativeGaussSeidelMultEnvironment {
70 static const MdpEngine engine = MdpEngine::PrismSparse;
71 static const bool isExact =
false;
72 typedef double ValueType;
73 typedef storm::models::sparse::Mdp<ValueType> ModelType;
74 static storm::Environment createEnvironment() {
75 storm::Environment env;
84class SparseDoubleValueIterationNativeRegularMultEnvironment {
87 static const MdpEngine engine = MdpEngine::PrismSparse;
88 static const bool isExact =
false;
89 typedef double ValueType;
90 typedef storm::models::sparse::Mdp<ValueType> ModelType;
91 static storm::Environment createEnvironment() {
92 storm::Environment env;
101class JaniSparseDoubleValueIterationEnvironment {
104 static const MdpEngine engine = MdpEngine::JaniSparse;
105 static const bool isExact =
false;
106 typedef double ValueType;
107 typedef storm::models::sparse::Mdp<ValueType> ModelType;
108 static storm::Environment createEnvironment() {
109 storm::Environment env;
116class SparseDoubleIntervalIterationEnvironment {
119 static const MdpEngine engine = MdpEngine::PrismSparse;
120 static const bool isExact =
false;
121 typedef double ValueType;
122 typedef storm::models::sparse::Mdp<ValueType> ModelType;
123 static storm::Environment createEnvironment() {
124 storm::Environment env;
133class SparseDoubleSoundValueIterationEnvironment {
136 static const MdpEngine engine = MdpEngine::PrismSparse;
137 static const bool isExact =
false;
138 typedef double ValueType;
139 typedef storm::models::sparse::Mdp<ValueType> ModelType;
140 static storm::Environment createEnvironment() {
141 storm::Environment env;
150class SparseDoubleOptimisticValueIterationEnvironment {
153 static const MdpEngine engine = MdpEngine::PrismSparse;
154 static const bool isExact =
false;
155 typedef double ValueType;
156 typedef storm::models::sparse::Mdp<ValueType> ModelType;
157 static storm::Environment createEnvironment() {
158 storm::Environment env;
167class SparseDoubleGuessingValueIterationEnvironment {
170 static const MdpEngine engine = MdpEngine::PrismSparse;
171 static const bool isExact =
false;
172 typedef double ValueType;
173 typedef storm::models::sparse::Mdp<ValueType> ModelType;
174 static storm::Environment createEnvironment() {
175 storm::Environment env;
184class SparseDoubleTopologicalValueIterationEnvironment {
187 static const MdpEngine engine = MdpEngine::PrismSparse;
188 static const bool isExact =
false;
189 typedef double ValueType;
190 typedef storm::models::sparse::Mdp<ValueType> ModelType;
191 static storm::Environment createEnvironment() {
192 storm::Environment env;
201class SparseDoubleTopologicalSoundValueIterationEnvironment {
204 static const MdpEngine engine = MdpEngine::PrismSparse;
205 static const bool isExact =
false;
206 typedef double ValueType;
207 typedef storm::models::sparse::Mdp<ValueType> ModelType;
208 static storm::Environment createEnvironment() {
209 storm::Environment env;
219class SparseDoubleTopologicalGuessingValueIterationEnvironment {
222 static const MdpEngine engine = MdpEngine::PrismSparse;
223 static const bool isExact =
false;
224 typedef double ValueType;
225 typedef storm::models::sparse::Mdp<ValueType> ModelType;
226 static storm::Environment createEnvironment() {
227 storm::Environment env;
237class SparseDoubleLPEnvironment {
240 static const MdpEngine engine = MdpEngine::PrismSparse;
241 static const bool isExact =
false;
242 typedef double ValueType;
243 typedef storm::models::sparse::Mdp<ValueType> ModelType;
244 static storm::Environment createEnvironment() {
245 storm::Environment env;
252class SparseDoubleViToLPEnvironment {
255 static const MdpEngine engine = MdpEngine::PrismSparse;
256 static const bool isExact =
false;
257 typedef double ValueType;
258 typedef storm::models::sparse::Mdp<ValueType> ModelType;
259 static storm::Environment createEnvironment() {
260 storm::Environment env;
267class SparseRationalPolicyIterationEnvironment {
270 static const MdpEngine engine = MdpEngine::PrismSparse;
271 static const bool isExact =
true;
272 typedef storm::RationalNumber ValueType;
273 typedef storm::models::sparse::Mdp<ValueType> ModelType;
274 static storm::Environment createEnvironment() {
275 storm::Environment env;
281class SparseRationalViToPiEnvironment {
284 static const MdpEngine engine = MdpEngine::PrismSparse;
285 static const bool isExact =
true;
286 typedef storm::RationalNumber ValueType;
287 typedef storm::models::sparse::Mdp<ValueType> ModelType;
288 static storm::Environment createEnvironment() {
289 storm::Environment env;
295class SparseRationalRationalSearchEnvironment {
298 static const MdpEngine engine = MdpEngine::PrismSparse;
299 static const bool isExact =
true;
300 typedef storm::RationalNumber ValueType;
301 typedef storm::models::sparse::Mdp<ValueType> ModelType;
302 static storm::Environment createEnvironment() {
303 storm::Environment env;
308class HybridCuddDoubleValueIterationEnvironment {
311 static const MdpEngine engine = MdpEngine::Hybrid;
312 static const bool isExact =
false;
313 typedef double ValueType;
314 typedef storm::models::symbolic::Mdp<ddType, ValueType> ModelType;
316 static void checkLibraryAvailable() {
317#ifndef STORM_HAVE_CUDD
318 GTEST_SKIP() <<
"Library CUDD not available.";
322 static storm::Environment createEnvironment() {
323 storm::Environment env;
329class HybridSylvanDoubleValueIterationEnvironment {
332 static const MdpEngine engine = MdpEngine::Hybrid;
333 static const bool isExact =
false;
334 typedef double ValueType;
335 typedef storm::models::symbolic::Mdp<ddType, ValueType> ModelType;
337 static void checkLibraryAvailable() {
338#ifndef STORM_HAVE_SYLVAN
339 GTEST_SKIP() <<
"Library Sylvan not available.";
343 static storm::Environment createEnvironment() {
344 storm::Environment env;
350class HybridCuddDoubleSoundValueIterationEnvironment {
353 static const MdpEngine engine = MdpEngine::Hybrid;
354 static const bool isExact =
false;
355 typedef double ValueType;
356 typedef storm::models::symbolic::Mdp<ddType, ValueType> ModelType;
358 static void checkLibraryAvailable() {
359#ifndef STORM_HAVE_CUDD
360 GTEST_SKIP() <<
"Library CUDD not available.";
364 static storm::Environment createEnvironment() {
365 storm::Environment env;
373class HybridCuddDoubleOptimisticValueIterationEnvironment {
376 static const MdpEngine engine = MdpEngine::Hybrid;
377 static const bool isExact =
false;
378 typedef double ValueType;
379 typedef storm::models::symbolic::Mdp<ddType, ValueType> ModelType;
381 static void checkLibraryAvailable() {
382#ifndef STORM_HAVE_CUDD
383 GTEST_SKIP() <<
"Library CUDD not available.";
387 static storm::Environment createEnvironment() {
388 storm::Environment env;
396class HybridCuddDoubleGuessingValueIterationEnvironment {
399 static const MdpEngine engine = MdpEngine::Hybrid;
400 static const bool isExact =
false;
401 typedef double ValueType;
402 typedef storm::models::symbolic::Mdp<ddType, ValueType> ModelType;
404 static void checkLibraryAvailable() {
405#ifndef STORM_HAVE_CUDD
406 GTEST_SKIP() <<
"Library CUDD not available.";
410 static storm::Environment createEnvironment() {
411 storm::Environment env;
419class HybridSylvanRationalPolicyIterationEnvironment {
422 static const MdpEngine engine = MdpEngine::Hybrid;
423 static const bool isExact =
true;
424 typedef storm::RationalNumber ValueType;
425 typedef storm::models::symbolic::Mdp<ddType, ValueType> ModelType;
427 static void checkLibraryAvailable() {
428#ifndef STORM_HAVE_SYLVAN
429 GTEST_SKIP() <<
"Library Sylvan not available.";
433 static storm::Environment createEnvironment() {
434 storm::Environment env;
439class DdCuddDoubleValueIterationEnvironment {
442 static const MdpEngine engine = MdpEngine::PrismDd;
443 static const bool isExact =
false;
444 typedef double ValueType;
445 typedef storm::models::symbolic::Mdp<ddType, ValueType> ModelType;
447 static void checkLibraryAvailable() {
448#ifndef STORM_HAVE_CUDD
449 GTEST_SKIP() <<
"Library CUDD not available.";
453 static storm::Environment createEnvironment() {
454 storm::Environment env;
460class JaniDdCuddDoubleValueIterationEnvironment {
463 static const MdpEngine engine = MdpEngine::JaniDd;
464 static const bool isExact =
false;
465 typedef double ValueType;
466 typedef storm::models::symbolic::Mdp<ddType, ValueType> ModelType;
468 static void checkLibraryAvailable() {
469#ifndef STORM_HAVE_CUDD
470 GTEST_SKIP() <<
"Library CUDD not available.";
474 static storm::Environment createEnvironment() {
475 storm::Environment env;
481class DdSylvanDoubleValueIterationEnvironment {
484 static const MdpEngine engine = MdpEngine::PrismDd;
485 static const bool isExact =
false;
486 typedef double ValueType;
487 typedef storm::models::symbolic::Mdp<ddType, ValueType> ModelType;
489 static void checkLibraryAvailable() {
490#ifndef STORM_HAVE_SYLVAN
491 GTEST_SKIP() <<
"Library Sylvan not available.";
495 static storm::Environment createEnvironment() {
496 storm::Environment env;
502class DdCuddDoublePolicyIterationEnvironment {
505 static const MdpEngine engine = MdpEngine::PrismDd;
506 static const bool isExact =
false;
507 typedef double ValueType;
508 typedef storm::models::symbolic::Mdp<ddType, ValueType> ModelType;
510 static void checkLibraryAvailable() {
511#ifndef STORM_HAVE_CUDD
512 GTEST_SKIP() <<
"Library CUDD not available.";
516 static storm::Environment createEnvironment() {
517 storm::Environment env;
523class DdSylvanRationalRationalSearchEnvironment {
526 static const MdpEngine engine = MdpEngine::PrismDd;
527 static const bool isExact =
true;
528 typedef storm::RationalNumber ValueType;
529 typedef storm::models::symbolic::Mdp<ddType, ValueType> ModelType;
531 static void checkLibraryAvailable() {
532#ifndef STORM_HAVE_SYLVAN
533 GTEST_SKIP() <<
"Library Sylvan not available.";
537 static storm::Environment createEnvironment() {
538 storm::Environment env;
544template<
typename TestType>
545class MdpPrctlModelCheckerTest :
public ::testing::Test {
547 typedef typename TestType::ValueType ValueType;
548 typedef typename storm::models::sparse::Mdp<ValueType> SparseModelType;
549 typedef typename storm::models::symbolic::Mdp<TestType::ddType, ValueType> SymbolicModelType;
551 MdpPrctlModelCheckerTest() : _environment(TestType::createEnvironment()) {}
553 void SetUp()
override {
555 GTEST_SKIP() <<
"Z3 not available.";
557 if constexpr (TestType::engine == MdpEngine::Hybrid || TestType::engine == MdpEngine::PrismDd || TestType::engine == MdpEngine::JaniDd) {
558 TestType::checkLibraryAvailable();
562 storm::Environment
const& env()
const {
565 ValueType
parseNumber(std::string
const& input)
const {
568 ValueType precision()
const {
571 bool isSparseModel()
const {
572 return std::is_same<typename TestType::ModelType, SparseModelType>::value;
574 bool isSymbolicModel()
const {
575 return std::is_same<typename TestType::ModelType, SymbolicModelType>::value;
578 template<
typename MT =
typename TestType::ModelType>
579 typename std::enable_if<std::is_same<MT, SparseModelType>::value,
580 std::pair<std::shared_ptr<MT>, std::vector<std::shared_ptr<storm::logic::Formula const>>>>::type
581 buildModelFormulas(std::string
const& pathToPrismFile, std::string
const& formulasAsString, std::string
const& constantDefinitionString =
"")
const {
582 std::pair<std::shared_ptr<MT>, std::vector<std::shared_ptr<storm::logic::Formula const>>> result;
584 program = program.
preprocess(constantDefinitionString);
585 if (TestType::engine == MdpEngine::PrismSparse) {
588 }
else if (TestType::engine == MdpEngine::JaniSparse) {
590 janiData.first.substituteFunctions();
597 template<
typename MT =
typename TestType::ModelType>
598 typename std::enable_if<std::is_same<MT, SymbolicModelType>::value,
599 std::pair<std::shared_ptr<MT>, std::vector<std::shared_ptr<storm::logic::Formula const>>>>::type
600 buildModelFormulas(std::string
const& pathToPrismFile, std::string
const& formulasAsString, std::string
const& constantDefinitionString =
"")
const {
601 std::pair<std::shared_ptr<MT>, std::vector<std::shared_ptr<storm::logic::Formula const>>> result;
603 program = program.
preprocess(constantDefinitionString);
604 if (TestType::engine == MdpEngine::Hybrid || TestType::engine == MdpEngine::PrismDd) {
607 }
else if (TestType::engine == MdpEngine::JaniDd) {
609 janiData.first.substituteFunctions();
616 std::vector<storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>> getTasks(
617 std::vector<std::shared_ptr<storm::logic::Formula const>>
const& formulas)
const {
618 std::vector<storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>> result;
619 for (
auto const& f : formulas) {
620 result.emplace_back(*f);
625 template<
typename MT =
typename TestType::ModelType>
626 typename std::enable_if<std::is_same<MT, SparseModelType>::value, std::shared_ptr<storm::modelchecker::AbstractModelChecker<MT>>>::type createModelChecker(
627 std::shared_ptr<MT>
const& model)
const {
628 if (TestType::engine == MdpEngine::PrismSparse || TestType::engine == MdpEngine::JaniSparse) {
629 return std::make_shared<storm::modelchecker::SparseMdpPrctlModelChecker<SparseModelType>>(*model);
633 template<
typename MT =
typename TestType::ModelType>
634 typename std::enable_if<std::is_same<MT, SymbolicModelType>::value, std::shared_ptr<storm::modelchecker::AbstractModelChecker<MT>>>::type
635 createModelChecker(std::shared_ptr<MT>
const& model)
const {
636 if (TestType::engine == MdpEngine::Hybrid) {
637 return std::make_shared<storm::modelchecker::HybridMdpPrctlModelChecker<SymbolicModelType>>(*model);
638 }
else if (TestType::engine == MdpEngine::PrismDd || TestType::engine == MdpEngine::JaniDd) {
639 return std::make_shared<storm::modelchecker::SymbolicMdpPrctlModelChecker<SymbolicModelType>>(*model);
643 template<
typename MT =
typename TestType::ModelType>
644 typename std::enable_if<std::is_same<MT, SparseModelType>::value,
void>::type execute(std::shared_ptr<MT>
const& model,
645 std::function<
void()>
const& f)
const {
649 template<
typename MT =
typename TestType::ModelType>
650 typename std::enable_if<std::is_same<MT, SymbolicModelType>::value,
void>::type execute(std::shared_ptr<MT>
const& model,
651 std::function<
void()>
const& f)
const {
652 model->getManager().execute(f);
655 bool getQualitativeResultAtInitialState(std::shared_ptr<storm::models::Model<ValueType>>
const& model,
656 std::unique_ptr<storm::modelchecker::CheckResult>& result) {
658 result->filter(*filter);
659 return result->asQualitativeCheckResult().forallTrue();
663 std::unique_ptr<storm::modelchecker::CheckResult>& result) {
665 result->filter(*filter);
666 return result->asQuantitativeCheckResult<ValueType>().getMin();
673 void expectQuantitativeResultAtInitialState(std::shared_ptr<storm::models::Model<ValueType>>
const& model,
674 std::unique_ptr<storm::modelchecker::CheckResult>& result, ValueType
const& expected) {
676 if (!result->isExplicitQuantitativeCheckResult()) {
680 auto const& explicitResult = result->template asExplicitQuantitativeCheckResult<ValueType>();
682 if (explicitResult.hasLowerBounds()) {
683 EXPECT_LE(explicitResult.getLowerBoundVector().front(), expected + tolerance) <<
"The lower bound exceeds the expected value.";
685 if (explicitResult.hasUpperBounds()) {
686 EXPECT_LE(expected, explicitResult.getUpperBoundVector().front() + tolerance) <<
"The upper bound falls below the expected value.";
693 void expectExactResultAtInitialState(std::shared_ptr<storm::models::Model<ValueType>>
const& model,
694 std::unique_ptr<storm::modelchecker::CheckResult>& result, ValueType
const& expected) {
695 expectQuantitativeResultAtInitialState(model, result, expected);
696 if (!result->isExplicitQuantitativeCheckResult()) {
699 auto const& explicitResult = result->template asExplicitQuantitativeCheckResult<ValueType>();
700 ASSERT_TRUE(explicitResult.hasLowerBounds()) <<
"No lower bound was reported although the values are exact.";
701 ASSERT_TRUE(explicitResult.hasUpperBounds()) <<
"No upper bound was reported although the values are exact.";
702 EXPECT_EQ(explicitResult.getLowerBoundVector(), explicitResult.getUpperBoundVector()) <<
"The bounds do not pin the values down.";
706 storm::Environment _environment;
708 std::unique_ptr<storm::modelchecker::QualitativeCheckResult>
getInitialStateFilter(std::shared_ptr<storm::models::Model<ValueType>>
const& model)
const {
709 if (isSparseModel()) {
710 return std::make_unique<storm::modelchecker::ExplicitQualitativeCheckResult<ValueType>>(model->template as<SparseModelType>()->getInitialStates());
712 return std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<TestType::ddType>>(
713 model->template as<SymbolicModelType>()->getReachableStates(), model->template as<SymbolicModelType>()->getInitialStates());
718typedef ::testing::Types<SparseDoubleValueIterationViOpGaussSeidelMultEnvironment, SparseDoubleValueIterationViOpRegularMultEnvironment,
719 SparseDoubleValueIterationNativeGaussSeidelMultEnvironment, SparseDoubleValueIterationNativeRegularMultEnvironment,
720 JaniSparseDoubleValueIterationEnvironment, SparseDoubleIntervalIterationEnvironment, SparseDoubleSoundValueIterationEnvironment,
721 SparseDoubleOptimisticValueIterationEnvironment, SparseDoubleGuessingValueIterationEnvironment,
722 SparseDoubleTopologicalValueIterationEnvironment, SparseDoubleTopologicalSoundValueIterationEnvironment,
723 SparseDoubleTopologicalGuessingValueIterationEnvironment, SparseDoubleLPEnvironment, SparseDoubleViToLPEnvironment,
724 SparseRationalPolicyIterationEnvironment, SparseRationalViToPiEnvironment, SparseRationalRationalSearchEnvironment,
725 HybridCuddDoubleValueIterationEnvironment, HybridSylvanDoubleValueIterationEnvironment, HybridCuddDoubleSoundValueIterationEnvironment,
726 HybridCuddDoubleOptimisticValueIterationEnvironment, HybridCuddDoubleGuessingValueIterationEnvironment,
727 HybridSylvanRationalPolicyIterationEnvironment, DdCuddDoubleValueIterationEnvironment, JaniDdCuddDoubleValueIterationEnvironment,
728 DdSylvanDoubleValueIterationEnvironment, DdCuddDoublePolicyIterationEnvironment, DdSylvanRationalRationalSearchEnvironment>
734 std::string formulasString =
"Pmin=? [F \"two\"]";
735 formulasString +=
"; Pmax=? [F \"two\"]";
736 formulasString +=
"; Pmin=? [F \"three\"]";
737 formulasString +=
"; Pmax=? [F \"three\"]";
738 formulasString +=
"; Pmin=? [F \"four\"]";
739 formulasString +=
"; Pmax=? [F \"four\"]";
740 formulasString +=
"; Rmin=? [F \"done\"]";
741 formulasString +=
"; Rmax=? [F \"done\"]";
743 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/two_dice.nm", formulasString);
744 auto model = std::move(modelFormulas.first);
745 auto tasks = this->getTasks(modelFormulas.second);
746 this->execute(model, [&]() {
747 EXPECT_EQ(169ul, model->getNumberOfStates());
748 EXPECT_EQ(436ul, model->getNumberOfTransitions());
751 auto checker = this->createModelChecker(model);
752 std::unique_ptr<storm::modelchecker::CheckResult> result;
754 result = checker->check(this->env(), tasks[0]);
755 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/36"));
757 result = checker->check(this->env(), tasks[1]);
758 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/36"));
760 result = checker->check(this->env(), tasks[2]);
761 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"2/36"));
763 result = checker->check(this->env(), tasks[3]);
764 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"2/36"));
766 result = checker->check(this->env(), tasks[4]);
767 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"3/36"));
769 result = checker->check(this->env(), tasks[5]);
770 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"3/36"));
772 result = checker->check(this->env(), tasks[6]);
773 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"22/3"));
775 result = checker->check(this->env(), tasks[7]);
776 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"22/3"));
781 std::string formulasString =
"Pmin=? [F \"elected\"]";
782 formulasString +=
"; Pmax=? [F \"elected\"]";
783 formulasString +=
"; Pmin=? [F<=25 \"elected\"]";
784 formulasString +=
"; Pmax=? [F<=25 \"elected\"]";
785 formulasString +=
"; Rmin=? [F \"elected\"]";
786 formulasString +=
"; Rmax=? [F \"elected\"]";
788 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/leader4.nm", formulasString);
789 auto model = std::move(modelFormulas.first);
790 auto tasks = this->getTasks(modelFormulas.second);
791 this->execute(model, [&]() {
792 EXPECT_EQ(3172ul, model->getNumberOfStates());
793 EXPECT_EQ(7144ul, model->getNumberOfTransitions());
795 auto checker = this->createModelChecker(model);
796 std::unique_ptr<storm::modelchecker::CheckResult> result;
798 result = checker->check(this->env(), tasks[0]);
799 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1"));
801 result = checker->check(this->env(), tasks[1]);
802 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1"));
804 result = checker->check(this->env(), tasks[2]);
805 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"1/16"));
807 result = checker->check(this->env(), tasks[3]);
808 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"1/16"));
810 result = checker->check(this->env(), tasks[4]);
811 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"30/7"));
813 result = checker->check(this->env(), tasks[5]);
814 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"30/7"));
818TYPED_TEST(MdpPrctlModelCheckerTest, MaybeStateEndComponent) {
821 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/maybe_state_end_component.nm",
"Pmax=? [F \"target\"]");
822 auto model = std::move(modelFormulas.first);
823 auto tasks = this->getTasks(modelFormulas.second);
824 EXPECT_EQ(4ul, model->getNumberOfStates());
827 auto checker = this->createModelChecker(model);
828 auto result = checker->check(this->env(), tasks[0]);
829 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/4"));
833 std::string formulasString =
"Pmax=? [F \"finished\"]";
834 formulasString +=
"; Pmax=? [F \"all_coins_equal_1\"]";
835 formulasString +=
"; P<0.8 [F \"all_coins_equal_1\"]";
836 formulasString +=
"; P<0.9 [F \"all_coins_equal_1\"]";
837 formulasString +=
"; Rmax=? [F \"all_coins_equal_1\"]";
838 formulasString +=
"; Rmin=? [F \"all_coins_equal_1\"]";
839 formulasString +=
"; Rmax=? [F \"finished\"]";
840 formulasString +=
"; Rmin=? [F \"finished\"]";
842 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/coin2-2.nm", formulasString);
843 auto model = std::move(modelFormulas.first);
844 auto tasks = this->getTasks(modelFormulas.second);
845 this->execute(model, [&]() {
846 EXPECT_EQ(272ul, model->getNumberOfStates());
847 EXPECT_EQ(492ul, model->getNumberOfTransitions());
849 auto checker = this->createModelChecker(model);
850 std::unique_ptr<storm::modelchecker::CheckResult> result;
852 result = checker->check(this->env(), tasks[0]);
853 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1"));
855 result = checker->check(this->env(), tasks[1]);
856 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"57/64"));
858 result = checker->check(this->env(), tasks[2]);
859 EXPECT_FALSE(this->getQualitativeResultAtInitialState(model, result));
861 result = checker->check(this->env(), tasks[3]);
862 EXPECT_TRUE(this->getQualitativeResultAtInitialState(model, result));
864 result = checker->check(this->env(), tasks[4]);
867 result = checker->check(this->env(), tasks[5]);
870 result = checker->check(this->env(), tasks[6]);
871 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"75"));
873 result = checker->check(this->env(), tasks[7]);
874 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"48"));
878TYPED_TEST(MdpPrctlModelCheckerTest, TinyRewards) {
879 std::string formulasString =
"Rmin=? [F \"target\"]";
880 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/tiny_rewards.nm", formulasString);
881 auto model = std::move(modelFormulas.first);
882 auto tasks = this->getTasks(modelFormulas.second);
883 this->execute(model, [&]() {
884 EXPECT_EQ(3ul, model->getNumberOfStates());
885 EXPECT_EQ(4ul, model->getNumberOfTransitions());
887 auto checker = this->createModelChecker(model);
888 std::unique_ptr<storm::modelchecker::CheckResult> result;
893 if (TypeParam::engine == MdpEngine::PrismDd && this->env().solver().minMax().getMethod() == storm::solver::MinMaxMethod::RationalSearch) {
896 result = checker->check(this->env(), tasks[0]);
897 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1"));
903 std::string formulasString =
"R{\"w_1_total\"}max=? [ C ]";
904 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/multiobj_team3.nm", formulasString);
905 auto model = std::move(modelFormulas.first);
906 auto tasks = this->getTasks(modelFormulas.second);
907 this->execute(model, [&]() {
908 EXPECT_EQ(12475ul, model->getNumberOfStates());
909 EXPECT_EQ(15228ul, model->getNumberOfTransitions());
911 auto checker = this->createModelChecker(model);
912 std::unique_ptr<storm::modelchecker::CheckResult> result;
916 if (TypeParam::engine == MdpEngine::PrismSparse || TypeParam::engine == MdpEngine::JaniSparse) {
917 result = checker->check(this->env(), tasks[0]);
918 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"114/49"));
920 EXPECT_FALSE(checker->canHandle(tasks[0]));
925TYPED_TEST(MdpPrctlModelCheckerTest, LtlProbabilitiesCoin) {
926#ifdef STORM_HAVE_LTL_MODELCHECKING_SUPPORT
927 std::string formulasString =
"Pmin=? [!(GF \"all_coins_equal_1\")]";
928 formulasString +=
"; Pmax=? [F \"all_coins_equal_1\" U \"finished\"]";
929 formulasString +=
"; P>0.4 [!(GF \"all_coins_equal_1\")]";
930 formulasString +=
"; P<0.6 [F \"all_coins_equal_1\" U \"finished\"]";
932 formulasString +=
"; Pmax=?[ (GF \"all_coins_equal_1\") & ((GF \"all_coins_equal_0\") | (FG \"finished\"))]";
934 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/coin2-2.nm", formulasString);
935 auto model = std::move(modelFormulas.first);
936 auto tasks = this->getTasks(modelFormulas.second);
937 this->execute(model, [&]() {
938 EXPECT_EQ(272ul, model->getNumberOfStates());
939 EXPECT_EQ(492ul, model->getNumberOfTransitions());
941 auto checker = this->createModelChecker(model);
942 std::unique_ptr<storm::modelchecker::CheckResult> result;
945 if (TypeParam::engine == MdpEngine::PrismSparse || TypeParam::engine == MdpEngine::JaniSparse) {
946 result = checker->check(this->env(), tasks[0]);
947 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"4/9"));
949 result = checker->check(this->env(), tasks[1]);
950 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"5/9"));
952 result = checker->check(this->env(), tasks[2]);
953 EXPECT_TRUE(this->getQualitativeResultAtInitialState(model, result));
955 result = checker->check(this->env(), tasks[3]);
956 EXPECT_TRUE(this->getQualitativeResultAtInitialState(model, result));
958 result = checker->check(this->env(), tasks[4]);
959 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"5/9"));
962 EXPECT_FALSE(checker->canHandle(tasks[0]));
970TYPED_TEST(MdpPrctlModelCheckerTest, LtlDice) {
971#ifdef STORM_HAVE_LTL_MODELCHECKING_SUPPORT
972 std::string formulasString =
"Pmax=? [ X (((s1=1) U (s1=3)) U (s1=7))]";
973 formulasString +=
"; Pmax=? [ (F (X (s1=6 & (XX s1=5)))) & (F G (d1!=5))]";
974 formulasString +=
"; Pmax=? [ F s1=3 U (\"three\")]";
975 formulasString +=
"; Pmin=? [! F (s2=6) & X \"done\"]";
977 formulasString +=
"; Pmax=? [ ( (G F !(\"two\")) | F G (\"three\") ) & ( (G F !(\"five\") ) | F G (\"seven\") )]";
979 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/two_dice.nm", formulasString);
980 auto model = std::move(modelFormulas.first);
981 auto tasks = this->getTasks(modelFormulas.second);
982 this->execute(model, [&]() {
983 EXPECT_EQ(169ul, model->getNumberOfStates());
984 EXPECT_EQ(436ul, model->getNumberOfTransitions());
986 auto checker = this->createModelChecker(model);
987 std::unique_ptr<storm::modelchecker::CheckResult> result;
990 if (TypeParam::engine == MdpEngine::PrismSparse || TypeParam::engine == MdpEngine::JaniSparse) {
991 result = checker->check(this->env(), tasks[0]);
992 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/6"));
994 result = checker->check(this->env(), tasks[1]);
995 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/24"));
997 result = checker->check(this->env(), tasks[2]);
998 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/36"));
1000 result = checker->check(this->env(), tasks[3]);
1001 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"5/6"));
1003 result = checker->check(this->env(), tasks[4]);
1004 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"31/36"));
1007 EXPECT_FALSE(checker->canHandle(tasks[0]));
1015TYPED_TEST(MdpPrctlModelCheckerTest, LtlCoinFlips) {
1016#ifdef STORM_HAVE_LTL_MODELCHECKING_SUPPORT
1017 std::string formulasString =
"Pmax=? [ G (true U (heads | \"done\")) ]";
1018 formulasString +=
"; Pmin=? [ G (true U (heads | \"done\")) ]";
1019 formulasString +=
"; Pmax=? [ G (true U<=10 (heads | \"done\")) ]";
1020 formulasString +=
"; Pmin=? [ G (true U<=10 (heads | \"done\")) ]";
1021 formulasString +=
"; Pmax=? [ X G (true U<=0 (heads | \"done\")) ]";
1022 formulasString +=
"; Pmax=? [ true U[10,12] heads ]";
1023 formulasString +=
"; Pmax=? [ X (true U[0,0] heads) ]";
1024 formulasString +=
"; Pmax=? [ G (!(P>=1 [\"done\"]) U<=10 (heads | P>=1 [ \"done\"])) ]";
1025 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/coin_flips.nm", formulasString);
1026 auto model = std::move(modelFormulas.first);
1027 auto tasks = this->getTasks(modelFormulas.second);
1028 this->execute(model, [&]() {
1029 EXPECT_EQ(61ul, model->getNumberOfStates());
1030 EXPECT_EQ(177ul, model->getNumberOfTransitions());
1032 auto checker = this->createModelChecker(model);
1033 std::unique_ptr<storm::modelchecker::CheckResult> result;
1036 if (TypeParam::engine == MdpEngine::PrismSparse || TypeParam::engine == MdpEngine::JaniSparse) {
1037 result = checker->check(this->env(), tasks[0]);
1038 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1"));
1040 result = checker->check(this->env(), tasks[1]);
1041 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"0"));
1043 result = checker->check(this->env(), tasks[2]);
1044 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1021/1024"));
1046 result = checker->check(this->env(), tasks[3]);
1047 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"0"));
1049 result = checker->check(this->env(), tasks[4]);
1050 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/524288"));
1052 result = checker->check(this->env(), tasks[5]);
1053 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"7/8"));
1055 result = checker->check(this->env(), tasks[6]);
1056 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/2"));
1058 result = checker->check(this->env(), tasks[7]);
1059 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1021/1024"));
1062 EXPECT_FALSE(checker->canHandle(tasks[0]));
1070TYPED_TEST(MdpPrctlModelCheckerTest, HOADice) {
1072 std::string formulasString =
"; P=?[HOA: {\"" STORM_TEST_RESOURCES_DIR
"/hoa/automaton_Fandp0Xp1.hoa\", \"p0\" -> \"three\", \"p1\" -> s2=1 }]";
1074 formulasString +=
"; P=?[HOA: {\"" STORM_TEST_RESOURCES_DIR
"/hoa/automaton_UXp0p1.hoa\", \"p0\" -> !(s2=6), \"p1\" -> \"done\" }]";
1076 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/two_dice.nm", formulasString);
1077 auto model = std::move(modelFormulas.first);
1078 auto tasks = this->getTasks(modelFormulas.second);
1079 this->execute(model, [&]() {
1080 EXPECT_EQ(169ul, model->getNumberOfStates());
1081 EXPECT_EQ(436ul, model->getNumberOfTransitions());
1083 auto checker = this->createModelChecker(model);
1084 std::unique_ptr<storm::modelchecker::CheckResult> result;
1087 if (TypeParam::engine == MdpEngine::PrismSparse || TypeParam::engine == MdpEngine::JaniSparse) {
1088 result = checker->check(tasks[0]);
1089 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"0"));
1091 result = checker->check(tasks[1]);
1092 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"3/4"));
1094 EXPECT_FALSE(checker->canHandle(tasks[0]));
1099TYPED_TEST(MdpPrctlModelCheckerTest, SmallDiscount) {
1100 if (TypeParam::isExact || std::is_same<TypeParam, SparseDoubleLPEnvironment>::value || std::is_same<TypeParam, SparseDoubleViToLPEnvironment>::value) {
1101 GTEST_SKIP() <<
"Exact computations for discounted properties are not supported.";
1103 std::string formulasString =
"Rmax=? [ C ]";
1104 formulasString +=
"; Rmax=? [ Cdiscount=9/10 ]";
1105 formulasString +=
"; Rmax=? [ Cdiscount=15/16 ]";
1106 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/small_discount.nm", formulasString);
1107 auto model = std::move(modelFormulas.first);
1108 auto tasks = this->getTasks(modelFormulas.second);
1109 EXPECT_EQ(4ul, model->getNumberOfStates());
1110 EXPECT_EQ(6ul, model->getNumberOfTransitions());
1112 auto checker = this->createModelChecker(model);
1114 if (TypeParam::engine == MdpEngine::PrismSparse || TypeParam::engine == MdpEngine::JaniSparse) {
1115 std::unique_ptr<storm::modelchecker::CheckResult> result = checker->check(this->env(), tasks[0]);
1116 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"5"));
1117 result = checker->check(this->env(), tasks[1]);
1118 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"18/5"));
1119 result = checker->check(this->env(), tasks[2]);
1120 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"15/4"));
1122 EXPECT_FALSE(checker->canHandle(tasks[0]));
1123 EXPECT_FALSE(checker->canHandle(tasks[1]));
1124 EXPECT_FALSE(checker->canHandle(tasks[2]));
1128TYPED_TEST(MdpPrctlModelCheckerTest, OneStateDiscounting) {
1129 if (TypeParam::isExact || std::is_same<TypeParam, SparseDoubleLPEnvironment>::value || std::is_same<TypeParam, SparseDoubleViToLPEnvironment>::value) {
1130 GTEST_SKIP() <<
"Exact computations for discounted properties are not supported.";
1132 std::string formulasString =
"Rmax=? [ Cdiscount=9/10 ]";
1133 formulasString +=
"; Rmax=? [ C<=5discount=9/10 ]";
1134 formulasString +=
"; Rmax=? [ C<=10discount=9/10 ]";
1135 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/one_state.nm", formulasString);
1136 auto model = std::move(modelFormulas.first);
1137 auto tasks = this->getTasks(modelFormulas.second);
1138 EXPECT_EQ(1ul, model->getNumberOfStates());
1139 EXPECT_EQ(2ul, model->getNumberOfTransitions());
1141 auto checker = this->createModelChecker(model);
1143 if ((TypeParam::engine == MdpEngine::PrismSparse || TypeParam::engine == MdpEngine::JaniSparse)) {
1144 std::unique_ptr<storm::modelchecker::CheckResult> result = checker->check(this->env(), tasks[0]);
1145 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1000"));
1146 result = checker->check(this->env(), tasks[1]);
1147 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"40951/100"));
1148 result = checker->check(this->env(), tasks[2]);
1149 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"6513215599/10000000"));
1151 EXPECT_FALSE(checker->canHandle(tasks[0]));
1152 EXPECT_FALSE(checker->canHandle(tasks[1]));
1153 EXPECT_FALSE(checker->canHandle(tasks[2]));
1157TYPED_TEST(MdpPrctlModelCheckerTest, StepBoundedReachability) {
1158 std::string formulasString =
"Pmax=? [ F<=0 x=5];";
1159 formulasString +=
"Pmax=? [ F<=1 x=5];";
1160 formulasString +=
"Pmax=? [ F<=2 x=5];";
1161 formulasString +=
"Pmax=? [ F[2,2] x=5];";
1162 formulasString +=
"Pmax=? [ F[2,3] x=5];";
1163 formulasString +=
"Pmin=? [ F[2,3] x=5];";
1164 formulasString +=
"Pmax=? [ x<2 U[2,2] x=5];";
1165 formulasString +=
"Pmax=? [ x<2 U[2,3] x=5];";
1166 formulasString +=
"Pmax=? [ x<3 U[2,2] x=5];";
1167 formulasString +=
"Pmax=? [ x<3 U<=4 x=5];";
1168 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/mdp/chain.nm", formulasString);
1169 auto model = std::move(modelFormulas.first);
1170 auto tasks = this->getTasks(modelFormulas.second);
1171 EXPECT_EQ(7ul, model->getNumberOfStates());
1172 EXPECT_EQ(16ul, model->getNumberOfTransitions());
1174 auto checker = this->createModelChecker(model);
1176 if (TypeParam::engine == MdpEngine::PrismSparse || TypeParam::engine == MdpEngine::JaniSparse) {
1177 std::unique_ptr<storm::modelchecker::CheckResult> result = checker->check(this->env(), tasks[0]);
1178 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"0"));
1179 result = checker->check(this->env(), tasks[1]);
1180 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"1/2"));
1181 result = checker->check(this->env(), tasks[2]);
1182 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"3/4"));
1183 result = checker->check(this->env(), tasks[3]);
1184 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"1/4"));
1185 result = checker->check(this->env(), tasks[4]);
1186 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"3/8"));
1187 result = checker->check(this->env(), tasks[5]);
1188 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"0"));
1189 result = checker->check(this->env(), tasks[6]);
1190 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"1/4"));
1191 result = checker->check(this->env(), tasks[7]);
1192 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"1/4"));
1193 result = checker->check(this->env(), tasks[8]);
1194 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"1/4"));
1195 result = checker->check(this->env(), tasks[9]);
1196 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"7/8"));
std::unique_ptr< storm::modelchecker::QualitativeCheckResult > getInitialStateFilter(std::shared_ptr< storm::models::sparse::Model< storm::Interval > > const &model)
double getQuantitativeResultAtInitialState(std::shared_ptr< storm::models::sparse::Model< storm::Interval > > const &model, std::unique_ptr< storm::modelchecker::CheckResult > &result)
SolverEnvironment & solver()
void setMultiplicationStyle(storm::solver::MultiplicationStyle value)
void setPrecision(storm::RationalNumber value)
void setMethod(storm::solver::MinMaxMethod value, bool isSetFromDefault=false)
void setRelativeTerminationCriterion(bool value)
void setType(storm::solver::MultiplierType value, bool isSetFromDefault=false)
TopologicalSolverEnvironment & topological()
MinMaxSolverEnvironment & minMax()
void setForceSoundness(bool value)
MultiplierEnvironment & multiplier()
void setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod value, bool isSetFromDefault=false)
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...
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::symbolic::Model< LibraryType, ValueType > > buildSymbolicModel(storm::Environment const &env, storm::storage::SymbolicModelDescription const &model, std::vector< std::shared_ptr< storm::logic::Formula const > > const &formulas, bool buildFullModel=false, bool applyMaximumProgress=true, bool fixDeadlocks=true)
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())
std::vector< std::shared_ptr< storm::logic::Formula const > > extractFormulasFromProperties(std::vector< storm::jani::Property > const &properties)
std::pair< storm::jani::Model, std::vector< storm::jani::Property > > convertPrismToJani(storm::prism::Program const &program, storm::converter::PrismToJaniConverterOptions options)
NumberType parseNumber(std::string const &value)
Parse number from string.
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...
std::conditional_t< storm::NumberTraits< ValueType >::HasInfinity, ValueType, ExtendedNumber< ValueType > > ExtendedValueType
The type to use for values that may be infinite.
bool isInfinity(ValueType const &a)
TargetType convertNumber(SourceType const &number)
TYPED_TEST(GraphTestAR, SymbolicProb01StochasticGameDieSmall)
TYPED_TEST_SUITE(GraphTestAR, TestingTypes,)
::testing::Types< Cudd, Sylvan > TestingTypes
#define STORM_EXPENSIVE_TYPED_TEST(test_suite_name, test_name)
#define STORM_SILENT_EXPECT_THROW(statement, expected_exception)