#ifndef STORM_H #define STORM_H #include #include #include #include #include #include #include "storm/storage/ModelFormulasPair.h" #include "initialize.h" #include "storm-config.h" // Headers that provide auxiliary functionality. #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/IOSettings.h" #include "storm/settings/modules/BisimulationSettings.h" #include "storm/settings/modules/ParametricSettings.h" #include "storm/settings/modules/EliminationSettings.h" #include "storm/settings/modules/JitBuilderSettings.h" #include "storm/settings/modules/JaniExportSettings.h" // Formula headers. #include "storm/logic/Formulas.h" #include "storm/logic/FragmentSpecification.h" // Model headers. #include "storm/models/ModelBase.h" #include "storm/models/sparse/Model.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/models/symbolic/Model.h" #include "storm/models/symbolic/StandardRewardModel.h" #include "storm/storage/dd/Add.h" #include "storm/storage/dd/Bdd.h" #include "storm/parser/AutoParser.h" #include "storm/parser/DirectEncodingParser.h" #include "storm/storage/jani/Model.h" #include "storm/storage/jani/Property.h" // Headers of builders. #include "storm/builder/ExplicitModelBuilder.h" #include "storm/builder/jit/ExplicitJitJaniModelBuilder.h" #include "storm/builder/DdPrismModelBuilder.h" #include "storm/builder/DdJaniModelBuilder.h" // Headers for model processing. #include "storm/storage/bisimulation/DeterministicModelBisimulationDecomposition.h" #include "storm/storage/bisimulation/NondeterministicModelBisimulationDecomposition.h" #include "storm/transformer/SymbolicToSparseTransformer.h" #include "storm/storage/ModelFormulasPair.h" #include "storm/storage/SymbolicModelDescription.h" #include "storm/storage/jani/JSONExporter.h" // Headers for model checking. #include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" #include "storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h" #include "storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h" #include "storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h" #include "storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h" #include "storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h" #include "storm/modelchecker/reachability/SparseDtmcEliminationModelChecker.h" #include "storm/modelchecker/abstraction/GameBasedMdpModelChecker.h" #include "storm/modelchecker/exploration/SparseExplorationModelChecker.h" #include "storm/modelchecker/parametric/SparseDtmcRegionChecker.h" #include "storm/modelchecker/parametric/SparseMdpRegionChecker.h" #include "storm/utility/parameterlifting.h" #include "storm/modelchecker/csl/SparseCtmcCslModelChecker.h" #include "storm/modelchecker/csl/helper/SparseCtmcCslHelper.h" #include "storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h" #include "storm/modelchecker/csl/HybridCtmcCslModelChecker.h" #include "storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h" #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h" #include "storm/modelchecker/results/HybridQuantitativeCheckResult.h" #include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h" #include "storm/transformer/ContinuousToDiscreteTimeModelTransformer.h" // Headers for counterexample generation. #include "storm/counterexamples/MILPMinimalCommandSetGenerator.h" #include "storm/counterexamples/SMTMinimalCommandSetGenerator.h" // Headers related to model building. #include "storm/generator/PrismNextStateGenerator.h" #include "storm/generator/JaniNextStateGenerator.h" #include "storm/analysis/GraphConditions.h" // Headers related to exception handling. #include "storm/exceptions/InvalidStateException.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/InvalidSettingsException.h" #include "storm/exceptions/InvalidTypeException.h" #include "storm/exceptions/NotImplementedException.h" #include "storm/exceptions/NotSupportedException.h" #include "storm/utility/Stopwatch.h" #include "storm/utility/file.h" namespace storm { namespace parser { class FormulaParser; } template inline std::shared_ptr> buildExplicitModel(std::string const&, std::string const&, boost::optional const& = boost::none, boost::optional const& = boost::none, boost::optional const& = boost::none) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Exact or parametric models with explicit input are not supported."); } template<> inline std::shared_ptr> buildExplicitModel(std::string const& transitionsFile, std::string const& labelingFile, boost::optional const& stateRewardsFile, boost::optional const& transitionRewardsFile, boost::optional const& choiceLabelingFile) { return storm::parser::AutoParser::parseModel(transitionsFile, labelingFile, stateRewardsFile ? stateRewardsFile.get() : "", transitionRewardsFile ? transitionRewardsFile.get() : "", choiceLabelingFile ? choiceLabelingFile.get() : "" ); } template inline std::shared_ptr> buildExplicitDRNModel(std::string const& drnFile) { return storm::parser::DirectEncodingParser::parseModel(drnFile); } template<> inline std::shared_ptr> buildExplicitDRNModel(std::string const&) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Exact models with direct encoding are not supported."); } std::vector> extractFormulasFromProperties(std::vector const& properties); std::pair> parseJaniModel(std::string const& path); storm::prism::Program parseProgram(std::string const& path); std::vector substituteConstantsInProperties(std::vector const& properties, std::map const& substitution); std::vector parseProperties(storm::parser::FormulaParser& formulaParser, std::string const& inputString, boost::optional> const& propertyFilter = boost::none); std::vector parsePropertiesForExplicit(std::string const& inputString, boost::optional> const& propertyFilter = boost::none); std::vector parsePropertiesForPrismProgram(std::string const& inputString, storm::prism::Program const& program, boost::optional> const& propertyFilter = boost::none); std::vector parsePropertiesForJaniModel(std::string const& inputString, storm::jani::Model const& model, boost::optional> const& propertyFilter = boost::none); boost::optional> parsePropertyFilter(boost::optional const& propertyFilter); std::vector filterProperties(std::vector const& properties, boost::optional> const& propertyFilter); template std::shared_ptr> buildSparseModel(storm::storage::SymbolicModelDescription const& model, std::vector> const& formulas) { storm::builder::BuilderOptions options(formulas); if (storm::settings::getModule().isBuildChoiceLabelsSet()) { options.setBuildChoiceLabels(true); } if (storm::settings::getModule().isBuildFullModelSet()) { options.setBuildAllLabels(); options.setBuildAllRewardModels(); options.setBuildChoiceLabels(true); options.clearTerminalStates(); } // Generate command labels if we are going to build a counterexample later. if (storm::settings::getModule().isMinimalCommandSetGenerationSet()) { options.setBuildChoiceOrigins(true); } if (storm::settings::getModule().isJitSet()) { STORM_LOG_THROW(model.isJaniModel(), storm::exceptions::NotSupportedException, "Cannot use JIT-based model builder for non-JANI model."); storm::builder::jit::ExplicitJitJaniModelBuilder builder(model.asJaniModel(), options); if (storm::settings::getModule().isDoctorSet()) { bool result = builder.doctor(); STORM_LOG_THROW(result, storm::exceptions::InvalidSettingsException, "The JIT-based model builder cannot be used on your system."); STORM_LOG_INFO("The JIT-based model builder seems to be working."); } return builder.build(); } else { std::shared_ptr> generator; if (model.isPrismProgram()) { generator = std::make_shared>(model.asPrismProgram(), options); } else if (model.isJaniModel()) { generator = std::make_shared>(model.asJaniModel(), options); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Cannot build sparse model from this symbolic model description."); } storm::builder::ExplicitModelBuilder builder(generator); return builder.build(); } } template std::shared_ptr> buildSymbolicModel(storm::storage::SymbolicModelDescription const& model, std::vector> const& formulas) { if (model.isPrismProgram()) { typename storm::builder::DdPrismModelBuilder::Options options; options = typename storm::builder::DdPrismModelBuilder::Options(formulas); storm::builder::DdPrismModelBuilder builder; return builder.build(model.asPrismProgram(), options); } else { STORM_LOG_THROW(model.isJaniModel(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model for the given symbolic model description."); typename storm::builder::DdJaniModelBuilder::Options options; options = typename storm::builder::DdJaniModelBuilder::Options(formulas); storm::builder::DdJaniModelBuilder builder; return builder.build(model.asJaniModel(), options); } } template std::shared_ptr performDeterministicSparseBisimulationMinimization(std::shared_ptr model, std::vector> const& formulas, storm::storage::BisimulationType type) { STORM_LOG_INFO("Performing bisimulation minimization... "); typename storm::storage::DeterministicModelBisimulationDecomposition::Options options; if (!formulas.empty()) { options = typename storm::storage::DeterministicModelBisimulationDecomposition::Options(*model, formulas); } options.setType(type); storm::storage::DeterministicModelBisimulationDecomposition bisimulationDecomposition(*model, options); bisimulationDecomposition.computeBisimulationDecomposition(); model = bisimulationDecomposition.getQuotient(); STORM_LOG_INFO("Bisimulation done, quotient model has " << model->getNumberOfStates() << " states and " << model->getNumberOfTransitions() << " transitions."); return model; } template std::shared_ptr performNondeterministicSparseBisimulationMinimization(std::shared_ptr model, std::vector> const& formulas, storm::storage::BisimulationType type) { STORM_LOG_INFO("Performing bisimulation minimization... "); typename storm::storage::DeterministicModelBisimulationDecomposition::Options options; if (!formulas.empty()) { options = typename storm::storage::NondeterministicModelBisimulationDecomposition::Options(*model, formulas); } options.setType(type); storm::storage::NondeterministicModelBisimulationDecomposition bisimulationDecomposition(*model, options); bisimulationDecomposition.computeBisimulationDecomposition(); model = bisimulationDecomposition.getQuotient(); STORM_LOG_INFO("Bisimulation done, quotient model has " << model->getNumberOfStates() << " states and " << model->getNumberOfTransitions() << " transitions."); return model; } template std::shared_ptr> performBisimulationMinimization(std::shared_ptr> const& model, std::vector> const& formulas, storm::storage::BisimulationType type) { using ValueType = typename ModelType::ValueType; STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Dtmc) || model->isOfType(storm::models::ModelType::Ctmc) || model->isOfType(storm::models::ModelType::Mdp), storm::exceptions::InvalidSettingsException, "Bisimulation minimization is currently only available for DTMCs, CTMCs and MDPs."); model->reduceToStateBasedRewards(); if (model->isOfType(storm::models::ModelType::Dtmc)) { return performDeterministicSparseBisimulationMinimization>(model->template as>(), formulas, type); } else if (model->isOfType(storm::models::ModelType::Ctmc)) { return performDeterministicSparseBisimulationMinimization>(model->template as>(), formulas, type); } else { return performNondeterministicSparseBisimulationMinimization>(model->template as>(), formulas, type); } } template std::shared_ptr> performBisimulationMinimization(std::shared_ptr> const& model, std::shared_ptr const& formula, storm::storage::BisimulationType type) { std::vector> formulas = { formula }; return performBisimulationMinimization(model, formulas , type); } template std::shared_ptr preprocessModel(std::shared_ptr model, std::vector> const& formulas) { storm::utility::Stopwatch preprocessingWatch(true); bool operationPerformed = false; if (model->getType() == storm::models::ModelType::MarkovAutomaton && model->isSparseModel()) { operationPerformed = true; std::shared_ptr> ma = model->template as>(); ma->close(); if (ma->hasOnlyTrivialNondeterminism()) { // Markov automaton can be converted into CTMC. STORM_PRINT_AND_LOG(std::endl << "Converting deterministic MA to a CTMC..." << std::endl); model = ma->convertToCTMC(); } } if (model->isSparseModel() && storm::settings::getModule().isBisimulationSet()) { operationPerformed = true; storm::storage::BisimulationType bisimType = storm::storage::BisimulationType::Strong; if (storm::settings::getModule().isWeakBisimulationSet()) { bisimType = storm::storage::BisimulationType::Weak; } STORM_LOG_THROW(model->isSparseModel(), storm::exceptions::InvalidSettingsException, "Bisimulation minimization is currently only available for sparse models."); model = performBisimulationMinimization(model->template as>(), formulas, bisimType); STORM_LOG_INFO("Quotient model has " << model->getNumberOfStates() << " states and " << model->getNumberOfTransitions() << " transitions."); } preprocessingWatch.stop(); if (operationPerformed) { STORM_PRINT_AND_LOG(std::endl << "Time for model preprocessing: " << preprocessingWatch << "." << std::endl << std::endl); } return model; } template void generateCounterexample(storm::storage::SymbolicModelDescription const& model, std::shared_ptr> markovModel, std::shared_ptr const& formula) { if (storm::settings::getModule().isMinimalCommandSetGenerationSet()) { STORM_LOG_THROW(model.isPrismProgram(), storm::exceptions::InvalidTypeException, "Minimal command set generation is only available for PRISM models."); STORM_LOG_THROW(markovModel->getType() == storm::models::ModelType::Mdp, storm::exceptions::InvalidTypeException, "Minimal command set generation is only available for MDPs."); storm::prism::Program const& program = model.asPrismProgram(); std::shared_ptr> mdp = markovModel->template as>(); // Determine whether we are required to use the MILP-version or the SAT-version. bool useMILP = storm::settings::getModule().isUseMilpBasedMinimalCommandSetGenerationSet(); if (useMILP) { storm::counterexamples::MILPMinimalCommandSetGenerator::computeCounterexample(program, *mdp, formula); } else { storm::counterexamples::SMTMinimalCommandSetGenerator::computeCounterexample(program, storm::settings::getModule().getConstantDefinitionString(), *mdp, formula); } } else { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "No suitable counterexample representation selected."); } } #ifdef STORM_HAVE_CARL template<> inline void generateCounterexample(storm::storage::SymbolicModelDescription const&, std::shared_ptr>, std::shared_ptr const& ) { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unable to generate counterexample for exact arithmetic model."); } template<> inline void generateCounterexample(storm::storage::SymbolicModelDescription const&, std::shared_ptr>, std::shared_ptr const& ) { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unable to generate counterexample for parametric model."); } #endif template void generateCounterexamples(storm::storage::SymbolicModelDescription const& model, std::shared_ptr> markovModel, std::vector> const& formulas) { for (auto const& formula : formulas) { generateCounterexample(model, markovModel, formula); } } template inline void performParameterLifting(std::shared_ptr>, std::shared_ptr const&) { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unable to perform parameterLifting for non-parametric model."); } #ifdef STORM_HAVE_CARL template<> inline void performParameterLifting(std::shared_ptr> markovModel, std::shared_ptr const& formula) { storm::utility::Stopwatch parameterLiftingStopWatch(true); std::shared_ptr consideredFormula = formula; STORM_LOG_WARN_COND(storm::utility::parameterlifting::validateParameterLiftingSound(markovModel, formula), "Could not validate whether parameter lifting is sound on the input model and the formula " << *formula); if (markovModel->isOfType(storm::models::ModelType::Ctmc) || markovModel->isOfType(storm::models::ModelType::MarkovAutomaton)) { STORM_PRINT_AND_LOG("Transforming continuous model to discrete model..."); storm::transformer::transformContinuousToDiscreteModelInPlace(markovModel, consideredFormula); STORM_PRINT_AND_LOG(" done!" << std::endl); markovModel->printModelInformationToStream(std::cout); } auto modelParameters = storm::models::sparse::getProbabilityParameters(*markovModel); auto rewParameters = storm::models::sparse::getRewardParameters(*markovModel); modelParameters.insert(rewParameters.begin(), rewParameters.end()); STORM_LOG_THROW(storm::settings::getModule().isParameterSpaceSet(), storm::exceptions::InvalidSettingsException, "Invoked Parameter lifting but no parameter space was defined."); auto parameterSpaceAsString = storm::settings::getModule().getParameterSpace(); auto parameterSpace = storm::storage::ParameterRegion::parseRegion(parameterSpaceAsString, modelParameters); auto refinementThreshold = storm::utility::convertNumber::CoefficientType>(storm::settings::getModule().getRefinementThreshold()); std::vector, storm::modelchecker::parametric::RegionCheckResult>> result; STORM_PRINT_AND_LOG("Performing parameter lifting for property " << *consideredFormula << " with parameter space " << parameterSpace.toString(true) << " and refinement threshold " << storm::utility::convertNumber(refinementThreshold) << " ..." << std::endl); storm::modelchecker::CheckTask task(*consideredFormula, true); std::string resultVisualization; if (markovModel->isOfType(storm::models::ModelType::Dtmc)) { if (storm::settings::getModule().isExactSet()) { storm::modelchecker::parametric::SparseDtmcRegionChecker , storm::RationalNumber> regionChecker(*markovModel->template as>()); regionChecker.specifyFormula(task); result = regionChecker.performRegionRefinement(parameterSpace, refinementThreshold); parameterLiftingStopWatch.stop(); if (modelParameters.size() == 2) { resultVisualization = regionChecker.visualizeResult(result, parameterSpace, *modelParameters.begin(), *(modelParameters.rbegin())); } } else { storm::modelchecker::parametric::SparseDtmcRegionChecker , double, storm::RationalNumber> regionChecker(*markovModel->template as>()); regionChecker.specifyFormula(task); result = regionChecker.performRegionRefinement(parameterSpace, refinementThreshold); parameterLiftingStopWatch.stop(); if (modelParameters.size() == 2) { resultVisualization = regionChecker.visualizeResult(result, parameterSpace, *modelParameters.begin(), *(modelParameters.rbegin())); } } } else if (markovModel->isOfType(storm::models::ModelType::Mdp)) { if (storm::settings::getModule().isExactSet()) { storm::modelchecker::parametric::SparseMdpRegionChecker, storm::RationalNumber> regionChecker(*markovModel->template as>()); regionChecker.specifyFormula(task); result = regionChecker.performRegionRefinement(parameterSpace, refinementThreshold); parameterLiftingStopWatch.stop(); if (modelParameters.size() == 2) { resultVisualization = regionChecker.visualizeResult(result, parameterSpace, *modelParameters.begin(), *(modelParameters.rbegin())); } } else { storm::modelchecker::parametric::SparseMdpRegionChecker, double, storm::RationalNumber> regionChecker(*markovModel->template as>()); regionChecker.specifyFormula(task); result = regionChecker.performRegionRefinement(parameterSpace, refinementThreshold); parameterLiftingStopWatch.stop(); if (modelParameters.size() == 2) { resultVisualization = regionChecker.visualizeResult(result, parameterSpace, *modelParameters.begin(), *(modelParameters.rbegin())); } } } else { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unable to perform parameterLifting on the provided model type."); } auto satArea = storm::utility::zero::CoefficientType>(); auto unsatArea = storm::utility::zero::CoefficientType>(); uint_fast64_t numOfSatRegions = 0; uint_fast64_t numOfUnsatRegions = 0; for (auto const& res : result) { switch (res.second) { case storm::modelchecker::parametric::RegionCheckResult::AllSat: satArea += res.first.area(); ++numOfSatRegions; break; case storm::modelchecker::parametric::RegionCheckResult::AllViolated: unsatArea += res.first.area(); ++numOfUnsatRegions; break; default: STORM_LOG_ERROR("Unexpected result for region " << res.first.toString(true) << " : " << res.second << "."); break; } } typename storm::storage::ParameterRegion::CoefficientType satAreaFraction = satArea / parameterSpace.area(); typename storm::storage::ParameterRegion::CoefficientType unsatAreaFraction = unsatArea / parameterSpace.area(); STORM_PRINT_AND_LOG("Done! Found " << numOfSatRegions << " safe regions and " << numOfUnsatRegions << " unsafe regions." << std::endl); STORM_PRINT_AND_LOG(storm::utility::convertNumber(satAreaFraction) * 100 << "% of the parameter space is safe, and " << storm::utility::convertNumber(unsatAreaFraction) * 100 << "% of the parameter space is unsafe." << std::endl); STORM_PRINT_AND_LOG("Model checking with parameter lifting took " << parameterLiftingStopWatch << " seconds." << std::endl); STORM_PRINT_AND_LOG(resultVisualization); if (storm::settings::getModule().exportResultToFile()) { std::string path = storm::settings::getModule().exportResultPath(); STORM_PRINT_AND_LOG("Exporting result to path " << path << "." << std::endl); std::ofstream filestream; storm::utility::openFile(path, filestream); for (auto const& res : result) { switch (res.second) { case storm::modelchecker::parametric::RegionCheckResult::AllSat: filestream << "safe: " << res.first.toString(true) << std::endl; break; case storm::modelchecker::parametric::RegionCheckResult::AllViolated: filestream << "unsafe: " << res.first.toString(true) << std::endl; break; default: break; } } } } #endif template inline void performParameterLifting(std::shared_ptr> markovModel, std::vector> const& formulas) { for (auto const& formula : formulas) { performParameterLifting(markovModel, formula); } } template std::unique_ptr verifyModel(std::shared_ptr model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant) { switch(storm::settings::getModule().getEngine()) { case storm::settings::modules::CoreSettings::Engine::Sparse: { std::shared_ptr> sparseModel = model->template as>(); STORM_LOG_THROW(sparseModel != nullptr, storm::exceptions::InvalidArgumentException, "Sparse engine requires a sparse input model."); return (sparseModel, formula, onlyInitialStatesRelevant); } case storm::settings::modules::CoreSettings::Engine::Hybrid: { std::shared_ptr> ddModel = model->template as>(); STORM_LOG_THROW(ddModel != nullptr, storm::exceptions::InvalidArgumentException, "Hybrid engine requires a DD-based input model."); return verifySymbolicModelWithHybridEngine(ddModel, formula, onlyInitialStatesRelevant); } case storm::settings::modules::CoreSettings::Engine::Dd: { std::shared_ptr> ddModel = model->template as>(); STORM_LOG_THROW(ddModel != nullptr, storm::exceptions::InvalidArgumentException, "Dd engine requires a DD-based input model."); return verifySymbolicModelWithDdEngine(ddModel, formula, onlyInitialStatesRelevant); } default: { STORM_LOG_ASSERT(false, "This position should not be reached, as at this point no model has been built."); } } } template std::unique_ptr verifySparseDtmc(std::shared_ptr> dtmc, storm::modelchecker::CheckTask const& task) { std::unique_ptr result; if (storm::settings::getModule().getEquationSolver() == storm::solver::EquationSolverType::Elimination && storm::settings::getModule().isUseDedicatedModelCheckerSet()) { storm::modelchecker::SparseDtmcEliminationModelChecker> modelchecker(*dtmc); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The property " << task.getFormula() << " is not supported by the dedicated elimination model checker."); } } else { storm::modelchecker::SparseDtmcPrctlModelChecker> modelchecker(*dtmc); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The property " << task.getFormula() << " is not supported."); } } return result; } template std::unique_ptr verifySparseCtmc(std::shared_ptr> ctmc, storm::modelchecker::CheckTask const& task) { std::unique_ptr result; storm::modelchecker::SparseCtmcCslModelChecker> modelchecker(*ctmc); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The property " << task.getFormula() << " is not supported."); } return result; } template std::unique_ptr verifySparseMdp(std::shared_ptr> mdp, storm::modelchecker::CheckTask const& task) { std::unique_ptr result; storm::modelchecker::SparseMdpPrctlModelChecker> modelchecker(*mdp); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The property " << task.getFormula() << " is not supported."); } return result; } template std::unique_ptr verifySparseMarkovAutomaton(std::shared_ptr> ma, storm::modelchecker::CheckTask const& task) { std::unique_ptr result; // Close the MA, if it is not already closed. if (!ma->isClosed()) { ma->close(); } storm::modelchecker::SparseMarkovAutomatonCslModelChecker> modelchecker(*ma); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The property " << task.getFormula() << " is not supported."); } return result; } template std::unique_ptr verifySparseModel(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant = false) { storm::modelchecker::CheckTask task(*formula, onlyInitialStatesRelevant); std::unique_ptr result; if (model->getType() == storm::models::ModelType::Dtmc) { result = verifySparseDtmc(model->template as>(), task); } else if (model->getType() == storm::models::ModelType::Mdp) { result = verifySparseMdp(model->template as>(), task); } else if (model->getType() == storm::models::ModelType::Ctmc) { result = verifySparseCtmc(model->template as>(), task); } else if (model->getType() == storm::models::ModelType::MarkovAutomaton) { result = verifySparseMarkovAutomaton(model->template as>(), task); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The model type " << model->getType() << " is not supported."); } return result; } #ifdef STORM_HAVE_CARL template<> inline std::unique_ptr verifySparseModel(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant) { storm::modelchecker::CheckTask task(*formula, onlyInitialStatesRelevant); std::unique_ptr result; if (model->getType() == storm::models::ModelType::Dtmc) { result = verifySparseDtmc(model->template as>(), task); } else if (model->getType() == storm::models::ModelType::Ctmc) { result = verifySparseCtmc(model->template as>(), task); } else if (model->getType() == storm::models::ModelType::Mdp) { result = verifySparseMdp(model->template as>(), task); } else if (model->getType() == storm::models::ModelType::MarkovAutomaton) { result = verifySparseMarkovAutomaton(model->template as>(), task); } else { STORM_LOG_ASSERT(false, "Illegal model type."); } return result; } inline void exportParametricResultToFile(storm::RationalFunction const& result, storm::analysis::ConstraintCollector const& constraintCollector, std::string const& path) { std::ofstream filestream; storm::utility::openFile(path, filestream); filestream << "!Parameters: "; std::set vars = result.gatherVariables(); std::copy(vars.begin(), vars.end(), std::ostream_iterator(filestream, "; ")); filestream << std::endl; filestream << "!Result: " << result << std::endl; filestream << "!Well-formed Constraints: " << std::endl; std::vector stringConstraints; std::transform(constraintCollector.getWellformedConstraints().begin(), constraintCollector.getWellformedConstraints().end(), std::back_inserter(stringConstraints), [](carl::Formula const& c) -> std::string { return c.toString();}); std::copy(stringConstraints.begin(), stringConstraints.end(), std::ostream_iterator(filestream, "\n")); filestream << "!Graph-preserving Constraints: " << std::endl; stringConstraints.clear(); std::transform(constraintCollector.getGraphPreservingConstraints().begin(), constraintCollector.getGraphPreservingConstraints().end(), std::back_inserter(stringConstraints), [](carl::Formula const& c) -> std::string { return c.toString();}); std::copy(stringConstraints.begin(), stringConstraints.end(), std::ostream_iterator(filestream, "\n")); storm::utility::closeFile(filestream); } template<> inline std::unique_ptr verifySparseModel(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant) { storm::modelchecker::CheckTask task(*formula, onlyInitialStatesRelevant); std::unique_ptr result; if (model->getType() == storm::models::ModelType::Dtmc) { result = verifySparseDtmc(model->template as>(), task); } else if (model->getType() == storm::models::ModelType::Mdp) { //std::shared_ptr> mdp = model->template as>(); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The parametric engine currently does not support MDPs."); } else if (model->getType() == storm::models::ModelType::Ctmc) { result = verifySparseCtmc(model->template as>(), task); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The parametric engine currently does not support " << model->getType()); } return result; } #endif template std::unique_ptr verifySymbolicModelWithHybridEngine(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant = false) { std::unique_ptr result; storm::modelchecker::CheckTask task(*formula, onlyInitialStatesRelevant); if (model->getType() == storm::models::ModelType::Dtmc) { std::shared_ptr> dtmc = model->template as>(); storm::modelchecker::HybridDtmcPrctlModelChecker> modelchecker(*dtmc); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } } else if (model->getType() == storm::models::ModelType::Ctmc) { std::shared_ptr> ctmc = model->template as>(); storm::modelchecker::HybridCtmcCslModelChecker> modelchecker(*ctmc); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } } else if (model->getType() == storm::models::ModelType::Mdp) { std::shared_ptr> mdp = model->template as>(); storm::modelchecker::HybridMdpPrctlModelChecker> modelchecker(*mdp); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } } else { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This functionality is not yet implemented."); } return result; } template std::unique_ptr verifySymbolicModelWithHybridEngine(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant = false) { std::unique_ptr result; storm::modelchecker::CheckTask task(*formula, onlyInitialStatesRelevant); STORM_LOG_THROW(model->getType() == storm::models::ModelType::Dtmc, storm::exceptions::NotSupportedException, "Only DTMCs are supported by this engine (in parametric mode)."); std::shared_ptr> dtmc = model->template as>(); if (storm::settings::getModule().getEquationSolver() == storm::solver::EquationSolverType::Elimination && storm::settings::getModule().isUseDedicatedModelCheckerSet()) { storm::transformer::SymbolicDtmcToSparseDtmcTransformer transformer; std::shared_ptr> sparseDtmc = transformer.translate(*dtmc); // Optimally, we could preprocess the model here and apply, for example, bisimulation minimization. However, // with the current structure of functions in storm.h and entrypoints.h this is not possible, because later // the filters will be applied wrt. to states of the original model, which is problematic. // sparseDtmc = preprocessModel>(sparseDtmc, {formula})->template as>(); storm::modelchecker::SparseDtmcEliminationModelChecker> modelchecker(*sparseDtmc); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); // Now translate the sparse result to hybrid one, so it can be filtered with the symbolic initial states of the model later. if (result->isQualitative()) { storm::modelchecker::ExplicitQualitativeCheckResult const& explicitResult = result->asExplicitQualitativeCheckResult(); if (explicitResult.isResultForAllStates()) { result = std::make_unique>(model->getReachableStates(), storm::dd::Bdd::fromVector(model->getManager(), explicitResult.getTruthValuesVector(), transformer.getOdd(), model->getRowVariables())); } else { storm::dd::Odd oldOdd = transformer.getOdd(); storm::dd::Odd newOdd = model->getInitialStates().createOdd(); storm::storage::BitVector tmp(oldOdd.getTotalOffset()); for (auto const& entry : explicitResult.getTruthValuesMap()) { tmp.set(entry.first, entry.second); } result = std::make_unique>(model->getReachableStates(), storm::dd::Bdd::fromVector(model->getManager(), tmp, oldOdd, model->getRowVariables())); } } else if (result->isQuantitative()) { storm::modelchecker::ExplicitQuantitativeCheckResult const& explicitResult = result->asExplicitQuantitativeCheckResult(); if (explicitResult.isResultForAllStates()) { result = std::make_unique>(model->getReachableStates(), model->getManager().getBddZero(), model->getManager().template getAddZero(), model->getReachableStates(), transformer.getOdd(), explicitResult.getValueVector()); } else { storm::dd::Odd oldOdd = transformer.getOdd(); storm::dd::Odd newOdd = model->getInitialStates().createOdd(); std::vector tmp(oldOdd.getTotalOffset(), storm::utility::zero()); for (auto const& entry : explicitResult.getValueMap()) { tmp[entry.first] = entry.second; } std::vector newValues = model->getInitialStates().filterExplicitVector(oldOdd, tmp); result = std::make_unique>(model->getReachableStates(), model->getManager().getBddZero(), model->getManager().template getAddZero(), model->getInitialStates(), newOdd, newValues); } } } } else { storm::modelchecker::HybridDtmcPrctlModelChecker> modelchecker(*dtmc); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } } return result; } template std::unique_ptr verifySymbolicModelWithDdEngine(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant) { std::unique_ptr result; storm::modelchecker::CheckTask task(*formula, onlyInitialStatesRelevant); if (model->getType() == storm::models::ModelType::Dtmc) { std::shared_ptr> dtmc = model->template as>(); storm::modelchecker::SymbolicDtmcPrctlModelChecker> modelchecker(*dtmc); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } } else if (model->getType() == storm::models::ModelType::Mdp) { std::shared_ptr> mdp = model->template as>(); storm::modelchecker::SymbolicMdpPrctlModelChecker> modelchecker(*mdp); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } } else { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This functionality is not yet implemented."); } return result; } template std::unique_ptr verifySymbolicModelWithDdEngine(std::shared_ptr> model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant) { std::unique_ptr result; storm::modelchecker::CheckTask task(*formula, onlyInitialStatesRelevant); STORM_LOG_THROW(model->getType() == storm::models::ModelType::Dtmc, storm::exceptions::NotSupportedException, "Only DTMCs are supported by this engine (in parametric mode)."); std::shared_ptr> dtmc = model->template as>(); storm::modelchecker::SymbolicDtmcPrctlModelChecker> modelchecker(*dtmc); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } return result; } template std::unique_ptr verifySymbolicModelWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& formula, bool onlyInitialStatesRelevant = false) { STORM_LOG_THROW(model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::DTMC || model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::MDP, storm::exceptions::InvalidSettingsException, "Can only treat DTMCs/MDPs using the abstraction refinement engine."); if (model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::DTMC) { storm::modelchecker::GameBasedMdpModelChecker> modelchecker(model); storm::modelchecker::CheckTask task(*formula, onlyInitialStatesRelevant); return modelchecker.check(task); } else { storm::modelchecker::GameBasedMdpModelChecker> modelchecker(model); storm::modelchecker::CheckTask task(*formula, onlyInitialStatesRelevant); return modelchecker.check(task); } } /** * */ void exportJaniModel(storm::jani::Model const& model, std::vector const& properties, std::string const& filepath); template void exportMatrixToFile(std::shared_ptr> model, std::string const& filepath) { STORM_LOG_THROW(model->getType() != storm::models::ModelType::Ctmc, storm::exceptions::NotImplementedException, "This functionality is not yet implemented." ); std::ofstream stream; storm::utility::openFile(filepath, stream); model->getTransitionMatrix().printAsMatlabMatrix(stream); storm::utility::closeFile(stream); } } #endif /* STORM_H */