#include "gtest/gtest.h" #include "test/storm_gtest.h" #include "storm-config.h" #include "storm/api/builder.h" #include "storm/api/model_descriptions.h" #include "storm/api/properties.h" #include "storm/parser/FormulaParser.h" #include "storm/logic/Formulas.h" #include "storm/solver/EigenLinearEquationSolver.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/models/symbolic/StandardRewardModel.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/symbolic/Dtmc.h" #include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" #include "storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h" #include "storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h" #include "storm/modelchecker/results/QuantitativeCheckResult.h" #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h" #include "storm/modelchecker/results/QualitativeCheckResult.h" #include "storm/parser/PrismParser.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/environment/solver/GmmxxSolverEnvironment.h" #include "storm/environment/solver/EigenSolverEnvironment.h" #include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h" namespace { class SparseGmmxxGmresIluEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = false; typedef double ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Gmmxx); env.solver().gmmxx().setMethod(storm::solver::GmmxxLinearEquationSolverMethod::Gmres); env.solver().gmmxx().setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner::Ilu); env.solver().gmmxx().setPrecision(storm::utility::convertNumber(1e-8)); return env; } }; class SparseGmmxxGmresDiagEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = false; typedef double ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Gmmxx); env.solver().gmmxx().setMethod(storm::solver::GmmxxLinearEquationSolverMethod::Gmres); env.solver().gmmxx().setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner::Diagonal); env.solver().gmmxx().setPrecision(storm::utility::convertNumber(1e-8)); return env; } }; class SparseGmmxxBicgstabIluEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = false; typedef double ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Gmmxx); env.solver().gmmxx().setMethod(storm::solver::GmmxxLinearEquationSolverMethod::Bicgstab); env.solver().gmmxx().setPreconditioner(storm::solver::GmmxxLinearEquationSolverPreconditioner::Ilu); env.solver().gmmxx().setPrecision(storm::utility::convertNumber(1e-8)); return env; } }; class SparseEigenDGmresEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = false; typedef double ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Eigen); env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::DGmres); env.solver().eigen().setPreconditioner(storm::solver::EigenLinearEquationSolverPreconditioner::Ilu); env.solver().eigen().setPrecision(storm::utility::convertNumber(1e-8)); return env; } }; class SparseEigenDoubleLUEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = false; typedef double ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Eigen); env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::SparseLU); return env; } }; class SparseEigenRationalLUEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = true; typedef storm::RationalNumber ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Eigen); env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::SparseLU); return env; } }; class SparseRationalEliminationEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = true; typedef storm::RationalNumber ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Elimination); return env; } }; class SparseNativeJacobiEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = false; typedef double ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Jacobi); env.solver().native().setPrecision(storm::utility::convertNumber(1e-8)); return env; } }; class SparseNativeWalkerChaeEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = false; typedef double ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::WalkerChae); env.solver().native().setMaximalNumberOfIterations(1000000); env.solver().native().setPrecision(storm::utility::convertNumber(1e-7)); return env; } }; class SparseNativeSorEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = false; typedef double ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::SOR); env.solver().native().setPrecision(storm::utility::convertNumber(1e-8)); return env; } }; class SparseNativePowerEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = false; typedef double ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Power); env.solver().native().setPrecision(storm::utility::convertNumber(1e-8)); return env; } }; class SparseNativeSoundPowerEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = false; typedef double ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setForceSoundness(true); env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Power); env.solver().native().setPrecision(storm::utility::convertNumber(1e-6)); return env; } }; class SparseNativeQuickSoundPowerEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = false; typedef double ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setForceSoundness(true); env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::QuickPower); env.solver().native().setRelativeTerminationCriterion(false); env.solver().native().setPrecision(storm::utility::convertNumber(1e-6)); return env; } }; class SparseNativeRationalSearchEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = true; typedef storm::RationalNumber ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::RationalSearch); return env; } }; class SparseTopologicalEigenLUEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; static const bool isExact = true; typedef storm::RationalNumber ValueType; typedef storm::models::sparse::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Topological); env.solver().topological().setUnderlyingSolverType(storm::solver::EquationSolverType::Eigen); env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::SparseLU); return env; } }; class HybridSylvanGmmxxGmresEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Hybrid; static const bool isExact = false; typedef double ValueType; typedef storm::models::symbolic::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Gmmxx); env.solver().gmmxx().setMethod(storm::solver::GmmxxLinearEquationSolverMethod::Gmres); env.solver().gmmxx().setPrecision(storm::utility::convertNumber(1e-8)); return env; } }; class HybridCuddNativeJacobiEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::CUDD; static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Hybrid; static const bool isExact = false; typedef double ValueType; typedef storm::models::symbolic::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Jacobi); env.solver().native().setPrecision(storm::utility::convertNumber(1e-8)); return env; } }; class HybridCuddNativeSoundPowerEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::CUDD; static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Hybrid; static const bool isExact = false; typedef double ValueType; typedef storm::models::symbolic::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setForceSoundness(true); env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Power); env.solver().native().setPrecision(storm::utility::convertNumber(1e-6)); return env; } }; class HybridSylvanNativeRationalSearchEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Hybrid; static const bool isExact = true; typedef storm::RationalNumber ValueType; typedef storm::models::symbolic::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::RationalSearch); return env; } }; class DdSylvanNativePowerEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Dd; static const bool isExact = false; typedef double ValueType; typedef storm::models::symbolic::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Power); env.solver().native().setPrecision(storm::utility::convertNumber(1e-8)); return env; } }; class DdCuddNativeJacobiEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::CUDD; static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Dd; static const bool isExact = false; typedef double ValueType; typedef storm::models::symbolic::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Power); env.solver().native().setPrecision(storm::utility::convertNumber(1e-8)); return env; } }; class DdSylvanRationalSearchEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Dd; static const bool isExact = true; typedef storm::RationalNumber ValueType; typedef storm::models::symbolic::Dtmc ModelType; static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::RationalSearch); return env; } }; template class DtmcPrctlModelCheckerTest : public ::testing::Test { public: typedef typename TestType::ValueType ValueType; typedef typename storm::models::sparse::Dtmc SparseModelType; typedef typename storm::models::symbolic::Dtmc SymbolicModelType; DtmcPrctlModelCheckerTest() : _environment(TestType::createEnvironment()) {} storm::Environment const& env() const { return _environment; } ValueType parseNumber(std::string const& input) const { return storm::utility::convertNumber(input);} ValueType precision() const { return TestType::isExact ? parseNumber("0") : parseNumber("1e-6");} bool isSparseModel() const { return std::is_same::value; } bool isSymbolicModel() const { return std::is_same::value; } template typename std::enable_if::value, std::pair, std::vector>>>::type buildModelFormulas(std::string const& pathToPrismFile, std::string const& formulasAsString, std::string const& constantDefinitionString = "") const { std::pair, std::vector>> result; storm::prism::Program program = storm::api::parseProgram(pathToPrismFile); program = storm::utility::prism::preprocess(program, constantDefinitionString); result.second = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulasAsString, program)); result.first = storm::api::buildSparseModel(program, result.second)->template as(); return result; } template typename std::enable_if::value, std::pair, std::vector>>>::type buildModelFormulas(std::string const& pathToPrismFile, std::string const& formulasAsString, std::string const& constantDefinitionString = "") const { std::pair, std::vector>> result; storm::prism::Program program = storm::api::parseProgram(pathToPrismFile); program = storm::utility::prism::preprocess(program, constantDefinitionString); result.second = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulasAsString, program)); result.first = storm::api::buildSymbolicModel(program, result.second)->template as(); return result; } std::vector> getTasks(std::vector> const& formulas) const { std::vector> result; for (auto const& f : formulas) { result.emplace_back(*f); } return result; } template typename std::enable_if::value, std::shared_ptr>>::type createModelChecker(std::shared_ptr const& model) const { if (TestType::engine == storm::settings::modules::CoreSettings::Engine::Sparse) { return std::make_shared>(*model); } } template typename std::enable_if::value, std::shared_ptr>>::type createModelChecker(std::shared_ptr const& model) const { if (TestType::engine == storm::settings::modules::CoreSettings::Engine::Hybrid) { return std::make_shared>(*model); } else if (TestType::engine == storm::settings::modules::CoreSettings::Engine::Dd) { return std::make_shared>(*model); } } bool getQualitativeResultAtInitialState(std::shared_ptr> const& model, std::unique_ptr& result) { auto filter = getInitialStateFilter(model); result->filter(*filter); return result->asQualitativeCheckResult().forallTrue(); } ValueType getQuantitativeResultAtInitialState(std::shared_ptr> const& model, std::unique_ptr& result) { auto filter = getInitialStateFilter(model); result->filter(*filter); return result->asQuantitativeCheckResult().getMin(); } private: storm::Environment _environment; std::unique_ptr getInitialStateFilter(std::shared_ptr> const& model) const { if (isSparseModel()) { return std::make_unique(model->template as()->getInitialStates()); } else { return std::make_unique>(model->template as()->getReachableStates(), model->template as()->getInitialStates()); } } }; typedef ::testing::Types< SparseGmmxxGmresIluEnvironment, SparseGmmxxGmresDiagEnvironment, SparseGmmxxBicgstabIluEnvironment, SparseEigenDGmresEnvironment, SparseEigenDoubleLUEnvironment, SparseEigenRationalLUEnvironment, SparseRationalEliminationEnvironment, SparseNativeJacobiEnvironment, SparseNativeWalkerChaeEnvironment, SparseNativeSorEnvironment, SparseNativePowerEnvironment, SparseNativeSoundPowerEnvironment, SparseNativeQuickSoundPowerEnvironment, SparseNativeRationalSearchEnvironment, SparseTopologicalEigenLUEnvironment, HybridSylvanGmmxxGmresEnvironment, HybridCuddNativeJacobiEnvironment, HybridCuddNativeSoundPowerEnvironment, HybridSylvanNativeRationalSearchEnvironment, DdSylvanNativePowerEnvironment, DdCuddNativeJacobiEnvironment, DdSylvanRationalSearchEnvironment > TestingTypes; TYPED_TEST_CASE(DtmcPrctlModelCheckerTest, TestingTypes); TYPED_TEST(DtmcPrctlModelCheckerTest, Die) { std::string formulasString = "P=? [F \"one\"]"; formulasString += "; P=? [F \"two\"]"; formulasString += "; P=? [F \"three\"]"; formulasString += "; R=? [F \"done\"]"; auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR "/dtmc/die.pm", formulasString); auto model = std::move(modelFormulas.first); auto tasks = this->getTasks(modelFormulas.second); EXPECT_EQ(13ul, model->getNumberOfStates()); EXPECT_EQ(20ul, model->getNumberOfTransitions()); ASSERT_EQ(model->getType(), storm::models::ModelType::Dtmc); auto checker = this->createModelChecker(model); std::unique_ptr result; result = checker->check(this->env(), tasks[0]); EXPECT_NEAR(this->parseNumber("1/6"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); result = checker->check(this->env(), tasks[1]); EXPECT_NEAR(this->parseNumber("1/6"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); result = checker->check(this->env(), tasks[2]); EXPECT_NEAR(this->parseNumber("1/6"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); result = checker->check(this->env(), tasks[3]); EXPECT_NEAR(this->parseNumber("11/3"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); } TYPED_TEST(DtmcPrctlModelCheckerTest, Crowds) { std::string formulasString = "P=? [F observe0>1]"; formulasString += "; P=? [F \"observeIGreater1\"]"; formulasString += "; P=? [F observe1>1]"; auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR "/dtmc/crowds-4-3.pm", formulasString); auto model = std::move(modelFormulas.first); auto tasks = this->getTasks(modelFormulas.second); EXPECT_EQ(726ul, model->getNumberOfStates()); EXPECT_EQ(1146ul, model->getNumberOfTransitions()); ASSERT_EQ(model->getType(), storm::models::ModelType::Dtmc); auto checker = this->createModelChecker(model); std::unique_ptr result; result = checker->check(this->env(), tasks[0]); EXPECT_NEAR(this->parseNumber("78686542099694893/1268858272000000000"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); result = checker->check(this->env(), tasks[1]); EXPECT_NEAR(this->parseNumber("40300855878315123/1268858272000000000"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); result = checker->check(this->env(), tasks[2]); EXPECT_NEAR(this->parseNumber("13433618626105041/1268858272000000000"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); } TYPED_TEST(DtmcPrctlModelCheckerTest, SynchronousLeader) { std::string formulasString = "P=? [F \"elected\"]"; formulasString += "; P=? [F<=5 \"elected\"]"; formulasString += "; R=? [F \"elected\"]"; auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR "/dtmc/leader-3-5.pm", formulasString); auto model = std::move(modelFormulas.first); auto tasks = this->getTasks(modelFormulas.second); EXPECT_EQ(273ul, model->getNumberOfStates()); EXPECT_EQ(397ul, model->getNumberOfTransitions()); ASSERT_EQ(model->getType(), storm::models::ModelType::Dtmc); auto checker = this->createModelChecker(model); std::unique_ptr result; result = checker->check(this->env(), tasks[0]); EXPECT_NEAR(this->parseNumber("1"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); result = checker->check(this->env(), tasks[1]); EXPECT_NEAR(this->parseNumber("24/25"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); result = checker->check(this->env(), tasks[2]); EXPECT_NEAR(this->parseNumber("25/24"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); } }