1#include "storm-config.h"
36enum class DtmcEngine { PrismSparse, JaniSparse,
Hybrid, PrismDd, JaniDd };
39class SparseGmmxxGmresIluEnvironment {
42 static const DtmcEngine engine = DtmcEngine::PrismSparse;
43 static const bool isExact =
false;
45 typedef storm::models::sparse::Dtmc<ValueType>
ModelType;
46 static storm::Environment createEnvironment() {
47 storm::Environment env;
56class JaniSparseGmmxxGmresIluEnvironment {
59 static const DtmcEngine engine = DtmcEngine::JaniSparse;
60 static const bool isExact =
false;
62 typedef storm::models::sparse::Dtmc<ValueType>
ModelType;
63 static storm::Environment createEnvironment() {
64 storm::Environment env;
73class SparseGmmxxGmresDiagEnvironment {
76 static const DtmcEngine engine = DtmcEngine::PrismSparse;
77 static const bool isExact =
false;
79 typedef storm::models::sparse::Dtmc<ValueType>
ModelType;
80 static storm::Environment createEnvironment() {
81 storm::Environment env;
90class SparseGmmxxBicgstabIluEnvironment {
93 static const DtmcEngine engine = DtmcEngine::PrismSparse;
94 static const bool isExact =
false;
96 typedef storm::models::sparse::Dtmc<ValueType>
ModelType;
97 static storm::Environment createEnvironment() {
98 storm::Environment env;
108class SparseEigenDGmresEnvironment {
111 static const DtmcEngine engine = DtmcEngine::PrismSparse;
112 static const bool isExact =
false;
113 typedef double ValueType;
114 typedef storm::models::sparse::Dtmc<ValueType> ModelType;
115 static storm::Environment createEnvironment() {
116 storm::Environment env;
125class SparseEigenDoubleLUEnvironment {
128 static const DtmcEngine engine = DtmcEngine::PrismSparse;
129 static const bool isExact =
false;
130 typedef double ValueType;
131 typedef storm::models::sparse::Dtmc<ValueType> ModelType;
132 static storm::Environment createEnvironment() {
133 storm::Environment env;
140class SparseEigenRationalLUEnvironment {
143 static const DtmcEngine engine = DtmcEngine::PrismSparse;
144 static const bool isExact =
true;
145 typedef storm::RationalNumber ValueType;
146 typedef storm::models::sparse::Dtmc<ValueType> ModelType;
147 static storm::Environment createEnvironment() {
148 storm::Environment env;
155class SparseRationalEliminationEnvironment {
158 static const DtmcEngine engine = DtmcEngine::PrismSparse;
159 static const bool isExact =
true;
160 typedef storm::RationalNumber ValueType;
161 typedef storm::models::sparse::Dtmc<ValueType> ModelType;
162 static storm::Environment createEnvironment() {
163 storm::Environment env;
169class SparseNativeJacobiEnvironment {
172 static const DtmcEngine engine = DtmcEngine::PrismSparse;
173 static const bool isExact =
false;
174 typedef double ValueType;
175 typedef storm::models::sparse::Dtmc<ValueType> ModelType;
176 static storm::Environment createEnvironment() {
177 storm::Environment env;
185class SparseNativeWalkerChaeEnvironment {
188 static const DtmcEngine engine = DtmcEngine::PrismSparse;
189 static const bool isExact =
false;
190 typedef double ValueType;
191 typedef storm::models::sparse::Dtmc<ValueType> ModelType;
192 static storm::Environment createEnvironment() {
193 storm::Environment env;
202class SparseNativeSorEnvironment {
205 static const DtmcEngine engine = DtmcEngine::PrismSparse;
206 static const bool isExact =
false;
207 typedef double ValueType;
208 typedef storm::models::sparse::Dtmc<ValueType> ModelType;
209 static storm::Environment createEnvironment() {
210 storm::Environment env;
218class SparseNativePowerEnvironment {
221 static const DtmcEngine engine = DtmcEngine::PrismSparse;
222 static const bool isExact =
false;
223 typedef double ValueType;
224 typedef storm::models::sparse::Dtmc<ValueType> ModelType;
225 static storm::Environment createEnvironment() {
226 storm::Environment env;
234class SparseNativeSoundValueIterationEnvironment {
237 static const DtmcEngine engine = DtmcEngine::PrismSparse;
238 static const bool isExact =
false;
239 typedef double ValueType;
240 typedef storm::models::sparse::Dtmc<ValueType> ModelType;
241 static storm::Environment createEnvironment() {
242 storm::Environment env;
245 env.
solver().
native().
setMethod(storm::solver::NativeLinearEquationSolverMethod::SoundValueIteration);
251class SparseNativeOptimisticValueIterationEnvironment {
254 static const DtmcEngine engine = DtmcEngine::PrismSparse;
255 static const bool isExact =
false;
256 typedef double ValueType;
257 typedef storm::models::sparse::Dtmc<ValueType> ModelType;
258 static storm::Environment createEnvironment() {
259 storm::Environment env;
262 env.
solver().
native().
setMethod(storm::solver::NativeLinearEquationSolverMethod::OptimisticValueIteration);
268class SparseNativeGuessingValueIterationEnvironment {
271 static const DtmcEngine engine = DtmcEngine::PrismSparse;
272 static const bool isExact =
false;
273 typedef double ValueType;
274 typedef storm::models::sparse::Dtmc<ValueType> ModelType;
275 static storm::Environment createEnvironment() {
276 storm::Environment env;
279 env.
solver().
native().
setMethod(storm::solver::NativeLinearEquationSolverMethod::GuessingValueIteration);
286class SparseNativeIntervalIterationEnvironment {
289 static const DtmcEngine engine = DtmcEngine::PrismSparse;
290 static const bool isExact =
false;
291 typedef double ValueType;
292 typedef storm::models::sparse::Dtmc<ValueType> ModelType;
293 static storm::Environment createEnvironment() {
294 storm::Environment env;
304class SparseNativeRationalSearchEnvironment {
307 static const DtmcEngine engine = DtmcEngine::PrismSparse;
308 static const bool isExact =
true;
309 typedef storm::RationalNumber ValueType;
310 typedef storm::models::sparse::Dtmc<ValueType> ModelType;
311 static storm::Environment createEnvironment() {
312 storm::Environment env;
319class SparseTopologicalEigenLUEnvironment {
322 static const DtmcEngine engine = DtmcEngine::PrismSparse;
323 static const bool isExact =
true;
324 typedef storm::RationalNumber ValueType;
325 typedef storm::models::sparse::Dtmc<ValueType> ModelType;
326 static storm::Environment createEnvironment() {
327 storm::Environment env;
336class HybridSylvanGmmxxGmresEnvironment {
339 static const DtmcEngine engine = DtmcEngine::Hybrid;
340 static const bool isExact =
false;
342 typedef storm::models::symbolic::Dtmc<ddType, ValueType>
ModelType;
344 static void checkLibraryAvailable() {
345#ifndef STORM_HAVE_SYLVAN
346 GTEST_SKIP() <<
"Library Sylvan not available.";
350 static storm::Environment createEnvironment() {
351 storm::Environment env;
360class HybridCuddNativeJacobiEnvironment {
363 static const DtmcEngine engine = DtmcEngine::Hybrid;
364 static const bool isExact =
false;
365 typedef double ValueType;
366 typedef storm::models::symbolic::Dtmc<ddType, ValueType> ModelType;
368 static void checkLibraryAvailable() {
369#ifndef STORM_HAVE_CUDD
370 GTEST_SKIP() <<
"Library CUDD not available.";
374 static storm::Environment createEnvironment() {
375 storm::Environment env;
383class HybridCuddNativeSoundValueIterationEnvironment {
386 static const DtmcEngine engine = DtmcEngine::Hybrid;
387 static const bool isExact =
false;
388 typedef double ValueType;
389 typedef storm::models::symbolic::Dtmc<ddType, ValueType> ModelType;
391 static void checkLibraryAvailable() {
392#ifndef STORM_HAVE_CUDD
393 GTEST_SKIP() <<
"Library CUDD not available.";
397 static storm::Environment createEnvironment() {
398 storm::Environment env;
407class HybridSylvanNativeRationalSearchEnvironment {
410 static const DtmcEngine engine = DtmcEngine::Hybrid;
411 static const bool isExact =
true;
412 typedef storm::RationalNumber ValueType;
413 typedef storm::models::symbolic::Dtmc<ddType, ValueType> ModelType;
415 static void checkLibraryAvailable() {
416#ifndef STORM_HAVE_SYLVAN
417 GTEST_SKIP() <<
"Library Sylvan not available.";
421 static storm::Environment createEnvironment() {
422 storm::Environment env;
429class DdSylvanNativePowerEnvironment {
432 static const DtmcEngine engine = DtmcEngine::PrismDd;
433 static const bool isExact =
false;
434 typedef double ValueType;
435 typedef storm::models::symbolic::Dtmc<ddType, ValueType> ModelType;
437 static void checkLibraryAvailable() {
438#ifndef STORM_HAVE_SYLVAN
439 GTEST_SKIP() <<
"Library Sylvan not available.";
443 static storm::Environment createEnvironment() {
444 storm::Environment env;
452class JaniDdSylvanNativePowerEnvironment {
455 static const DtmcEngine engine = DtmcEngine::JaniDd;
456 static const bool isExact =
false;
457 typedef double ValueType;
458 typedef storm::models::symbolic::Dtmc<ddType, ValueType> ModelType;
460 static void checkLibraryAvailable() {
461#ifndef STORM_HAVE_SYLVAN
462 GTEST_SKIP() <<
"Library Sylvan not available.";
466 static storm::Environment createEnvironment() {
467 storm::Environment env;
475class DdCuddNativeJacobiEnvironment {
478 static const DtmcEngine engine = DtmcEngine::PrismDd;
479 static const bool isExact =
false;
480 typedef double ValueType;
481 typedef storm::models::symbolic::Dtmc<ddType, ValueType> ModelType;
483 static void checkLibraryAvailable() {
484#ifndef STORM_HAVE_CUDD
485 GTEST_SKIP() <<
"Library CUDD not available.";
489 static storm::Environment createEnvironment() {
490 storm::Environment env;
498class DdSylvanRationalSearchEnvironment {
501 static const DtmcEngine engine = DtmcEngine::PrismDd;
502 static const bool isExact =
true;
503 typedef storm::RationalNumber ValueType;
504 typedef storm::models::symbolic::Dtmc<ddType, ValueType> ModelType;
506 static void checkLibraryAvailable() {
507#ifndef STORM_HAVE_SYLVAN
508 GTEST_SKIP() <<
"Library Sylvan not available.";
512 static storm::Environment createEnvironment() {
513 storm::Environment env;
520template<
typename TestType>
521class DtmcPrctlModelCheckerTest :
public ::testing::Test {
523 typedef typename TestType::ValueType ValueType;
524 typedef typename storm::models::sparse::Dtmc<ValueType> SparseModelType;
525 typedef typename storm::models::symbolic::Dtmc<TestType::ddType, ValueType> SymbolicModelType;
527 DtmcPrctlModelCheckerTest() : _environment(TestType::createEnvironment()) {}
529 void SetUp()
override {
531 GTEST_SKIP() <<
"Z3 not available.";
533 if constexpr (TestType::engine == DtmcEngine::Hybrid || TestType::engine == DtmcEngine::PrismDd || TestType::engine == DtmcEngine::JaniDd) {
534 TestType::checkLibraryAvailable();
538 storm::Environment
const& env()
const {
541 ValueType
parseNumber(std::string
const& input)
const {
544 ValueType precision()
const {
547 bool isSparseModel()
const {
548 return std::is_same<typename TestType::ModelType, SparseModelType>::value;
550 bool isSymbolicModel()
const {
551 return std::is_same<typename TestType::ModelType, SymbolicModelType>::value;
554 template<
typename MT =
typename TestType::ModelType>
555 typename std::enable_if<std::is_same<MT, SparseModelType>::value,
556 std::pair<std::shared_ptr<MT>, std::vector<std::shared_ptr<storm::logic::Formula const>>>>::type
557 buildModelFormulas(std::string
const& pathToPrismFile, std::string
const& formulasAsString, std::string
const& constantDefinitionString =
"")
const {
558 std::pair<std::shared_ptr<MT>, std::vector<std::shared_ptr<storm::logic::Formula const>>> result;
560 program = program.
preprocess(constantDefinitionString);
561 if (TestType::engine == DtmcEngine::PrismSparse) {
564 }
else if (TestType::engine == DtmcEngine::JaniSparse) {
573 template<
typename MT =
typename TestType::ModelType>
574 typename std::enable_if<std::is_same<MT, SymbolicModelType>::value,
575 std::pair<std::shared_ptr<MT>, std::vector<std::shared_ptr<storm::logic::Formula const>>>>::type
576 buildModelFormulas(std::string
const& pathToPrismFile, std::string
const& formulasAsString, std::string
const& constantDefinitionString =
"")
const {
577 std::pair<std::shared_ptr<MT>, std::vector<std::shared_ptr<storm::logic::Formula const>>> result;
579 program = program.
preprocess(constantDefinitionString);
580 if (TestType::engine == DtmcEngine::Hybrid || TestType::engine == DtmcEngine::PrismDd) {
583 }
else if (TestType::engine == DtmcEngine::JaniDd) {
585 janiData.first.substituteFunctions();
592 std::vector<storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>> getTasks(
593 std::vector<std::shared_ptr<storm::logic::Formula const>>
const& formulas)
const {
594 std::vector<storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>> result;
595 for (
auto const& f : formulas) {
596 result.emplace_back(*f);
601 template<
typename MT =
typename TestType::ModelType>
602 typename std::enable_if<std::is_same<MT, SparseModelType>::value, std::shared_ptr<storm::modelchecker::AbstractModelChecker<MT>>>::type createModelChecker(
603 std::shared_ptr<MT>
const& model)
const {
604 if (TestType::engine == DtmcEngine::PrismSparse || TestType::engine == DtmcEngine::JaniSparse) {
605 return std::make_shared<storm::modelchecker::SparseDtmcPrctlModelChecker<SparseModelType>>(*model);
609 template<
typename MT =
typename TestType::ModelType>
610 typename std::enable_if<std::is_same<MT, SymbolicModelType>::value, std::shared_ptr<storm::modelchecker::AbstractModelChecker<MT>>>::type
611 createModelChecker(std::shared_ptr<MT>
const& model)
const {
612 if (TestType::engine == DtmcEngine::Hybrid) {
613 return std::make_shared<storm::modelchecker::HybridDtmcPrctlModelChecker<SymbolicModelType>>(*model);
614 }
else if (TestType::engine == DtmcEngine::PrismDd || TestType::engine == DtmcEngine::JaniDd) {
615 return std::make_shared<storm::modelchecker::SymbolicDtmcPrctlModelChecker<SymbolicModelType>>(*model);
619 template<
typename MT =
typename TestType::ModelType>
620 typename std::enable_if<std::is_same<MT, SparseModelType>::value,
void>::type execute(std::shared_ptr<MT>
const& model,
621 std::function<
void()>
const& f)
const {
625 template<
typename MT =
typename TestType::ModelType>
626 typename std::enable_if<std::is_same<MT, SymbolicModelType>::value,
void>::type execute(std::shared_ptr<MT>
const& model,
627 std::function<
void()>
const& f)
const {
628 model->getManager().execute(f);
631 bool getQualitativeResultAtInitialState(std::shared_ptr<storm::models::Model<ValueType>>
const& model,
632 std::unique_ptr<storm::modelchecker::CheckResult>& result) {
634 result->filter(*filter);
635 return result->asQualitativeCheckResult().forallTrue();
639 std::unique_ptr<storm::modelchecker::CheckResult>& result) {
641 result->filter(*filter);
642 return result->asQuantitativeCheckResult<ValueType>().getMin();
649 void expectQuantitativeResultAtInitialState(std::shared_ptr<storm::models::Model<ValueType>>
const& model,
650 std::unique_ptr<storm::modelchecker::CheckResult>& result, ValueType
const& expected) {
652 if (!result->isExplicitQuantitativeCheckResult()) {
656 auto const& explicitResult = result->template asExplicitQuantitativeCheckResult<ValueType>();
658 if (explicitResult.hasLowerBounds()) {
659 EXPECT_LE(explicitResult.getLowerBoundVector().front(), expected + tolerance) <<
"The lower bound exceeds the expected value.";
661 if (explicitResult.hasUpperBounds()) {
662 EXPECT_LE(expected, explicitResult.getUpperBoundVector().front() + tolerance) <<
"The upper bound falls below the expected value.";
669 void expectExactResultAtInitialState(std::shared_ptr<storm::models::Model<ValueType>>
const& model,
670 std::unique_ptr<storm::modelchecker::CheckResult>& result, ValueType
const& expected) {
671 expectQuantitativeResultAtInitialState(model, result, expected);
672 if (!result->isExplicitQuantitativeCheckResult()) {
675 auto const& explicitResult = result->template asExplicitQuantitativeCheckResult<ValueType>();
676 ASSERT_TRUE(explicitResult.hasLowerBounds()) <<
"No lower bound was reported although the values are exact.";
677 ASSERT_TRUE(explicitResult.hasUpperBounds()) <<
"No upper bound was reported although the values are exact.";
678 EXPECT_EQ(explicitResult.getLowerBoundVector(), explicitResult.getUpperBoundVector()) <<
"The bounds do not pin the values down.";
682 storm::Environment _environment;
684 std::unique_ptr<storm::modelchecker::QualitativeCheckResult>
getInitialStateFilter(std::shared_ptr<storm::models::Model<ValueType>>
const& model)
const {
685 if (isSparseModel()) {
686 return std::make_unique<storm::modelchecker::ExplicitQualitativeCheckResult<ValueType>>(model->template as<SparseModelType>()->getInitialStates());
688 return std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<TestType::ddType>>(
689 model->template as<SymbolicModelType>()->getReachableStates(), model->template as<SymbolicModelType>()->getInitialStates());
694typedef ::testing::Types<
696 SparseGmmxxGmresIluEnvironment, JaniSparseGmmxxGmresIluEnvironment, SparseGmmxxGmresDiagEnvironment, SparseGmmxxBicgstabIluEnvironment,
697 HybridSylvanGmmxxGmresEnvironment,
699 SparseEigenDGmresEnvironment, SparseEigenDoubleLUEnvironment, SparseEigenRationalLUEnvironment, SparseRationalEliminationEnvironment,
700 SparseNativeJacobiEnvironment, SparseNativeWalkerChaeEnvironment, SparseNativeSorEnvironment, SparseNativePowerEnvironment,
701 SparseNativeSoundValueIterationEnvironment, SparseNativeOptimisticValueIterationEnvironment, SparseNativeGuessingValueIterationEnvironment,
702 SparseNativeIntervalIterationEnvironment, SparseNativeRationalSearchEnvironment, SparseTopologicalEigenLUEnvironment, HybridCuddNativeJacobiEnvironment,
703 HybridCuddNativeSoundValueIterationEnvironment, HybridSylvanNativeRationalSearchEnvironment, DdSylvanNativePowerEnvironment,
704 JaniDdSylvanNativePowerEnvironment, DdCuddNativeJacobiEnvironment, DdSylvanRationalSearchEnvironment>
710 std::string formulasString =
"P=? [F \"one\"]";
711 formulasString +=
"; P=? [F \"two\"]";
712 formulasString +=
"; P=? [F \"three\"]";
713 formulasString +=
"; R=? [F \"done\"]";
715 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/dtmc/die.pm", formulasString);
716 auto model = std::move(modelFormulas.first);
717 auto tasks = this->getTasks(modelFormulas.second);
718 this->execute(model, [&]() {
719 EXPECT_EQ(13ul, model->getNumberOfStates());
720 EXPECT_EQ(20ul, model->getNumberOfTransitions());
722 auto checker = this->createModelChecker(model);
723 std::unique_ptr<storm::modelchecker::CheckResult> result;
725 result = checker->check(this->env(), tasks[0]);
726 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/6"));
728 result = checker->check(this->env(), tasks[1]);
729 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/6"));
731 result = checker->check(this->env(), tasks[2]);
732 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/6"));
734 result = checker->check(this->env(), tasks[3]);
735 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"11/3"));
740 std::string formulasString =
"P=? [F observe0>1]";
741 formulasString +=
"; P=? [F \"observeIGreater1\"]";
742 formulasString +=
"; P=? [F observe1>1]";
744 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/dtmc/crowds-4-3.pm", formulasString);
745 auto model = std::move(modelFormulas.first);
746 auto tasks = this->getTasks(modelFormulas.second);
747 this->execute(model, [&]() {
748 EXPECT_EQ(726ul, model->getNumberOfStates());
749 EXPECT_EQ(1146ul, 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(
"78686542099694893/1268858272000000000"));
757 result = checker->check(this->env(), tasks[1]);
758 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"40300855878315123/1268858272000000000"));
760 result = checker->check(this->env(), tasks[2]);
761 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"13433618626105041/1268858272000000000"));
765TYPED_TEST(DtmcPrctlModelCheckerTest, SynchronousLeader) {
766 std::string formulasString =
"P=? [F \"elected\"]";
767 formulasString +=
"; P=? [F<=5 \"elected\"]";
768 formulasString +=
"; R=? [F \"elected\"]";
770 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/dtmc/leader-3-5.pm", formulasString);
771 auto model = std::move(modelFormulas.first);
772 auto tasks = this->getTasks(modelFormulas.second);
773 this->execute(model, [&]() {
774 EXPECT_EQ(273ul, model->getNumberOfStates());
775 EXPECT_EQ(397ul, model->getNumberOfTransitions());
777 auto checker = this->createModelChecker(model);
778 std::unique_ptr<storm::modelchecker::CheckResult> result;
780 result = checker->check(this->env(), tasks[0]);
781 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1"));
783 result = checker->check(this->env(), tasks[1]);
784 this->expectExactResultAtInitialState(model, result, this->parseNumber(
"24/25"));
786 result = checker->check(this->env(), tasks[2]);
787 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"25/24"));
791TEST(DtmcPrctlModelCheckerTest, BoundedReachability) {
792 std::string formulasString =
"P=? [F<=1 \"a\"]";
793 formulasString +=
"; P=? [F[1,1] \"a\"]";
794 formulasString +=
"; P=? [F[0,2] \"a\"]";
796 std::shared_ptr<storm::models::sparse::Model<double>> modelPtr =
806 auto expectExactValue = [](std::unique_ptr<storm::modelchecker::CheckResult>
const& result,
double expected) {
807 EXPECT_NEAR(expected, result->asQuantitativeCheckResult<
double>().getMin(), 0.0001);
808 auto const& explicitResult = result->asExplicitQuantitativeCheckResult<
double>();
809 ASSERT_TRUE(explicitResult.hasLowerBounds());
810 ASSERT_TRUE(explicitResult.hasUpperBounds());
811 EXPECT_EQ(explicitResult.getLowerBoundVector(), explicitResult.getUpperBoundVector());
815 auto result = checker.
check(env, task);
816 auto filter = std::make_unique<storm::modelchecker::ExplicitQualitativeCheckResult<double>>(dtmc->getInitialStates());
817 result->filter(*filter);
818 expectExactValue(result, 0.2);
822 result = checker.check(env, task);
823 filter = std::make_unique<storm::modelchecker::ExplicitQualitativeCheckResult<double>>(dtmc->getInitialStates());
824 result->filter(*filter);
825 expectExactValue(result, 0.2);
829 result = checker.check(env, task);
830 filter = std::make_unique<storm::modelchecker::ExplicitQualitativeCheckResult<double>>(dtmc->getInitialStates());
831 result->filter(*filter);
832 expectExactValue(result, 0.366);
835TEST(DtmcPrctlModelCheckerTest, AllUntilProbabilities) {
837 GTEST_SKIP() <<
"Z3 not available.";
839 std::string formulasString =
"P=? [F \"one\"]";
840 formulasString +=
"; P=? [F \"two\"]";
841 formulasString +=
"; P=? [F \"three\"]";
845 std::vector<storm::modelchecker::CheckTask<storm::logic::Formula, double>> tasks;
846 for (
auto const& f : formulas) {
847 tasks.emplace_back(*f);
850 EXPECT_EQ(13ul, model->getNumberOfStates());
851 EXPECT_EQ(20ul, model->getNumberOfTransitions());
855 initialStates.set(0);
867 initialStates, phiStates, psiStates);
869 EXPECT_NEAR(1.0 / 6, result[7], 1e-6);
870 EXPECT_NEAR(1.0 / 6, result[8], 1e-6);
871 EXPECT_NEAR(1.0 / 6, result[9], 1e-6);
872 EXPECT_NEAR(1.0 / 6, result[10], 1e-6);
873 EXPECT_NEAR(1.0 / 6, result[11], 1e-6);
874 EXPECT_NEAR(1.0 / 6, result[12], 1e-6);
882 EXPECT_NEAR(1, result[0], 1e-6);
883 EXPECT_NEAR(0.5, result[1], 1e-6);
884 EXPECT_NEAR(0.5, result[2], 1e-6);
885 EXPECT_NEAR(0.25, result[5], 1e-6);
886 EXPECT_NEAR(0, result[7], 1e-6);
887 EXPECT_NEAR(0, result[8], 1e-6);
888 EXPECT_NEAR(0, result[9], 1e-6);
889 EXPECT_NEAR(0.125, result[10], 1e-6);
890 EXPECT_NEAR(0.125, result[11], 1e-6);
891 EXPECT_NEAR(0, result[12], 1e-6);
894TYPED_TEST(DtmcPrctlModelCheckerTest, LtlProbabilitiesDie) {
895#ifdef STORM_HAVE_LTL_MODELCHECKING_SUPPORT
896 std::string formulasString =
"P=? [(X s>0) U (s=7 & d=2)]";
897 formulasString +=
"; P=? [ X (((s=1) U (s=3)) U (s=7))]";
898 formulasString +=
"; P=? [ (F (X (s=6 & (XX s=5)))) & (F G (d!=5))]";
899 formulasString +=
"; P=? [ F (s=3 U (\"three\"))]";
900 formulasString +=
"; P=? [ F s=3 U (\"three\")]";
901 formulasString +=
"; P=? [ F (s=6) & X \"done\"]";
902 formulasString +=
"; P=? [ (F s=6) & (X \"done\")]";
904 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/dtmc/die.pm", formulasString);
905 auto model = std::move(modelFormulas.first);
906 auto tasks = this->getTasks(modelFormulas.second);
907 this->execute(model, [&]() {
908 EXPECT_EQ(13ul, model->getNumberOfStates());
909 EXPECT_EQ(20ul, model->getNumberOfTransitions());
911 auto checker = this->createModelChecker(model);
912 std::unique_ptr<storm::modelchecker::CheckResult> result;
915 if (TypeParam::engine == DtmcEngine::PrismSparse || TypeParam::engine == DtmcEngine::JaniSparse) {
916 result = checker->check(tasks[0]);
917 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/6"));
919 result = checker->check(tasks[1]);
920 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/6"));
922 result = checker->check(tasks[2]);
923 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/24"));
925 result = checker->check(tasks[3]);
926 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/6"));
928 result = checker->check(tasks[4]);
929 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"0"));
931 result = checker->check(tasks[5]);
932 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/6"));
934 result = checker->check(tasks[6]);
935 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"0"));
937 EXPECT_FALSE(checker->canHandle(tasks[0]));
945TYPED_TEST(DtmcPrctlModelCheckerTest, LtlProbabilitiesSynchronousLeader) {
946#ifdef STORM_HAVE_LTL_MODELCHECKING_SUPPORT
947 std::string formulasString =
"P=? [X (u1=true U \"elected\")]";
948 formulasString +=
"; P=? [X !(u1=true U \"elected\")]";
949 formulasString +=
"; P=? [X v1=2 & X v1=1]";
950 formulasString +=
"; P=? [(X v1=2) & (X v1=1)]";
951 formulasString +=
"; P=? [(!X v1=2) & (X v1=1)]";
953 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/dtmc/leader-3-5.pm", formulasString);
954 auto model = std::move(modelFormulas.first);
955 auto tasks = this->getTasks(modelFormulas.second);
956 this->execute(model, [&]() {
957 EXPECT_EQ(273ul, model->getNumberOfStates());
958 EXPECT_EQ(397ul, model->getNumberOfTransitions());
960 auto checker = this->createModelChecker(model);
961 std::unique_ptr<storm::modelchecker::CheckResult> result;
964 if (TypeParam::engine == DtmcEngine::PrismSparse || TypeParam::engine == DtmcEngine::JaniSparse) {
965 result = checker->check(tasks[0]);
966 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"16/25"));
968 result = checker->check(tasks[1]);
969 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"9/25"));
971 result = checker->check(tasks[2]);
972 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/25"));
974 result = checker->check(tasks[3]);
975 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"0"));
977 result = checker->check(tasks[4]);
978 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/5"));
981 EXPECT_FALSE(checker->canHandle(tasks[0]));
989TYPED_TEST(DtmcPrctlModelCheckerTest, HOAProbabilitiesDie) {
991 std::string formulasString =
"P=?[HOA: {\"" STORM_TEST_RESOURCES_DIR
"/hoa/automaton_UXp0p1.hoa\", \"p0\" -> (s>0), \"p1\" -> (s=7 & d=2) }]";
993 formulasString +=
"; P=?[HOA: {\"" STORM_TEST_RESOURCES_DIR
"/hoa/automaton_UXp0p1.hoa\", \"p0\" -> (s>0), \"p1\" -> (d=4 | d=2) }]";
995 formulasString +=
"; P=?[HOA: {\"" STORM_TEST_RESOURCES_DIR
"/hoa/automaton_Fandp0Xp1.hoa\", \"p0\" -> (s=4), \"p1\" -> \"three\" }]";
997 formulasString +=
"; P=?[HOA: {\"" STORM_TEST_RESOURCES_DIR
"/hoa/automaton_Fandp0Xp1.hoa\", \"p0\" -> (s=6), \"p1\" -> \"done\" }]";
999 formulasString +=
"; P=?[HOA: {\"" STORM_TEST_RESOURCES_DIR
"/hoa/automaton_Fandp0Xp1.hoa\", \"p0\" -> (s=6), \"p1\" -> !\"done\" }]";
1001 formulasString +=
"; P=?[HOA: {\"" STORM_TEST_RESOURCES_DIR
"/hoa/automaton_Fandp0Xp1.hoa\", \"p0\" -> (s=4 | s=5), \"p1\" -> s=7 & (d=3 | d=5) }]";
1003 formulasString +=
"; P>0.3[HOA: {\"" STORM_TEST_RESOURCES_DIR
"/hoa/automaton_Fandp0Xp1.hoa\", \"p0\" -> (s=4 | s=5), \"p1\" -> s=7 & (d=3 | d=5) }]";
1005 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/dtmc/die.pm", formulasString);
1006 auto model = std::move(modelFormulas.first);
1007 auto tasks = this->getTasks(modelFormulas.second);
1008 this->execute(model, [&]() {
1009 EXPECT_EQ(13ul, model->getNumberOfStates());
1010 EXPECT_EQ(20ul, model->getNumberOfTransitions());
1012 auto checker = this->createModelChecker(model);
1013 std::unique_ptr<storm::modelchecker::CheckResult> result;
1016 if (TypeParam::engine == DtmcEngine::PrismSparse || TypeParam::engine == DtmcEngine::JaniSparse) {
1017 result = checker->check(tasks[0]);
1018 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/6"));
1020 result = checker->check(tasks[1]);
1021 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/3"));
1023 result = checker->check(tasks[2]);
1024 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/6"));
1026 result = checker->check(tasks[3]);
1027 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/6"));
1029 result = checker->check(tasks[4]);
1030 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/8"));
1032 result = checker->check(tasks[5]);
1033 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"1/3"));
1035 result = checker->check(tasks[6]);
1036 EXPECT_TRUE(this->getQualitativeResultAtInitialState(model, result));
1038 EXPECT_FALSE(checker->canHandle(tasks[0]));
1043TYPED_TEST(DtmcPrctlModelCheckerTest, SmallDiscount) {
1044 if (TypeParam::isExact) {
1045 GTEST_SKIP() <<
"Exact computations for discounted properties are not supported.";
1047 std::string formulasString =
"R=? [ C ]";
1048 formulasString +=
"; R=? [ Cdiscount=9/10 ]";
1049 formulasString +=
"; R=? [ Cdiscount=15/16 ]";
1050 formulasString +=
"; R=? [ C<5discount=9/10 ]";
1051 formulasString +=
"; R=? [ C<5discount=15/16 ]";
1052 auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR
"/dtmc/small_discount.nm", formulasString);
1053 auto model = std::move(modelFormulas.first);
1054 auto tasks = this->getTasks(modelFormulas.second);
1055 EXPECT_EQ(3ul, model->getNumberOfStates());
1056 EXPECT_EQ(4ul, model->getNumberOfTransitions());
1058 auto checker = this->createModelChecker(model);
1060 if (TypeParam::engine == DtmcEngine::PrismSparse || TypeParam::engine == DtmcEngine::JaniSparse) {
1061 std::unique_ptr<storm::modelchecker::CheckResult> result = checker->check(this->env(), tasks[0]);
1062 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"5"));
1064 result = checker->check(this->env(), tasks[1]);
1065 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"45/14"));
1066 result = checker->check(this->env(), tasks[2]);
1067 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"15/4"));
1068 result = checker->check(this->env(), tasks[3]);
1069 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"12591/6250"));
1070 result = checker->check(this->env(), tasks[4]);
1071 this->expectQuantitativeResultAtInitialState(model, result, this->parseNumber(
"555/256"));
1073 EXPECT_FALSE(checker->canHandle(tasks[0]));
1074 EXPECT_FALSE(checker->canHandle(tasks[1]));
1075 EXPECT_FALSE(checker->canHandle(tasks[2]));
1076 EXPECT_FALSE(checker->canHandle(tasks[3]));
1077 EXPECT_FALSE(checker->canHandle(tasks[4]));
TEST(RegionConstraintCheckerTest, AffineConstraintHoldsThroughout)
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)
void setPrecision(storm::RationalNumber value)
void setMethod(storm::solver::EigenLinearEquationSolverMethod value, bool isSetFromDefault=false)
void setPreconditioner(storm::solver::EigenLinearEquationSolverPreconditioner value)
SolverEnvironment & solver()
void setMethod(storm::solver::GmmxxLinearEquationSolverMethod value)
void setPrecision(storm::RationalNumber value)
void setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner value)
void setMaximalNumberOfIterations(uint64_t value)
void setRelativeTerminationCriterion(bool value)
void setPrecision(storm::RationalNumber value)
void setMethod(storm::solver::NativeLinearEquationSolverMethod value, bool isSetFromDefault=false)
TopologicalSolverEnvironment & topological()
void setLinearEquationSolverType(storm::solver::EquationSolverType const &value, bool isSetFromDefault=false)
EigenSolverEnvironment & eigen()
void setForceSoundness(bool value)
NativeSolverEnvironment & native()
GmmxxSolverEnvironment & gmmxx()
void setUnderlyingEquationSolverType(storm::solver::EquationSolverType value, bool isSetFromDefault=false)
virtual std::unique_ptr< CheckResult > check(Environment const &env, CheckTask< storm::logic::Formula, SolutionType > const &checkTask)
Checks the provided formula.
static std::vector< SolutionType > computeAllUntilProbabilities(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::BitVector const &initialStates, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
This class represents a discrete-time Markov chain.
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...
A bit vector that is internally represented as a vector of 64-bit values.
A class that holds a possibly non-square matrix in the compressed row storage format.
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)
std::vector< storm::jani::Property > parseProperties(storm::parser::FormulaParser &formulaParser, std::string const &inputString, boost::optional< std::set< std::string > > const &propertyFilter)
SFTBDDChecker::ValueType ValueType
NumberType parseNumber(std::string const &value)
Parse number from string.
template STORM_PARSERS_API std::shared_ptr< storm::models::sparse::Model< double > > parseDirectEncodingModel< double >(std::filesystem::path const &file, DirectEncodingParserOptions const &options)
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.
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)