#ifndef STORM_H #define STORM_H #include #include #include #include #include #include #include #include "initialize.h" #include "storm-config.h" // Headers that provide auxiliary functionality. #include "src/settings/SettingsManager.h" #include "src/settings/modules/CoreSettings.h" #include "src/settings/modules/IOSettings.h" #include "src/settings/modules/BisimulationSettings.h" #include "src/settings/modules/ParametricSettings.h" #include "src/settings/modules/EliminationSettings.h" #include "src/settings/modules/CoreSettings.h" // Formula headers. #include "src/logic/Formulas.h" #include "src/logic/FragmentSpecification.h" // Model headers. #include "src/models/ModelBase.h" #include "src/models/sparse/Model.h" #include "src/models/sparse/StandardRewardModel.h" #include "src/models/sparse/MarkovAutomaton.h" #include "src/models/symbolic/Model.h" #include "src/models/symbolic/StandardRewardModel.h" #include "src/storage/dd/Add.h" #include "src/storage/dd/Bdd.h" #include "src/parser/AutoParser.h" #include "src/storage/jani/Model.h" // Headers of builders. #include "src/builder/ExplicitModelBuilder.h" #include "src/builder/DdPrismModelBuilder.h" // Headers for model processing. #include "src/storage/bisimulation/DeterministicModelBisimulationDecomposition.h" #include "src/storage/bisimulation/NondeterministicModelBisimulationDecomposition.h" #include "src/storage/ModelFormulasPair.h" // Headers for model checking. #include "src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" #include "src/modelchecker/prctl/SparseMdpPrctlModelChecker.h" #include "src/modelchecker/prctl/HybridDtmcPrctlModelChecker.h" #include "src/modelchecker/prctl/HybridMdpPrctlModelChecker.h" #include "src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h" #include "src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h" #include "src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h" #include "src/modelchecker/exploration/SparseExplorationModelChecker.h" #include "src/modelchecker/csl/SparseCtmcCslModelChecker.h" #include "src/modelchecker/csl/helper/SparseCtmcCslHelper.h" #include "src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h" #include "src/modelchecker/csl/HybridCtmcCslModelChecker.h" #include "src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h" #include "src/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "src/modelchecker/results/SymbolicQualitativeCheckResult.h" // Headers for counterexample generation. #include "src/counterexamples/MILPMinimalLabelSetGenerator.h" #include "src/counterexamples/SMTMinimalCommandSetGenerator.h" // Headers related to PRISM model building. #include "src/generator/PrismNextStateGenerator.h" #include "src/utility/prism.h" // Headers related to exception handling. #include "src/exceptions/InvalidStateException.h" #include "src/exceptions/InvalidArgumentException.h" #include "src/exceptions/InvalidSettingsException.h" #include "src/exceptions/InvalidTypeException.h" #include "src/exceptions/NotImplementedException.h" #include "src/exceptions/NotSupportedException.h" namespace storm { template std::shared_ptr> buildExplicitModel(std::string const& transitionsFile, std::string const& labelingFile, boost::optional const& stateRewardsFile = boost::none, boost::optional const& transitionRewardsFile = boost::none, boost::optional const& choiceLabelingFile = boost::none) { return storm::parser::AutoParser<>::parseModel(transitionsFile, labelingFile, stateRewardsFile ? stateRewardsFile.get() : "", transitionRewardsFile ? transitionRewardsFile.get() : "", choiceLabelingFile ? choiceLabelingFile.get() : "" ); } storm::jani::Model parseModel(std::string const& path); storm::prism::Program parseProgram(std::string const& path); std::vector> parseFormulasForExplicit(std::string const& inputString); std::vector> parseFormulasForProgram(std::string const& inputString, storm::prism::Program const& program); template std::shared_ptr> buildSparseModel(storm::prism::Program const& program, std::vector> const& formulas, bool onlyInitialStatesRelevant = false) { storm::generator::NextStateGeneratorOptions options(formulas); // Generate command labels if we are going to build a counterexample later. if (storm::settings::getModule().isMinimalCommandSetGenerationSet()) { options.setBuildChoiceLabels(true); } std::shared_ptr> generator = std::make_shared>(program, options); storm::builder::ExplicitModelBuilder builder(generator); return builder.build(); } template std::shared_ptr> buildSymbolicModel(storm::prism::Program const& program, std::vector> const& formulas) { typename storm::builder::DdPrismModelBuilder::Options options; options = typename storm::builder::DdPrismModelBuilder::Options(formulas); storm::builder::DdPrismModelBuilder builder; return builder.build(program, 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. "); 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."); 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) { if(model->getType() == storm::models::ModelType::MarkovAutomaton && model->isSparseModel()) { std::shared_ptr> ma = model->template as>(); if (ma->hasOnlyTrivialNondeterminism()) { // Markov automaton can be converted into CTMC model = ma->convertToCTMC(); } } if (model->isSparseModel() && storm::settings::getModule().isBisimulationSet()) { 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."); return performBisimulationMinimization(model->template as>(), formulas, bisimType); } return model; } template void generateCounterexample(storm::prism::Program const& program, std::shared_ptr> model, std::shared_ptr const& formula) { if (storm::settings::getModule().isMinimalCommandSetGenerationSet()) { STORM_LOG_THROW(model->getType() == storm::models::ModelType::Mdp, storm::exceptions::InvalidTypeException, "Minimal command set generation is only available for MDPs."); STORM_LOG_THROW(storm::settings::getModule().isSymbolicSet(), storm::exceptions::InvalidSettingsException, "Minimal command set generation is only available for symbolic models."); std::shared_ptr> mdp = model->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::MILPMinimalLabelSetGenerator::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."); } } template<> inline void generateCounterexample(storm::prism::Program const& program, std::shared_ptr> model, std::shared_ptr const& formula) { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unable to generate counterexample for parametric model."); } template<> inline void generateCounterexample(storm::prism::Program const& program, std::shared_ptr> model, std::shared_ptr const& formula) { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unable to generate counterexample for parametric model."); } template void generateCounterexamples(storm::prism::Program const& program, std::shared_ptr> model, std::vector> const& formulas) { for (auto const& formula : formulas) { generateCounterexample(program, model, 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 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 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 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) { std::shared_ptr> ma = model->template as>(); // Close the MA, if it is not already closed. if (!ma->isClosed()) { ma->close(); } storm::modelchecker::SparseMarkovAutomatonCslModelChecker> modelchecker(*ma); result = modelchecker.check(task); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The model type " << model->getType() << " is not supported."); } return result; } 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 { STORM_LOG_ASSERT(false, "Illegal model type."); } return result; } #ifdef STORM_HAVE_CARL inline void exportParametricResultToFile(storm::RationalFunction const& result, storm::models::sparse::Dtmc::ConstraintCollector const& constraintCollector, std::string const& path) { std::ofstream filestream; filestream.open(path); // TODO: add checks. 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::copy(constraintCollector.getWellformedConstraints().begin(), constraintCollector.getWellformedConstraints().end(), std::ostream_iterator>(filestream, "\n")); filestream << "!Graph-preserving Constraints: " << std::endl; std::copy(constraintCollector.getGraphPreservingConstraints().begin(), constraintCollector.getGraphPreservingConstraints().end(), std::ostream_iterator>(filestream, "\n")); filestream.close(); } 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) { 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 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 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 ofs; ofs.open (filepath, std::ofstream::out); model->getTransitionMatrix().printAsMatlabMatrix(ofs); ofs.close(); } } #endif /* STORM_H */