diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bd0f67e7f..e9059930d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,6 +9,9 @@ add_subdirectory(storm-gspn) add_subdirectory(storm-gspn-cli) add_subdirectory(storm-dft) add_subdirectory(storm-dft-cli) +add_subdirectory(storm-pars) +add_subdirectory(storm-pars-cli) + add_subdirectory(test) -set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) \ No newline at end of file +set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) diff --git a/src/storm-pars-cli/CMakeLists.txt b/src/storm-pars-cli/CMakeLists.txt new file mode 100644 index 000000000..9cd155e35 --- /dev/null +++ b/src/storm-pars-cli/CMakeLists.txt @@ -0,0 +1,7 @@ +# Create storm-pars. +add_executable(storm-pars-cli ${PROJECT_SOURCE_DIR}/src/storm-pars-cli/storm-pars.cpp) +target_link_libraries(storm-pars-cli storm-pars) # Adding headers for xcode +set_target_properties(storm-pars-cli PROPERTIES OUTPUT_NAME "storm-pars") + +# installation +install(TARGETS storm-pars-cli RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp new file mode 100644 index 000000000..eba86792d --- /dev/null +++ b/src/storm-pars-cli/storm-pars.cpp @@ -0,0 +1,346 @@ + +#include "storm-pars/api/storm-pars.h" +#include "storm-pars/settings/ParsSettings.h" +#include "storm-pars/settings/modules/ParametricSettings.h" +#include "storm-pars/settings/modules/RegionSettings.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/api/storm.h" +#include "storm/cli/cli.h" +#include "storm/models/ModelBase.h" +#include "storm/storage/SymbolicModelDescription.h" +#include "storm/utility/file.h" +#include "storm/utility/initialize.h" +#include "storm/utility/Stopwatch.h" +#include "storm/utility/macros.h" + +#include "storm/settings/modules/GeneralSettings.h" +#include "storm/settings/modules/CoreSettings.h" +#include "storm/settings/modules/IOSettings.h" +#include "storm/settings/modules/BisimulationSettings.h" + +#include "storm/exceptions/BaseException.h" +#include "storm/exceptions/InvalidSettingsException.h" +#include "storm/exceptions/NotSupportedException.h" + +#include "storm/cli/cli.cpp" + +namespace storm { + namespace pars { + + typedef typename storm::cli::SymbolicInput SymbolicInput; + + template <typename ValueType> + std::shared_ptr<storm::models::ModelBase> buildModelSparse(SymbolicInput const& input, storm::settings::modules::IOSettings const& ioSettings) { + return storm::api::buildSparseModel<ValueType>(input.model.get(), storm::api::extractFormulasFromProperties(input.properties), ioSettings.isBuildChoiceLabelsSet()); + } + + template <storm::dd::DdType DdType, typename ValueType> + std::shared_ptr<storm::models::ModelBase> buildModel(storm::settings::modules::CoreSettings::Engine const& engine, SymbolicInput const& input, storm::settings::modules::IOSettings const& ioSettings) { + storm::utility::Stopwatch modelBuildingWatch(true); + + std::shared_ptr<storm::models::ModelBase> result; + if (input.model) { + if (engine == storm::settings::modules::CoreSettings::Engine::Dd || engine == storm::settings::modules::CoreSettings::Engine::Hybrid) { + result = storm::cli::buildModelDd<DdType, ValueType>(input); + } else if (engine == storm::settings::modules::CoreSettings::Engine::Sparse) { + result = storm::pars::buildModelSparse<ValueType>(input, ioSettings); + } + } else if (ioSettings.isExplicitSet() || ioSettings.isExplicitDRNSet()) { + STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Can only use sparse engine with explicit input."); + result = storm::cli::buildModelExplicit<ValueType>(ioSettings); + } + + modelBuildingWatch.stop(); + if (result) { + STORM_PRINT_AND_LOG("Time for model construction: " << modelBuildingWatch << "." << std::endl << std::endl); + } + + return result; + } + + + template <typename ValueType> + std::vector<storm::storage::ParameterRegion<ValueType>> parseRegions(std::shared_ptr<storm::models::ModelBase> const& model) { + std::vector<storm::storage::ParameterRegion<ValueType>> result; + auto regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>(); + if (regionSettings.isRegionSet()) { + result = storm::api::parseRegions<ValueType>(regionSettings.getRegionString(), *model); + } + return result; + } + + template <typename ValueType> + std::pair<std::shared_ptr<storm::models::ModelBase>, bool> preprocessSparseModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input) { + auto generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>(); + auto bisimulationSettings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>(); + auto parametricSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>(); + + std::pair<std::shared_ptr<storm::models::ModelBase>, bool> result = std::make_pair(model, false); + + if (result.first->isOfType(storm::models::ModelType::MarkovAutomaton)) { + result.first = storm::cli::preprocessSparseMarkovAutomaton(result.first->template as<storm::models::sparse::MarkovAutomaton<ValueType>>()); + result.second = true; + } + + if (generalSettings.isBisimulationSet()) { + result.first = storm::cli::preprocessSparseModelBisimulation(result.first->template as<storm::models::sparse::Model<ValueType>>(), input, bisimulationSettings); + result.second = true; + } + + if (parametricSettings.transformContinuousModel() && (result.first->isOfType(storm::models::ModelType::Ctmc) || result.first->isOfType(storm::models::ModelType::MarkovAutomaton))) { + result.first = storm::api::transformContinuousToDiscreteTimeSparseModel(std::move(*result.first->template as<storm::models::sparse::Model<ValueType>>()), storm::api::extractFormulasFromProperties(input.properties)); + result.second = true; + } + + return result; + } + + template <storm::dd::DdType DdType, typename ValueType> + std::pair<std::shared_ptr<storm::models::ModelBase>, bool> preprocessDdModel(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input) { + + std::pair<std::shared_ptr<storm::models::ModelBase>, bool> result = std::make_pair(model, false); + + auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>(); + if (coreSettings.getEngine() == storm::settings::modules::CoreSettings::Engine::Hybrid) { + // Currently, hybrid engine for parametric models just referrs to building the model symbolically. + STORM_LOG_INFO("Translating symbolic model to sparse model..."); + result.first = storm::api::transformSymbolicToSparseModel(model); + result.second = true; + // Invoke preprocessing on the sparse model + auto sparsePreprocessingResult = storm::pars::preprocessSparseModel<ValueType>(result.first->as<storm::models::sparse::Model<ValueType>>(), input); + if (sparsePreprocessingResult.second) { + result.first = sparsePreprocessingResult.first; + } + } + return result; + } + + template <storm::dd::DdType DdType, typename ValueType> + std::pair<std::shared_ptr<storm::models::ModelBase>, bool> preprocessModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) { + storm::utility::Stopwatch preprocessingWatch(true); + + std::pair<std::shared_ptr<storm::models::ModelBase>, bool> result = std::make_pair(model, false); + if (model->isSparseModel()) { + result = storm::pars::preprocessSparseModel<ValueType>(result.first->as<storm::models::sparse::Model<ValueType>>(), input); + } else { + STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type."); + result = storm::pars::preprocessDdModel<DdType, ValueType>(result.first->as<storm::models::symbolic::Model<DdType, ValueType>>(), input); + } + + if (result.second) { + STORM_PRINT_AND_LOG(std::endl << "Time for model preprocessing: " << preprocessingWatch << "." << std::endl << std::endl); + } + return result; + } + + template<typename ValueType> + void printInitialStatesResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::jani::Property const& property, storm::utility::Stopwatch* watch = nullptr) { + if (result) { + STORM_PRINT_AND_LOG("Result (initial states): " << std::endl); + + auto const* regionCheckResult = dynamic_cast<storm::modelchecker::RegionCheckResult<ValueType> const*>(result.get()); + if (regionCheckResult != nullptr) { + auto regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>(); + std::stringstream outStream; + if (regionSettings.isPrintFullResultSet()) { + regionCheckResult->writeToStream(outStream); + } else { + regionCheckResult->writeCondensedToStream(outStream); + } + outStream << std::endl; + if (!regionSettings.isPrintNoIllustrationSet()) { + auto const* regionRefinementCheckResult = dynamic_cast<storm::modelchecker::RegionRefinementCheckResult<ValueType> const*>(regionCheckResult); + if (regionRefinementCheckResult != nullptr) { + regionRefinementCheckResult->writeIllustrationToStream(outStream); + } + } + STORM_PRINT_AND_LOG(outStream.str()); + } else { + STORM_PRINT_AND_LOG(*result); + } + if (watch) { + STORM_PRINT_AND_LOG("Time for model checking: " << *watch << "." << std::endl); + } + } else { + STORM_PRINT_AND_LOG(" failed, property is unsupported by selected engine/settings." << std::endl); + } + } + + template<typename ValueType> + void verifyProperties(std::vector<storm::jani::Property> const& properties, std::function<std::unique_ptr<storm::modelchecker::CheckResult>(std::shared_ptr<storm::logic::Formula const> const& formula)> const& verificationCallback, std::function<void(std::unique_ptr<storm::modelchecker::CheckResult> const&)> const& postprocessingCallback) { + for (auto const& property : properties) { + storm::cli::printModelCheckingProperty(property); + storm::utility::Stopwatch watch(true); + std::unique_ptr<storm::modelchecker::CheckResult> result = verificationCallback(property.getRawFormula()); + watch.stop(); + printInitialStatesResult<ValueType>(result, property, &watch); + postprocessingCallback(result); + } + } + + template <typename ValueType> + void verifyPropertiesWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input) { + verifyProperties<ValueType>(input.properties, + [&model] (std::shared_ptr<storm::logic::Formula const> const& formula) { + std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithSparseEngine<ValueType>(model, storm::api::createTask<ValueType>(formula, true)); + result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates())); + return result; + }, + [&model] (std::unique_ptr<storm::modelchecker::CheckResult> const& result) { + auto parametricSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>(); + if (parametricSettings.exportResultToFile() && model->isOfType(storm::models::ModelType::Dtmc)) { + auto dtmc = model->template as<storm::models::sparse::Dtmc<ValueType>>(); + storm::api::exportParametricResultToFile(result->asExplicitQuantitativeCheckResult<ValueType>()[*model->getInitialStates().begin()],storm::analysis::ConstraintCollector<ValueType>(*dtmc), parametricSettings.exportResultPath()); + } + }); + } + + template <typename ValueType> + void verifyRegionsWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, std::vector<storm::storage::ParameterRegion<ValueType>> const& regions) { + STORM_LOG_ASSERT(!regions.empty(), "Can not analyze an empty set of regions."); + + auto parametricSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>(); + auto regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>(); + + std::function<std::unique_ptr<storm::modelchecker::CheckResult>(std::shared_ptr<storm::logic::Formula const> const& formula)> verificationCallback; + std::function<void(std::unique_ptr<storm::modelchecker::CheckResult> const&)> postprocessingCallback; + + if (regions.size() == 1) { + STORM_PRINT_AND_LOG(std::endl << "Analyzing parameter region " << regions.front()); + } else { + STORM_PRINT_AND_LOG(std::endl << "Analyzing " << regions.size() << " parameter regions"); + } + + auto engine = regionSettings.getRegionCheckEngine(); + STORM_PRINT_AND_LOG(" using " << engine); + + // Check the given set of regions with or without refinement + if (regionSettings.isRefineSet()) { + STORM_LOG_THROW(regions.size() == 1, storm::exceptions::NotSupportedException, "Region refinement is not supported for multiple initial regions."); + STORM_PRINT_AND_LOG(" with iterative refinement until " << (1.0 - regionSettings.getRefinementThreshold()) * 100.0 << "% is covered." << std::endl); + verificationCallback = [&] (std::shared_ptr<storm::logic::Formula const> const& formula) { + ValueType refinementThreshold = storm::utility::convertNumber<ValueType>(regionSettings.getRefinementThreshold()); + std::unique_ptr<storm::modelchecker::RegionRefinementCheckResult<ValueType>> result = storm::api::checkAndRefineRegionWithSparseEngine<ValueType>(model, storm::api::createTask<ValueType>(formula, true), regions.front(), refinementThreshold, engine); + return result; + }; + } else { + STORM_PRINT_AND_LOG("." << std::endl); + verificationCallback = [&] (std::shared_ptr<storm::logic::Formula const> const& formula) { + std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::checkRegionsWithSparseEngine<ValueType>(model, storm::api::createTask<ValueType>(formula, true), regions, engine); + return result; + }; + } + + postprocessingCallback = [&] (std::unique_ptr<storm::modelchecker::CheckResult> const& result) { + if (parametricSettings.exportResultToFile()) { + storm::api::exportRegionCheckResultToFile<ValueType>(result, parametricSettings.exportResultPath()); + } + }; + + verifyProperties<ValueType>(input.properties, verificationCallback, postprocessingCallback); + } + + template <typename ValueType> + void verifyWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, std::vector<storm::storage::ParameterRegion<ValueType>> const& regions) { + if (regions.empty()) { + storm::pars::verifyPropertiesWithSparseEngine(model, input); + } else { + storm::pars::verifyRegionsWithSparseEngine(model, input, regions); + } + } + + template <storm::dd::DdType DdType, typename ValueType> + void verifyParametricModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, std::vector<storm::storage::ParameterRegion<ValueType>> const& regions) { + STORM_LOG_ASSERT(model->isSparseModel(), "Unexpected model type."); + storm::pars::verifyWithSparseEngine<ValueType>(model->as<storm::models::sparse::Model<ValueType>>(), input, regions); + } + + template <storm::dd::DdType DdType, typename ValueType> + void processInputWithValueTypeAndDdlib(SymbolicInput& input) { + auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>(); + auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); + + auto engine = coreSettings.getEngine(); + STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse || engine == storm::settings::modules::CoreSettings::Engine::Hybrid || engine == storm::settings::modules::CoreSettings::Engine::Dd, storm::exceptions::InvalidSettingsException, "The selected engine is not supported for parametric models."); + + std::shared_ptr<storm::models::ModelBase> model; + if (!ioSettings.isNoBuildModelSet()) { + model = storm::pars::buildModel<DdType, ValueType>(engine, input, ioSettings); + } + + if (model) { + model->printModelInformationToStream(std::cout); + } + + STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model."); + + if (model) { + auto preprocessingResult = storm::pars::preprocessModel<DdType, ValueType>(model, input); + if (preprocessingResult.second) { + model = preprocessingResult.first; + model->printModelInformationToStream(std::cout); + } + } + + std::vector<storm::storage::ParameterRegion<ValueType>> regions = parseRegions<ValueType>(model); + + if (model) { + storm::cli::exportModel<DdType, ValueType>(model, input); + verifyParametricModel<DdType, ValueType>(model, input, regions); + } + } + + void processOptions() { + // Start by setting some urgent options (log levels, resources, etc.) + storm::cli::setUrgentOptions(); + + // Parse and preprocess symbolic input (PRISM, JANI, properties, etc.) + SymbolicInput symbolicInput = storm::cli::parseAndPreprocessSymbolicInput(); + + auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>(); + auto engine = coreSettings.getEngine(); + STORM_LOG_WARN_COND(engine != storm::settings::modules::CoreSettings::Engine::Dd || engine != storm::settings::modules::CoreSettings::Engine::Hybrid || coreSettings.getDdLibraryType() == storm::dd::DdType::Sylvan, "The selected DD library does not support parametric models. Switching to Sylvan..."); + + processInputWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, storm::RationalFunction>(symbolicInput); + } + + int64_t process(const int argc, const char** argv) { + storm::utility::setUp(); + storm::cli::printHeader("Storm-pars", argc, argv); + storm::settings::initializeParsSettings("Storm-pars", "storm-pars"); + + storm::utility::Stopwatch totalTimer(true); + if (!storm::cli::parseOptions(argc, argv)) { + return -1; + } + + processOptions(); + + totalTimer.stop(); + if (storm::settings::getModule<storm::settings::modules::ResourceSettings>().isPrintTimeAndMemorySet()) { + storm::cli::printTimeAndMemoryStatistics(totalTimer.getTimeInMilliseconds()); + } + + storm::utility::cleanUp(); + return 0; + } + } +} + + +/*! + * Main entry point of the executable storm-pars. + */ +int main(const int argc, const char** argv) { + + try { + return storm::pars::process(argc, argv); + } catch (storm::exceptions::BaseException const& exception) { + STORM_LOG_ERROR("An exception caused Storm-pars to terminate. The message of the exception is: " << exception.what()); + return 1; + } catch (std::exception const& exception) { + STORM_LOG_ERROR("An unexpected exception occurred and caused Storm-pars to terminate. The message of this exception is: " << exception.what()); + return 2; + } +} diff --git a/src/storm-pars/CMakeLists.txt b/src/storm-pars/CMakeLists.txt new file mode 100644 index 000000000..4e2ec1e0f --- /dev/null +++ b/src/storm-pars/CMakeLists.txt @@ -0,0 +1,40 @@ +file(GLOB_RECURSE ALL_FILES ${PROJECT_SOURCE_DIR}/src/storm-pars/*.h ${PROJECT_SOURCE_DIR}/src/storm-pars/*.cpp) + +register_source_groups_from_filestructure("${ALL_FILES}" storm-pars) + + + +file(GLOB_RECURSE STORM_PARS_SOURCES ${PROJECT_SOURCE_DIR}/src/storm-pars/*/*.cpp) +file(GLOB_RECURSE STORM_PARS_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-pars/*/*.h) + + +# Create storm-pars. +add_library(storm-pars SHARED ${STORM_PARS_SOURCES} ${STORM_PARS_HEADERS}) + +# Remove define symbol for shared libstorm. +set_target_properties(storm-pars PROPERTIES DEFINE_SYMBOL "") +#add_dependencies(storm resources) +list(APPEND STORM_TARGETS storm-pars) +set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) + +target_link_libraries(storm-pars PUBLIC storm ${STORM_PARS_LINK_LIBRARIES}) + +# Install storm headers to include directory. +foreach(HEADER ${STORM_PARS_HEADERS}) + string(REGEX REPLACE "${PROJECT_SOURCE_DIR}/src/?" "" RELATIVE_HEADER_PATH ${HEADER}) + string(REGEX MATCH "(.*)[/\\]" RELATIVE_DIRECTORY ${RELATIVE_HEADER_PATH}) + string(REGEX REPLACE "${RELATIVE_DIRECTORY}/?" "" HEADER_FILENAME ${RELATIVE_HEADER_PATH}) + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy ${HEADER} ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + DEPENDS ${HEADER} + ) + list(APPEND STORM_PARS_OUTPUT_HEADERS "${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME}") +endforeach() +add_custom_target(copy_storm_pars_headers DEPENDS ${STORM_PARS_OUTPUT_HEADERS} ${STORM_PARS_HEADERS}) +add_dependencies(storm-pars copy_storm_pars_headers) + +# installation +install(TARGETS storm-pars RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) + diff --git a/src/storm-pars/api/region.h b/src/storm-pars/api/region.h new file mode 100644 index 000000000..043f461b0 --- /dev/null +++ b/src/storm-pars/api/region.h @@ -0,0 +1,183 @@ +#pragma once + +#include <string> +#include <set> +#include <vector> +#include <memory> +#include <boost/optional.hpp> + +#include "storm-pars/modelchecker/results/RegionCheckResult.h" +#include "storm-pars/modelchecker/results/RegionRefinementCheckResult.h" +#include "storm-pars/modelchecker/region/RegionCheckEngine.h" +#include "storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h" +#include "storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.h" +#include "storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.h" +#include "storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.h" +#include "storm-pars/parser/ParameterRegionParser.h" +#include "storm-pars/storage/ParameterRegion.h" +#include "storm-pars/utility/parameterlifting.h" + +#include "storm/api/transformation.h" +#include "storm/utility/file.h" +#include "storm/models/sparse/Model.h" +#include "storm/exceptions/UnexpectedException.h" +#include "storm/exceptions/InvalidOperationException.h" +#include "storm/exceptions/NotSupportedException.h" + +namespace storm { + + namespace api { + + template <typename ValueType> + std::vector<storm::storage::ParameterRegion<ValueType>> parseRegions(std::string const& inputString, std::set<typename storm::storage::ParameterRegion<ValueType>::VariableType> const& consideredVariables) { + // If the given input string looks like a file (containing a dot and there exists a file with that name), + // we try to parse it as a file, otherwise we assume it's a region string. + if (inputString.find(".") != std::string::npos && std::ifstream(inputString).good()) { + return storm::parser::ParameterRegionParser<ValueType>().parseMultipleRegionsFromFile(inputString, consideredVariables); + } else { + return storm::parser::ParameterRegionParser<ValueType>().parseMultipleRegions(inputString, consideredVariables); + } + } + + template <typename ValueType> + std::vector<storm::storage::ParameterRegion<ValueType>> parseRegions(std::string const& inputString, storm::models::ModelBase const& model) { + std::set<typename storm::storage::ParameterRegion<ValueType>::VariableType> modelParameters; + if (model.isSparseModel()) { + auto const& sparseModel = dynamic_cast<storm::models::sparse::Model<ValueType> const&>(model); + modelParameters = storm::models::sparse::getProbabilityParameters(sparseModel); + auto rewParameters = storm::models::sparse::getRewardParameters(sparseModel); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Retrieving model parameters is not supported for the given model type."); + } + return parseRegions<ValueType>(inputString, modelParameters); + } + + template <typename ValueType> + storm::storage::ParameterRegion<ValueType> parseRegion(std::string const& inputString, std::set<typename storm::storage::ParameterRegion<ValueType>::VariableType> const& consideredVariables) { + // Handle the "empty region" case + if (inputString == "" && consideredVariables.empty()) { + return storm::storage::ParameterRegion<ValueType>(); + } + + auto res = parseRegions<ValueType>(inputString, consideredVariables); + STORM_LOG_THROW(res.size() == 1, storm::exceptions::InvalidOperationException, "Parsed " << res.size() << " regions but exactly one was expected."); + return res.front(); + } + + template <typename ValueType> + storm::storage::ParameterRegion<ValueType> parseRegion(std::string const& inputString, storm::models::ModelBase const& model) { + // Handle the "empty region" case + if (inputString == "" && !model.hasParameters()) { + return storm::storage::ParameterRegion<ValueType>(); + } + + auto res = parseRegions<ValueType>(inputString, model); + STORM_LOG_THROW(res.size() == 1, storm::exceptions::InvalidOperationException, "Parsed " << res.size() << " regions but exactly one was expected."); + return res.front(); + } + + template <typename ParametricType, typename ConstantType> + std::unique_ptr<storm::modelchecker::RegionModelChecker<ParametricType>> initializeParameterLiftingRegionModelChecker(std::shared_ptr<storm::models::sparse::Model<ParametricType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ParametricType> const& task) { + + STORM_LOG_WARN_COND(storm::utility::parameterlifting::validateParameterLiftingSound(*model, task.getFormula()), "Could not validate whether parameter lifting is applicable. Please validate manually..."); + + std::shared_ptr<storm::models::sparse::Model<ParametricType>> consideredModel = model; + + // Treat continuous time models + if (consideredModel->isOfType(storm::models::ModelType::Ctmc) || consideredModel->isOfType(storm::models::ModelType::MarkovAutomaton)) { + STORM_LOG_WARN("Parameter lifting not supported for continuous time models. Transforming continuous model to discrete model..."); + std::vector<std::shared_ptr<storm::logic::Formula const>> taskFormulaAsVector { task.getFormula().asSharedPointer() }; + consideredModel = storm::api::transformContinuousToDiscreteTimeSparseModel(consideredModel, taskFormulaAsVector); + STORM_LOG_THROW(consideredModel->isOfType(storm::models::ModelType::Dtmc) || consideredModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::UnexpectedException, "Transformation to discrete time model has failed."); + } + + // Obtain the region model checker + std::unique_ptr<storm::modelchecker::RegionModelChecker<ParametricType>> result; + if (consideredModel->isOfType(storm::models::ModelType::Dtmc)) { + result = std::make_unique<storm::modelchecker::SparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<ParametricType>, ConstantType>>(); + } else if (consideredModel->isOfType(storm::models::ModelType::Mdp)) { + result = std::make_unique<storm::modelchecker::SparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<ParametricType>, ConstantType>>(); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform parameterLifting on the provided model type."); + } + + result->specify(consideredModel, task); + + return result; + } + + template <typename ParametricType, typename ImpreciseType, typename PreciseType> + std::unique_ptr<storm::modelchecker::RegionModelChecker<ParametricType>> initializeValidatingRegionModelChecker(std::shared_ptr<storm::models::sparse::Model<ParametricType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ParametricType> const& task) { + + STORM_LOG_WARN_COND(storm::utility::parameterlifting::validateParameterLiftingSound(*model, task.getFormula()), "Could not validate whether parameter lifting is applicable. Please validate manually..."); + + std::shared_ptr<storm::models::sparse::Model<ParametricType>> consideredModel = model; + + // Treat continuous time models + if (consideredModel->isOfType(storm::models::ModelType::Ctmc) || consideredModel->isOfType(storm::models::ModelType::MarkovAutomaton)) { + STORM_LOG_WARN("Parameter lifting not supported for continuous time models. Transforming continuous model to discrete model..."); + std::vector<std::shared_ptr<storm::logic::Formula const>> taskFormulaAsVector { task.getFormula().asSharedPointer() }; + consideredModel = storm::api::transformContinuousToDiscreteTimeSparseModel(consideredModel, taskFormulaAsVector); + STORM_LOG_THROW(consideredModel->isOfType(storm::models::ModelType::Dtmc) || consideredModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::UnexpectedException, "Transformation to discrete time model has failed."); + } + + // Obtain the region model checker + std::unique_ptr<storm::modelchecker::RegionModelChecker<ParametricType>> result; + if (consideredModel->isOfType(storm::models::ModelType::Dtmc)) { + result = std::make_unique<storm::modelchecker::ValidatingSparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<ParametricType>, ImpreciseType, PreciseType>>(); + } else if (consideredModel->isOfType(storm::models::ModelType::Mdp)) { + result = std::make_unique<storm::modelchecker::ValidatingSparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<ParametricType>, ImpreciseType, PreciseType>>(); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform parameterLifting on the provided model type."); + } + + result->specify(consideredModel, task); + + return result; + } + + template <typename ValueType> + std::unique_ptr<storm::modelchecker::RegionModelChecker<ValueType>> initializeRegionModelChecker(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task, storm::modelchecker::RegionCheckEngine engine) { + switch (engine) { + case storm::modelchecker::RegionCheckEngine::ParameterLifting: + return initializeParameterLiftingRegionModelChecker<ValueType, double>(model, task); + case storm::modelchecker::RegionCheckEngine::ExactParameterLifting: + return initializeParameterLiftingRegionModelChecker<ValueType, storm::RationalNumber>(model, task); + case storm::modelchecker::RegionCheckEngine::ValidatingParameterLifting: + return initializeValidatingRegionModelChecker<ValueType, double, storm::RationalNumber>(model, task); + default: + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unexpected region model checker type."); + } + return nullptr; + } + + template <typename ValueType> + std::unique_ptr<storm::modelchecker::RegionCheckResult<ValueType>> checkRegionsWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task, std::vector<storm::storage::ParameterRegion<ValueType>> const& regions, storm::modelchecker::RegionCheckEngine engine) { + auto regionChecker = initializeRegionModelChecker(model, task, engine); + return regionChecker->analyzeRegions(regions, true); + } + + + template <typename ValueType> + std::unique_ptr<storm::modelchecker::RegionRefinementCheckResult<ValueType>> checkAndRefineRegionWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task, storm::storage::ParameterRegion<ValueType> const& region, ValueType const& refinementThreshold, storm::modelchecker::RegionCheckEngine engine) { + auto regionChecker = initializeRegionModelChecker(model, task, engine); + return regionChecker->performRegionRefinement(region, refinementThreshold); + } + + + template <typename ValueType> + void exportRegionCheckResultToFile(std::unique_ptr<storm::modelchecker::CheckResult> const& checkResult, std::string const& filename) { + + auto const* regionCheckResult = dynamic_cast<storm::modelchecker::RegionCheckResult<ValueType> const*>(checkResult.get()); + STORM_LOG_THROW(regionCheckResult != nullptr, storm::exceptions::UnexpectedException, "Can not export region check result: The given checkresult does not have the expected type."); + + std::ofstream filestream; + storm::utility::openFile(filename, filestream); + for (auto const& res : regionCheckResult->getRegionResults()) { + filestream << res.second << ": " << res.first << std::endl; + } + } + + } +} diff --git a/src/storm-pars/api/storm-pars.h b/src/storm-pars/api/storm-pars.h new file mode 100644 index 000000000..42ac7dc79 --- /dev/null +++ b/src/storm-pars/api/storm-pars.h @@ -0,0 +1,3 @@ +#pragma once + +#include "storm-pars/api/region.h" diff --git a/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp b/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp new file mode 100644 index 000000000..14d433e58 --- /dev/null +++ b/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp @@ -0,0 +1,147 @@ +#include "storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.h" + +#include "storm/logic/FragmentSpecification.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" +#include "storm/modelchecker/hints/ExplicitModelCheckerHint.h" +#include "storm/utility/vector.h" + +#include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/InvalidStateException.h" +namespace storm { + namespace modelchecker { + + template <typename SparseModelType, typename ConstantType> + SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::SparseDtmcInstantiationModelChecker(SparseModelType const& parametricModel) : SparseInstantiationModelChecker<SparseModelType, ConstantType>(parametricModel), modelInstantiator(parametricModel) { + //Intentionally left empty + } + + template <typename SparseModelType, typename ConstantType> + std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) { + STORM_LOG_THROW(this->currentCheckTask, storm::exceptions::InvalidStateException, "Checking has been invoked but no property has been specified before."); + auto const& instantiatedModel = modelInstantiator.instantiate(valuation); + STORM_LOG_ASSERT(instantiatedModel.getTransitionMatrix().isProbabilistic(), "Instantiated matrix is not probabilistic!"); + storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>> modelChecker(instantiatedModel); + + // Check if there are some optimizations implemented for the specified property + if(this->currentCheckTask->getFormula().isInFragment(storm::logic::reachability())) { + return checkReachabilityProbabilityFormula(modelChecker); + } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) { + return checkReachabilityRewardFormula(modelChecker); + } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setProbabilityOperatorsAllowed(true).setBoundedUntilFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) { + return checkBoundedUntilFormula(modelChecker); + } else { + return modelChecker.check(*this->currentCheckTask); + } + } + + template <typename SparseModelType, typename ConstantType> + std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityProbabilityFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker) { + + if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) { + this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>()); + } + ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>(); + std::unique_ptr<CheckResult> result; + + // Check the formula and store the result as a hint for the next call. + // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula + if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) { + result = modelChecker.check(*this->currentCheckTask); + hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()); + } else { + auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false); + std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask); + result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>()); + hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector())); + } + + if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) { + // Extract the maybe states from the current result. + assert(hint.hasResultHint()); + storm::storage::BitVector maybeStates = ~storm::utility::vector::filter<ConstantType>(hint.getResultHint(), + [] (ConstantType const& value) -> bool { return storm::utility::isZero<ConstantType>(value) || storm::utility::isOne<ConstantType>(value); }); + hint.setMaybeStates(std::move(maybeStates)); + hint.setComputeOnlyMaybeStates(true); + } + + return result; + } + + template <typename SparseModelType, typename ConstantType> + std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityRewardFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker) { + + if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) { + this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>()); + } + ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>(); + std::unique_ptr<CheckResult> result; + + // Check the formula and store the result as a hint for the next call. + // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula + if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) { + result = modelChecker.check(*this->currentCheckTask); + this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>().setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()); + } else { + auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false); + std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeRewards(this->currentCheckTask->getFormula().asRewardOperatorFormula().getMeasureType(), newCheckTask); + result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>()); + this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>().setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector())); + } + + if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) { + // Extract the maybe states from the current result. + assert(hint.hasResultHint()); + storm::storage::BitVector maybeStates = ~storm::utility::vector::filterInfinity(hint.getResultHint()); + // We need to exclude the target states from the maybe states. + // Note that we can not consider the states with reward zero since a valuation might set a reward to zero + std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asEventuallyFormula().getSubformula()); + maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector()); + hint.setMaybeStates(std::move(maybeStates)); + hint.setComputeOnlyMaybeStates(true); + } + + return result; + } + + template <typename SparseModelType, typename ConstantType> + std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::checkBoundedUntilFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker) { + + if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) { + this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>()); + } + std::unique_ptr<CheckResult> result; + ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>(); + + if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) { + // We extract the maybestates from the quantitative result + // For qualitative properties, we still need a quantitative result. Hence we perform the check on the subformula + if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) { + result = modelChecker.check(*this->currentCheckTask); + hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()); + } else { + auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false); + std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask); + result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>()); + hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector())); + } + + storm::storage::BitVector maybeStates = storm::utility::vector::filterGreaterZero(hint.getResultHint()); + // We need to exclude the target states from the maybe states. + // Note that we can not consider the states with probability one since a state might reach a target state with prob 1 within >0 steps + std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asBoundedUntilFormula().getRightSubformula()); + maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector()); + hint.setMaybeStates(std::move(maybeStates)); + hint.setComputeOnlyMaybeStates(true); + } else { + result = modelChecker.check(*this->currentCheckTask); + } + + return result; + } + + template class SparseDtmcInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>; + template class SparseDtmcInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>; + + } +} \ No newline at end of file diff --git a/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.h b/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.h new file mode 100644 index 000000000..ad1ffead4 --- /dev/null +++ b/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.h @@ -0,0 +1,35 @@ +#pragma once + +#include <memory> +#include <boost/optional.hpp> + +#include "storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h" +#include "storm-pars/utility/ModelInstantiator.h" +#include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" + +namespace storm { + namespace modelchecker { + + /*! + * Class to efficiently check a formula on a parametric model with different parameter instantiations + */ + template <typename SparseModelType, typename ConstantType> + class SparseDtmcInstantiationModelChecker : public SparseInstantiationModelChecker<SparseModelType, ConstantType> { + public: + SparseDtmcInstantiationModelChecker(SparseModelType const& parametricModel); + + virtual std::unique_ptr<CheckResult> check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) override; + + protected: + + // Optimizations for the different formula types + std::unique_ptr<CheckResult> checkReachabilityProbabilityFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker); + std::unique_ptr<CheckResult> checkReachabilityRewardFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker); + std::unique_ptr<CheckResult> checkBoundedUntilFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker); + + storm::utility::ModelInstantiator<SparseModelType, storm::models::sparse::Dtmc<ConstantType>> modelInstantiator; + }; + } +} diff --git a/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp b/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp new file mode 100644 index 000000000..d81d5b9a6 --- /dev/null +++ b/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp @@ -0,0 +1,42 @@ +#include "storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h" + +#include "storm/adapters/RationalFunctionAdapter.h" +#include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/Mdp.h" +#include "storm/models/sparse/StandardRewardModel.h" + +#include "storm/exceptions/InvalidArgumentException.h" + +namespace storm { + namespace modelchecker { + + template <typename SparseModelType, typename ConstantType> + SparseInstantiationModelChecker<SparseModelType, ConstantType>::SparseInstantiationModelChecker(SparseModelType const& parametricModel) : parametricModel(parametricModel), instantiationsAreGraphPreserving(false) { + //Intentionally left empty + } + + + template <typename SparseModelType, typename ConstantType> + void SparseInstantiationModelChecker<SparseModelType, ConstantType>::specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) { + currentFormula = checkTask.getFormula().asSharedPointer(); + currentCheckTask = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, ConstantType>>(checkTask.substituteFormula(*currentFormula).template convertValueType<ConstantType>()); + } + + template <typename SparseModelType, typename ConstantType> + void SparseInstantiationModelChecker<SparseModelType, ConstantType>::setInstantiationsAreGraphPreserving(bool value) { + instantiationsAreGraphPreserving = value; + } + + template <typename SparseModelType, typename ConstantType> + bool SparseInstantiationModelChecker<SparseModelType, ConstantType>::getInstantiationsAreGraphPreserving() const { + return instantiationsAreGraphPreserving; + } + + template class SparseInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>; + template class SparseInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>; + + template class SparseInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>; + template class SparseInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>; + + } +} diff --git a/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h b/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h new file mode 100644 index 000000000..43ed587ec --- /dev/null +++ b/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h @@ -0,0 +1,42 @@ +#pragma once + +#include "storm-pars/utility/parametric.h" +#include "storm/logic/Formulas.h" +#include "storm/modelchecker/CheckTask.h" +#include "storm/modelchecker/results/CheckResult.h" +#include "storm/modelchecker/hints/ModelCheckerHint.h" + +namespace storm { + namespace modelchecker { + + /*! + * Class to efficiently check a formula on a parametric model with different parameter instantiations + */ + template <typename SparseModelType, typename ConstantType> + class SparseInstantiationModelChecker { + public: + SparseInstantiationModelChecker(SparseModelType const& parametricModel); + virtual ~SparseInstantiationModelChecker() = default; + + void specifyFormula(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask); + + virtual std::unique_ptr<CheckResult> check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) = 0; + + // If set, it is assumed that all considered model instantiations have the same underlying graph structure. + // This bypasses the graph analysis for the different instantiations. + void setInstantiationsAreGraphPreserving(bool value); + bool getInstantiationsAreGraphPreserving() const; + + protected: + + SparseModelType const& parametricModel; + std::unique_ptr<CheckTask<storm::logic::Formula, ConstantType>> currentCheckTask; + + private: + // store the current formula. Note that currentCheckTask only stores a reference to the formula. + std::shared_ptr<storm::logic::Formula const> currentFormula; + + bool instantiationsAreGraphPreserving; + }; + } +} diff --git a/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp b/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp new file mode 100644 index 000000000..887d3b7bf --- /dev/null +++ b/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp @@ -0,0 +1,171 @@ +#include "storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.h" + +#include "storm/logic/FragmentSpecification.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" +#include "storm/modelchecker/hints/ExplicitModelCheckerHint.h" +#include "storm/storage/Scheduler.h" +#include "storm/utility/graph.h" +#include "storm/utility/vector.h" + +#include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/InvalidStateException.h" + +namespace storm { + namespace modelchecker { + + template <typename SparseModelType, typename ConstantType> + SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::SparseMdpInstantiationModelChecker(SparseModelType const& parametricModel) : SparseInstantiationModelChecker<SparseModelType, ConstantType>(parametricModel), modelInstantiator(parametricModel) { + //Intentionally left empty + } + + template <typename SparseModelType, typename ConstantType> + std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) { + STORM_LOG_THROW(this->currentCheckTask, storm::exceptions::InvalidStateException, "Checking has been invoked but no property has been specified before."); + auto const& instantiatedModel = modelInstantiator.instantiate(valuation); + STORM_LOG_ASSERT(instantiatedModel.getTransitionMatrix().isProbabilistic(), "Instantiated matrix is not probabilistic!"); + storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>> modelChecker(instantiatedModel); + + // Check if there are some optimizations implemented for the specified property + if(this->currentCheckTask->getFormula().isInFragment(storm::logic::reachability())) { + return checkReachabilityProbabilityFormula(modelChecker, instantiatedModel); + } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) { + return checkReachabilityRewardFormula(modelChecker, instantiatedModel); + } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setProbabilityOperatorsAllowed(true).setBoundedUntilFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) { + return checkBoundedUntilFormula(modelChecker); + } else { + return modelChecker.check(*this->currentCheckTask); + } + } + + template <typename SparseModelType, typename ConstantType> + std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityProbabilityFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel) { + + this->currentCheckTask->setProduceSchedulers(true); + + if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) { + this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>()); + } + ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>(); + std::unique_ptr<CheckResult> result; + + // Check the formula and store the result as a hint for the next call. + // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula + if(this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) { + result = modelChecker.check(*this->currentCheckTask); + storm::storage::Scheduler<ConstantType> const& scheduler = result->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler(); + hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()); + hint.setSchedulerHint(dynamic_cast<storm::storage::Scheduler<ConstantType> const&>(scheduler)); + } else { + auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false); + std::unique_ptr<storm::modelchecker::CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask); + result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>()); + storm::storage::Scheduler<ConstantType>& scheduler = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler(); + hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector())); + hint.setSchedulerHint(std::move(dynamic_cast<storm::storage::Scheduler<ConstantType>&>(scheduler))); + } + + if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) { + // Extract the maybe states from the current result. + assert(hint.hasResultHint()); + storm::storage::BitVector maybeStates = ~storm::utility::vector::filter<ConstantType>(hint.getResultHint(), + [] (ConstantType const& value) -> bool { return storm::utility::isZero<ConstantType>(value) || storm::utility::isOne<ConstantType>(value); }); + hint.setMaybeStates(std::move(maybeStates)); + hint.setComputeOnlyMaybeStates(true); + + // Check if there can be end components within the maybestates + if (storm::solver::minimize(this->currentCheckTask->getOptimizationDirection()) || + storm::utility::graph::performProb1A(instantiatedModel.getTransitionMatrix(), instantiatedModel.getTransitionMatrix().getRowGroupIndices(), instantiatedModel.getBackwardTransitions(), hint.getMaybeStates(), ~hint.getMaybeStates()).full()) { + hint.setNoEndComponentsInMaybeStates(true); + } + } + + return result; + } + + template <typename SparseModelType, typename ConstantType> + std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityRewardFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel) { + + this->currentCheckTask->setProduceSchedulers(true); + + if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) { + this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>()); + } + ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>(); + std::unique_ptr<CheckResult> result; + + // Check the formula and store the result as a hint for the next call. + // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula + if(this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) { + std::unique_ptr<storm::modelchecker::CheckResult> result = modelChecker.check(*this->currentCheckTask); + storm::storage::Scheduler<ConstantType> const& scheduler = result->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler(); + hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()); + hint.setSchedulerHint(dynamic_cast<storm::storage::Scheduler<ConstantType> const&>(scheduler)); + } else { + auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false); + std::unique_ptr<storm::modelchecker::CheckResult> quantitativeResult = modelChecker.computeRewards(this->currentCheckTask->getFormula().asRewardOperatorFormula().getMeasureType(), newCheckTask); + result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>()); + storm::storage::Scheduler<ConstantType>& scheduler = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler(); + hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector())); + hint.setSchedulerHint(std::move(dynamic_cast<storm::storage::Scheduler<ConstantType>&>(scheduler))); + } + + if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) { + // Extract the maybe states from the current result. + assert(hint.hasResultHint()); + storm::storage::BitVector maybeStates = ~storm::utility::vector::filterInfinity(hint.getResultHint()); + // We need to exclude the target states from the maybe states. + // Note that we can not consider the states with reward zero since a valuation might set a reward to zero + std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asEventuallyFormula().getSubformula()); + maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector()); + hint.setMaybeStates(std::move(maybeStates)); + hint.setComputeOnlyMaybeStates(true); + + // Check if there can be end components within the maybestates + if (storm::solver::maximize(this->currentCheckTask->getOptimizationDirection()) || + storm::utility::graph::performProb1A(instantiatedModel.getTransitionMatrix(), instantiatedModel.getTransitionMatrix().getRowGroupIndices(), instantiatedModel.getBackwardTransitions(), hint.getMaybeStates(), ~hint.getMaybeStates()).full()) { + hint.setNoEndComponentsInMaybeStates(true); + } + } + return result; + } + + template <typename SparseModelType, typename ConstantType> + std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::checkBoundedUntilFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker) { + + if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) { + this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>()); + } + std::unique_ptr<CheckResult> result; + ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>(); + + if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) { + // We extract the maybestates from the quantitative result + // For qualitative properties, we still need a quantitative result. Hence we perform the check on the subformula + if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) { + result = modelChecker.check(*this->currentCheckTask); + hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()); + } else { + auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false); + std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask); + result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>()); + hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector())); + } + storm::storage::BitVector maybeStates = storm::utility::vector::filterGreaterZero(hint.getResultHint()); + // We need to exclude the target states from the maybe states. + // Note that we can not consider the states with probability one since a state might reach a target state with prob 1 within >0 steps + std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asBoundedUntilFormula().getRightSubformula()); + maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector()); + hint.setMaybeStates(std::move(maybeStates)); + hint.setComputeOnlyMaybeStates(true); + } else { + result = modelChecker.check(*this->currentCheckTask); + } + return result; + } + + template class SparseMdpInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>; + template class SparseMdpInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>; + + } +} diff --git a/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.h b/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.h new file mode 100644 index 000000000..d8d5d46e8 --- /dev/null +++ b/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.h @@ -0,0 +1,34 @@ +#pragma once + +#include <memory> + +#include "storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h" +#include "storm-pars/utility/ModelInstantiator.h" +#include "storm/models/sparse/Mdp.h" +#include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h" + +namespace storm { + namespace modelchecker { + + /*! + * Class to efficiently check a formula on a parametric model with different parameter instantiations + */ + template <typename SparseModelType, typename ConstantType> + class SparseMdpInstantiationModelChecker : public SparseInstantiationModelChecker<SparseModelType, ConstantType> { + public: + SparseMdpInstantiationModelChecker(SparseModelType const& parametricModel); + + virtual std::unique_ptr<CheckResult> check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) override; + + protected: + // Optimizations for the different formula types + std::unique_ptr<CheckResult> checkReachabilityProbabilityFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel); + std::unique_ptr<CheckResult> checkReachabilityRewardFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel); + std::unique_ptr<CheckResult> checkBoundedUntilFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker); + + storm::utility::ModelInstantiator<SparseModelType, storm::models::sparse::Mdp<ConstantType>> modelInstantiator; + }; + } +} diff --git a/src/storm-pars/modelchecker/region/RegionCheckEngine.cpp b/src/storm-pars/modelchecker/region/RegionCheckEngine.cpp new file mode 100644 index 000000000..e23be1eb1 --- /dev/null +++ b/src/storm-pars/modelchecker/region/RegionCheckEngine.cpp @@ -0,0 +1,25 @@ +#include "storm-pars/modelchecker/region/RegionCheckEngine.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/NotImplementedException.h" + +namespace storm { + namespace modelchecker { + std::ostream& operator<<(std::ostream& os, RegionCheckEngine const& e) { + switch (e) { + case RegionCheckEngine::ParameterLifting: + os << "Parameter Lifting"; + break; + case RegionCheckEngine::ExactParameterLifting: + os << "Exact Parameter Lifting"; + break; + case RegionCheckEngine::ValidatingParameterLifting: + os << "Validating Parameter Lifting"; + break; + default: + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Could not get a string from the region check engine. The case has not been implemented"); + } + return os; + } + } +} diff --git a/src/storm-pars/modelchecker/region/RegionCheckEngine.h b/src/storm-pars/modelchecker/region/RegionCheckEngine.h new file mode 100644 index 000000000..5ff26d691 --- /dev/null +++ b/src/storm-pars/modelchecker/region/RegionCheckEngine.h @@ -0,0 +1,19 @@ +#pragma once + +#include <ostream> + +namespace storm { + namespace modelchecker { + /*! + * The considered engine for region checking + */ + enum class RegionCheckEngine { + ParameterLifting, /*!< Parameter lifting approach */ + ExactParameterLifting, /*!< Parameter lifting approach with exact arithmethics*/ + ValidatingParameterLifting, /*!< Parameter lifting approach with a) inexact (and fast) computation first and b) exact validation of obtained results second */ + }; + + std::ostream& operator<<(std::ostream& os, RegionCheckEngine const& regionCheckResult); + } +} + diff --git a/src/storm-pars/modelchecker/region/RegionModelChecker.cpp b/src/storm-pars/modelchecker/region/RegionModelChecker.cpp new file mode 100644 index 000000000..a2a19451d --- /dev/null +++ b/src/storm-pars/modelchecker/region/RegionModelChecker.cpp @@ -0,0 +1,130 @@ +#include <sstream> +#include <queue> + +#include "storm-pars/modelchecker/region/RegionModelChecker.h" + +#include "storm/adapters/RationalFunctionAdapter.h" + + +#include "storm/utility/vector.h" +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/Mdp.h" + +#include "storm/exceptions/NotSupportedException.h" +#include "storm/exceptions/InvalidStateException.h" +#include "storm/exceptions/InvalidArgumentException.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/CoreSettings.h" + + +namespace storm { + namespace modelchecker { + + template <typename ParametricType> + RegionModelChecker<ParametricType>::RegionModelChecker() { + // Intentionally left empty + } + + template <typename ParametricType> + std::unique_ptr<storm::modelchecker::RegionCheckResult<ParametricType>> RegionModelChecker<ParametricType>::analyzeRegions(std::vector<storm::storage::ParameterRegion<ParametricType>> const& regions, bool sampleVerticesOfRegion) { + + std::vector<std::pair<storm::storage::ParameterRegion<ParametricType>, storm::modelchecker::RegionResult>> result; + + for (auto const& region : regions) { + storm::modelchecker::RegionResult regionRes = analyzeRegion(region, storm::modelchecker::RegionResult::Unknown, sampleVerticesOfRegion); + result.emplace_back(region, regionRes); + } + + return std::make_unique<storm::modelchecker::RegionCheckResult<ParametricType>>(std::move(result)); + } + + template <typename ParametricType> + std::unique_ptr<storm::modelchecker::RegionRefinementCheckResult<ParametricType>> RegionModelChecker<ParametricType>::performRegionRefinement(storm::storage::ParameterRegion<ParametricType> const& region, ParametricType const& threshold) { + STORM_LOG_INFO("Applying refinement on region: " << region.toString(true) << " ."); + + auto thresholdAsCoefficient = storm::utility::convertNumber<CoefficientType>(threshold); + auto areaOfParameterSpace = region.area(); + auto fractionOfUndiscoveredArea = storm::utility::one<CoefficientType>(); + auto fractionOfAllSatArea = storm::utility::zero<CoefficientType>(); + auto fractionOfAllViolatedArea = storm::utility::zero<CoefficientType>(); + + std::queue<std::pair<storm::storage::ParameterRegion<ParametricType>, RegionResult>> unprocessedRegions; + std::vector<std::pair<storm::storage::ParameterRegion<ParametricType>, RegionResult>> result; + unprocessedRegions.emplace(region, RegionResult::Unknown); + uint_fast64_t numOfAnalyzedRegions = 0; + CoefficientType displayedProgress = storm::utility::zero<CoefficientType>(); + if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) { + STORM_PRINT_AND_LOG("Progress (solved fraction) :" << std::endl << "0% ["); + while (displayedProgress < storm::utility::one<CoefficientType>() - thresholdAsCoefficient) { + STORM_PRINT_AND_LOG(" "); + displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01); + } + while (displayedProgress < storm::utility::one<CoefficientType>()) { + STORM_PRINT_AND_LOG("-"); + displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01); + } + STORM_PRINT_AND_LOG("] 100%" << std::endl << " ["); + displayedProgress = storm::utility::zero<CoefficientType>(); + } + + while (fractionOfUndiscoveredArea > thresholdAsCoefficient) { + STORM_LOG_THROW(!unprocessedRegions.empty(), storm::exceptions::InvalidStateException, "Threshold for undiscovered area not reached but no unprocessed regions left."); + STORM_LOG_INFO("Analyzing region #" << numOfAnalyzedRegions << " (" << storm::utility::convertNumber<double>(fractionOfUndiscoveredArea) * 100 << "% still unknown)"); + auto& currentRegion = unprocessedRegions.front().first; + auto& res = unprocessedRegions.front().second; + res = analyzeRegion(currentRegion, res, false); + switch (res) { + case RegionResult::AllSat: + fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace; + fractionOfAllSatArea += currentRegion.area() / areaOfParameterSpace; + result.push_back(std::move(unprocessedRegions.front())); + break; + case RegionResult::AllViolated: + fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace; + fractionOfAllViolatedArea += currentRegion.area() / areaOfParameterSpace; + result.push_back(std::move(unprocessedRegions.front())); + break; + default: + std::vector<storm::storage::ParameterRegion<ParametricType>> newRegions; + currentRegion.split(currentRegion.getCenterPoint(), newRegions); + RegionResult initResForNewRegions = (res == RegionResult::CenterSat) ? RegionResult::ExistsSat : + ((res == RegionResult::CenterViolated) ? RegionResult::ExistsViolated : + RegionResult::Unknown); + for(auto& newRegion : newRegions) { + unprocessedRegions.emplace(std::move(newRegion), initResForNewRegions); + } + break; + } + ++numOfAnalyzedRegions; + unprocessedRegions.pop(); + if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) { + while (displayedProgress < storm::utility::one<CoefficientType>() - fractionOfUndiscoveredArea) { + STORM_PRINT_AND_LOG("#"); + displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01); + } + } + } + + if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) { + while (displayedProgress < storm::utility::one<CoefficientType>()) { + STORM_PRINT_AND_LOG("-"); + displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01); + } + STORM_PRINT_AND_LOG("]" << std::endl); + + STORM_PRINT_AND_LOG("Region Refinement Statistics:" << std::endl); + STORM_PRINT_AND_LOG(" Analyzed a total of " << numOfAnalyzedRegions << " regions." << std::endl); + } + + auto regionCopyForResult = region; + return std::make_unique<storm::modelchecker::RegionRefinementCheckResult<ParametricType>>(std::move(result), std::move(regionCopyForResult)); + } + +#ifdef STORM_HAVE_CARL + template class RegionModelChecker<storm::RationalFunction>; +#endif + } //namespace modelchecker +} //namespace storm + diff --git a/src/storm-pars/modelchecker/region/RegionModelChecker.h b/src/storm-pars/modelchecker/region/RegionModelChecker.h new file mode 100644 index 000000000..a8f1fdf01 --- /dev/null +++ b/src/storm-pars/modelchecker/region/RegionModelChecker.h @@ -0,0 +1,50 @@ +#pragma once + +#include <memory> + +#include "storm-pars/modelchecker/results/RegionCheckResult.h" +#include "storm-pars/modelchecker/results/RegionRefinementCheckResult.h" +#include "storm-pars/modelchecker/region/RegionResult.h" +#include "storm-pars/storage/ParameterRegion.h" + +#include "storm/models/ModelBase.h" +#include "storm/modelchecker/CheckTask.h" + +namespace storm { + namespace modelchecker{ + + template<typename ParametricType> + class RegionModelChecker { + public: + + typedef typename storm::storage::ParameterRegion<ParametricType>::CoefficientType CoefficientType; + + RegionModelChecker(); + virtual ~RegionModelChecker() = default; + + virtual bool canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, ParametricType> const& checkTask) const = 0; + virtual void specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, ParametricType> const& checkTask) = 0; + + /*! + * Analyzes the given region. + * An initial region result can be given to simplify the analysis (e.g. if the initial result is ExistsSat, we do not check for AllViolated). + * If supported by this model checker, it is possible to sample the vertices of the region whenever AllSat/AllViolated could not be shown. + */ + virtual RegionResult analyzeRegion(storm::storage::ParameterRegion<ParametricType> const& region, RegionResult const& initialResult = RegionResult::Unknown, bool sampleVerticesOfRegion = false) = 0; + + /*! + * Analyzes the given regions. + * If supported by this model checker, it is possible to sample the vertices of the regions whenever AllSat/AllViolated could not be shown. + */ + std::unique_ptr<storm::modelchecker::RegionCheckResult<ParametricType>> analyzeRegions(std::vector<storm::storage::ParameterRegion<ParametricType>> const& regions, bool sampleVerticesOfRegion = false) ; + + /*! + * Iteratively refines the region until the region analysis yields a conclusive result (AllSat or AllViolated). + * The refinement stops as soon as the fraction of the area of the subregions with inconclusive result is less then the given threshold + */ + std::unique_ptr<storm::modelchecker::RegionRefinementCheckResult<ParametricType>> performRegionRefinement(storm::storage::ParameterRegion<ParametricType> const& region, ParametricType const& threshold); + + }; + + } //namespace modelchecker +} //namespace storm diff --git a/src/storm-pars/modelchecker/region/RegionResult.cpp b/src/storm-pars/modelchecker/region/RegionResult.cpp new file mode 100644 index 000000000..0da22a028 --- /dev/null +++ b/src/storm-pars/modelchecker/region/RegionResult.cpp @@ -0,0 +1,40 @@ +#include "storm-pars/modelchecker/region/RegionResult.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/NotImplementedException.h" + +namespace storm { + namespace modelchecker { + std::ostream& operator<<(std::ostream& os, RegionResult const& regionResult) { + switch (regionResult) { + case RegionResult::Unknown: + os << "Unknown"; + break; + case RegionResult::ExistsSat: + os << "ExistsSat"; + break; + case RegionResult::ExistsViolated: + os << "ExistsViolated"; + break; + case RegionResult::CenterSat: + os << "CenterSat"; + break; + case RegionResult::CenterViolated: + os << "CenterViolated"; + break; + case RegionResult::ExistsBoth: + os << "ExistsBoth"; + break; + case RegionResult::AllSat: + os << "AllSat"; + break; + case RegionResult::AllViolated: + os << "AllViolated"; + break; + default: + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Could not get a string from the region check result. The case has not been implemented"); + } + return os; + } + } +} diff --git a/src/storm-pars/modelchecker/region/RegionResult.h b/src/storm-pars/modelchecker/region/RegionResult.h new file mode 100644 index 000000000..1ad568f87 --- /dev/null +++ b/src/storm-pars/modelchecker/region/RegionResult.h @@ -0,0 +1,24 @@ +#pragma once + +#include <ostream> + +namespace storm { + namespace modelchecker { + /*! + * The results for a single Parameter Region + */ + enum class RegionResult { + Unknown, /*!< the result is unknown */ + ExistsSat, /*!< the formula is satisfied for at least one parameter evaluation that lies in the given region */ + ExistsViolated, /*!< the formula is violated for at least one parameter evaluation that lies in the given region */ + CenterSat, /*!< the formula is satisfied for the parameter Valuation that corresponds to the center point of the region */ + CenterViolated, /*!< the formula is violated for the parameter Valuation that corresponds to the center point of the region */ + ExistsBoth, /*!< the formula is satisfied for some parameters but also violated for others */ + AllSat, /*!< the formula is satisfied for all parameters in the given region */ + AllViolated /*!< the formula is violated for all parameters in the given region */ + }; + + std::ostream& operator<<(std::ostream& os, RegionResult const& regionCheckResult); + } +} + diff --git a/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp new file mode 100644 index 000000000..5f32c8386 --- /dev/null +++ b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp @@ -0,0 +1,328 @@ +#include "storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h" + +#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h" + +#include "storm/adapters/RationalFunctionAdapter.h" +#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h" +#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/solver/StandardMinMaxLinearEquationSolver.h" +#include "storm/utility/vector.h" +#include "storm/utility/graph.h" +#include "storm/utility/NumberTraits.h" + +#include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/InvalidPropertyException.h" +#include "storm/exceptions/NotSupportedException.h" +#include "storm/exceptions/UnexpectedException.h" + +namespace storm { + namespace modelchecker { + + template <typename SparseModelType, typename ConstantType> + SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseDtmcParameterLiftingModelChecker() : SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>(std::make_unique<storm::solver::GeneralMinMaxLinearEquationSolverFactory<ConstantType>>()) { + // Intentionally left empty + } + + template <typename SparseModelType, typename ConstantType> + SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseDtmcParameterLiftingModelChecker(std::unique_ptr<storm::solver::MinMaxLinearEquationSolverFactory<ConstantType>>&& solverFactory) : solverFactory(std::move(solverFactory)) { + // Intentionally left empty + } + + template <typename SparseModelType, typename ConstantType> + bool SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const { + bool result = parametricModel->isOfType(storm::models::ModelType::Dtmc); + result &= parametricModel->isSparseModel(); + result &= parametricModel->supportsParameters(); + auto dtmc = parametricModel->template as<SparseModelType>(); + result &= static_cast<bool>(dtmc); + result &= checkTask.getFormula().isInFragment(storm::logic::reachability().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setBoundedUntilFormulasAllowed(true).setCumulativeRewardFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(true)); + return result; + } + + template <typename SparseModelType, typename ConstantType> + void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) { + auto dtmc = parametricModel->template as<SparseModelType>(); + specify(dtmc, checkTask, false); + } + + template <typename SparseModelType, typename ConstantType> + void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specify(std::shared_ptr<SparseModelType> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask, bool skipModelSimplification) { + + STORM_LOG_ASSERT(this->canHandle(parametricModel, checkTask), "specified model and formula can not be handled by this."); + + reset(); + + if (skipModelSimplification) { + this->parametricModel = parametricModel; + this->specifyFormula(checkTask); + } else { + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier<SparseModelType>(*parametricModel); + if (!simplifier.simplify(checkTask.getFormula())) { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull."); + } + this->parametricModel = simplifier.getSimplifiedModel(); + this->specifyFormula(checkTask.substituteFormula(*simplifier.getSimplifiedFormula())); + } + } + + + template <typename SparseModelType, typename ConstantType> + void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) { + + // get the step bound + STORM_LOG_THROW(!checkTask.getFormula().hasLowerBound(), storm::exceptions::NotSupportedException, "Lower step bounds are not supported."); + STORM_LOG_THROW(checkTask.getFormula().hasUpperBound(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with an upper bound."); + STORM_LOG_THROW(checkTask.getFormula().isStepBounded(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with step bounds."); + stepBound = checkTask.getFormula().getUpperBound().evaluateAsInt(); + STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive."); + if (checkTask.getFormula().isUpperBoundStrict()) { + STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero."); + --(*stepBound); + } + STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive."); + + // get the results for the subformulas + storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel); + STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported"); + storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); + storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); + + // get the maybeStates + maybeStates = storm::utility::graph::performProbGreater0(this->parametricModel->getBackwardTransitions(), phiStates, psiStates, true, *stepBound); + maybeStates &= ~psiStates; + + // set the result for all non-maybe states + resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>()); + storm::utility::vector::setVectorValues(resultsForNonMaybeStates, psiStates, storm::utility::one<ConstantType>()); + + // if there are maybestates, create the parameterLifter + if (!maybeStates.empty()) { + // Create the vector of one-step probabilities to go to target states. + std::vector<typename SparseModelType::ValueType> b = this->parametricModel->getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(), true), psiStates); + + parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, maybeStates, maybeStates); + } + + // We know some bounds for the results so set them + lowerResultBound = storm::utility::zero<ConstantType>(); + upperResultBound = storm::utility::one<ConstantType>(); + } + + template <typename SparseModelType, typename ConstantType> + void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) { + + // get the results for the subformulas + storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel); + STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported"); + storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); + storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); + + // get the maybeStates + std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 = storm::utility::graph::performProb01(this->parametricModel->getBackwardTransitions(), phiStates, psiStates); + maybeStates = ~(statesWithProbability01.first | statesWithProbability01.second); + + // set the result for all non-maybe states + resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>()); + storm::utility::vector::setVectorValues(resultsForNonMaybeStates, statesWithProbability01.second, storm::utility::one<ConstantType>()); + + // if there are maybestates, create the parameterLifter + if (!maybeStates.empty()) { + // Create the vector of one-step probabilities to go to target states. + std::vector<typename SparseModelType::ValueType> b = this->parametricModel->getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(), true), psiStates); + + parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, maybeStates, maybeStates); + } + + // We know some bounds for the results so set them + lowerResultBound = storm::utility::zero<ConstantType>(); + upperResultBound = storm::utility::one<ConstantType>(); + } + + template <typename SparseModelType, typename ConstantType> + void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) { + + // get the results for the subformula + storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel); + STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported"); + storm::storage::BitVector targetStates = std::move(propositionalChecker.check(checkTask.getFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); + + // get the maybeStates + storm::storage::BitVector infinityStates = storm::utility::graph::performProb1(this->parametricModel->getBackwardTransitions(), storm::storage::BitVector(this->parametricModel->getNumberOfStates(), true), targetStates); + infinityStates.complement(); + maybeStates = ~(targetStates | infinityStates); + + // set the result for all the non-maybe states + resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>()); + storm::utility::vector::setVectorValues(resultsForNonMaybeStates, infinityStates, storm::utility::infinity<ConstantType>()); + + // if there are maybestates, create the parameterLifter + if (!maybeStates.empty()) { + // Create the reward vector + STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel->hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model."); + + typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel->getRewardModel(checkTask.getRewardModel()) : this->parametricModel->getUniqueRewardModel(); + + std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel->getTransitionMatrix()); + + parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, maybeStates, maybeStates); + } + + // We only know a lower bound for the result + lowerResultBound = storm::utility::zero<ConstantType>(); + + } + + template <typename SparseModelType, typename ConstantType> + void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) { + + // Obtain the stepBound + stepBound = checkTask.getFormula().getBound().evaluateAsInt(); + if (checkTask.getFormula().isBoundStrict()) { + STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero."); + --(*stepBound); + } + STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive."); + + //Every state is a maybeState + maybeStates = storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getColumnCount(), true); + resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates()); + + // Create the reward vector + STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel->hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model."); + typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel->getRewardModel(checkTask.getRewardModel()) : this->parametricModel->getUniqueRewardModel(); + std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel->getTransitionMatrix()); + + parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, maybeStates, maybeStates); + + + // We only know a lower bound for the result + lowerResultBound = storm::utility::zero<ConstantType>(); + } + + template <typename SparseModelType, typename ConstantType> + storm::modelchecker::SparseInstantiationModelChecker<SparseModelType, ConstantType>& SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::getInstantiationChecker() { + if (!instantiationChecker) { + instantiationChecker = std::make_unique<storm::modelchecker::SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>>(*this->parametricModel); + instantiationChecker->specifyFormula(this->currentCheckTask->template convertValueType<typename SparseModelType::ValueType>()); + instantiationChecker->setInstantiationsAreGraphPreserving(true); + } + return *instantiationChecker; + } + + template <typename SparseModelType, typename ConstantType> + std::unique_ptr<CheckResult> SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) { + + if(maybeStates.empty()) { + return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(resultsForNonMaybeStates); + } + + parameterLifter->specifyRegion(region, dirForParameters); + + // Set up the solver + auto solver = solverFactory->create(parameterLifter->getMatrix()); + if (storm::NumberTraits<ConstantType>::IsExact && dynamic_cast<storm::solver::StandardMinMaxLinearEquationSolver<ConstantType>*>(solver.get())) { + STORM_LOG_INFO("Parameter Lifting: Setting solution method for exact MinMaxSolver to policy iteration"); + auto* standardSolver = dynamic_cast<storm::solver::StandardMinMaxLinearEquationSolver<ConstantType>*>(solver.get()); + auto settings = standardSolver->getSettings(); + settings.setSolutionMethod(storm::solver::StandardMinMaxLinearEquationSolverSettings<ConstantType>::SolutionMethod::PolicyIteration); + standardSolver->setSettings(settings); + } + if (lowerResultBound) solver->setLowerBound(lowerResultBound.get()); + if (upperResultBound) solver->setUpperBound(upperResultBound.get()); + if (!stepBound) solver->setTrackScheduler(true); + if (storm::solver::minimize(dirForParameters) && minSchedChoices && !stepBound) solver->setSchedulerHint(std::move(minSchedChoices.get())); + if (storm::solver::maximize(dirForParameters) && maxSchedChoices && !stepBound) solver->setSchedulerHint(std::move(maxSchedChoices.get())); + if (this->currentCheckTask->isBoundSet() && solver->hasSchedulerHint()) { + // If we reach this point, we know that after applying the hint, the x-values can only become larger (if we maximize) or smaller (if we minimize). + std::unique_ptr<storm::solver::TerminationCondition<ConstantType>> termCond; + storm::storage::BitVector relevantStatesInSubsystem = this->currentCheckTask->isOnlyInitialStatesRelevantSet() ? this->parametricModel->getInitialStates() % maybeStates : storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true); + if (storm::solver::minimize(dirForParameters)) { + // Terminate if the value for ALL relevant states is already below the threshold + termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumBelowThreshold<ConstantType>> (relevantStatesInSubsystem, this->currentCheckTask->getBoundThreshold(), true, false); + } else { + // Terminate if the value for ALL relevant states is already above the threshold + termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumExceedsThreshold<ConstantType>> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), true); + } + solver->setTerminationCondition(std::move(termCond)); + } + + // Invoke the solver + if(stepBound) { + assert(*stepBound > 0); + x = std::vector<ConstantType>(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>()); + solver->repeatedMultiply(dirForParameters, x, ¶meterLifter->getVector(), *stepBound); + } else { + x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>()); + solver->solveEquations(dirForParameters, x, parameterLifter->getVector()); + if(storm::solver::minimize(dirForParameters)) { + minSchedChoices = solver->getSchedulerChoices(); + } else { + maxSchedChoices = solver->getSchedulerChoices(); + } + } + + // Get the result for the complete model (including maybestates) + std::vector<ConstantType> result = resultsForNonMaybeStates; + auto maybeStateResIt = x.begin(); + for(auto const& maybeState : maybeStates) { + result[maybeState] = *maybeStateResIt; + ++maybeStateResIt; + } + return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(std::move(result)); + } + + + template <typename SparseModelType, typename ConstantType> + void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::reset() { + maybeStates.resize(0); + resultsForNonMaybeStates.clear(); + stepBound = boost::none; + instantiationChecker = nullptr; + parameterLifter = nullptr; + minSchedChoices = boost::none; + maxSchedChoices = boost::none; + x.clear(); + lowerResultBound = boost::none; + upperResultBound = boost::none; + } + + template <typename SparseModelType, typename ConstantType> + boost::optional<storm::storage::Scheduler<ConstantType>> SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMinScheduler() { + if (!minSchedChoices) { + return boost::none; + } + + storm::storage::Scheduler<ConstantType> result(minSchedChoices->size()); + uint_fast64_t state = 0; + for (auto const& schedulerChoice : minSchedChoices.get()) { + result.setChoice(schedulerChoice, state); + ++state; + } + + return result; + } + + template <typename SparseModelType, typename ConstantType> + boost::optional<storm::storage::Scheduler<ConstantType>> SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMaxScheduler() { + if (!maxSchedChoices) { + return boost::none; + } + + storm::storage::Scheduler<ConstantType> result(maxSchedChoices->size()); + uint_fast64_t state = 0; + for (auto const& schedulerChoice : maxSchedChoices.get()) { + result.setChoice(schedulerChoice, state); + ++state; + } + + return result; + } + + template class SparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>; + template class SparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>; + + } +} diff --git a/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h new file mode 100644 index 000000000..d6f51032b --- /dev/null +++ b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h @@ -0,0 +1,64 @@ +#pragma once + +#include <vector> +#include <memory> +#include <boost/optional.hpp> + +#include "storm-pars/transformer/ParameterLifter.h" +#include "storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h" +#include "storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.h" +#include "storm/storage/BitVector.h" +#include "storm/storage/Scheduler.h" +#include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/logic/FragmentSpecification.h" + + +namespace storm { + namespace modelchecker { + + template <typename SparseModelType, typename ConstantType> + class SparseDtmcParameterLiftingModelChecker : public SparseParameterLiftingModelChecker<SparseModelType, ConstantType> { + public: + SparseDtmcParameterLiftingModelChecker(); + SparseDtmcParameterLiftingModelChecker(std::unique_ptr<storm::solver::MinMaxLinearEquationSolverFactory<ConstantType>>&& solverFactory); + virtual ~SparseDtmcParameterLiftingModelChecker() = default; + + virtual bool canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const override; + virtual void specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) override; + void specify(std::shared_ptr<SparseModelType> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask, bool skipModelSimplification); + + boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMinScheduler(); + boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMaxScheduler(); + + protected: + + virtual void specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) override; + virtual void specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) override; + virtual void specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) override; + virtual void specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) override; + + virtual storm::modelchecker::SparseInstantiationModelChecker<SparseModelType, ConstantType>& getInstantiationChecker() override; + + virtual std::unique_ptr<CheckResult> computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) override; + + virtual void reset() override; + + private: + + + storm::storage::BitVector maybeStates; + std::vector<ConstantType> resultsForNonMaybeStates; + boost::optional<uint_fast64_t> stepBound; + + std::unique_ptr<storm::modelchecker::SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>> instantiationChecker; + + std::unique_ptr<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>> parameterLifter; + std::unique_ptr<storm::solver::MinMaxLinearEquationSolverFactory<ConstantType>> solverFactory; + + // Results from the most recent solver call. + boost::optional<std::vector<uint_fast64_t>> minSchedChoices, maxSchedChoices; + std::vector<ConstantType> x; + boost::optional<ConstantType> lowerResultBound, upperResultBound; + }; + } +} diff --git a/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp new file mode 100644 index 000000000..6169d22bf --- /dev/null +++ b/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp @@ -0,0 +1,408 @@ +#include "storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.h" +#include "storm-pars/utility/parameterlifting.h" +#include "storm-pars/transformer/SparseParametricMdpSimplifier.h" + +#include "storm/adapters/RationalFunctionAdapter.h" +#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h" +#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm/models/sparse/Mdp.h" +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/utility/vector.h" +#include "storm/utility/graph.h" +#include "storm/utility/NumberTraits.h" +#include "storm/solver/StandardGameSolver.h" +#include "storm/logic/FragmentSpecification.h" + +#include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/InvalidPropertyException.h" +#include "storm/exceptions/NotSupportedException.h" +#include "storm/exceptions/UnexpectedException.h" + +namespace storm { + namespace modelchecker { + + + template <typename SparseModelType, typename ConstantType> + SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseMdpParameterLiftingModelChecker() : SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>(std::make_unique<storm::solver::GameSolverFactory<ConstantType>>()) { + // Intentionally left empty + } + + template <typename SparseModelType, typename ConstantType> + SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseMdpParameterLiftingModelChecker(std::unique_ptr<storm::solver::GameSolverFactory<ConstantType>>&& solverFactory) : solverFactory(std::move(solverFactory)) { + // Intentionally left empty + } + + template <typename SparseModelType, typename ConstantType> + bool SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const { + bool result = parametricModel->isOfType(storm::models::ModelType::Mdp); + result &= parametricModel->isSparseModel(); + result &= parametricModel->supportsParameters(); + auto mdp = parametricModel->template as<SparseModelType>(); + result &= static_cast<bool>(mdp); + result &= checkTask.getFormula().isInFragment(storm::logic::reachability().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setBoundedUntilFormulasAllowed(true).setCumulativeRewardFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(true)); + return result; + } + + template <typename SparseModelType, typename ConstantType> + void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) { + auto mdp = parametricModel->template as<SparseModelType>(); + specify(mdp, checkTask, false); + } + + template <typename SparseModelType, typename ConstantType> + void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specify(std::shared_ptr<SparseModelType> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask, bool skipModelSimplification) { + + STORM_LOG_ASSERT(this->canHandle(parametricModel, checkTask), "specified model and formula can not be handled by this."); + + reset(); + + if (skipModelSimplification) { + this->parametricModel = parametricModel; + this->specifyFormula(checkTask); + } else { + auto simplifier = storm::transformer::SparseParametricMdpSimplifier<SparseModelType>(*parametricModel); + if (!simplifier.simplify(checkTask.getFormula())) { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull."); + } + this->parametricModel = simplifier.getSimplifiedModel(); + this->specifyFormula(checkTask.substituteFormula(*simplifier.getSimplifiedFormula())); + } + } + + template <typename SparseModelType, typename ConstantType> + void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) { + + // get the step bound + STORM_LOG_THROW(!checkTask.getFormula().hasLowerBound(), storm::exceptions::NotSupportedException, "Lower step bounds are not supported."); + STORM_LOG_THROW(checkTask.getFormula().hasUpperBound(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with an upper bound."); + STORM_LOG_THROW(checkTask.getFormula().isStepBounded(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with step bounds."); + stepBound = checkTask.getFormula().getUpperBound().evaluateAsInt(); + STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive."); + if (checkTask.getFormula().isUpperBoundStrict()) { + STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero."); + --(*stepBound); + } + STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive."); + + // get the results for the subformulas + storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel); + STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported"); + storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); + storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); + + // get the maybeStates + maybeStates = storm::solver::minimize(checkTask.getOptimizationDirection()) ? + storm::utility::graph::performProbGreater0A(this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(), this->parametricModel->getBackwardTransitions(), phiStates, psiStates, true, *stepBound) : + storm::utility::graph::performProbGreater0E(this->parametricModel->getBackwardTransitions(), phiStates, psiStates, true, *stepBound); + maybeStates &= ~psiStates; + + // set the result for all non-maybe states + resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>()); + storm::utility::vector::setVectorValues(resultsForNonMaybeStates, psiStates, storm::utility::one<ConstantType>()); + + // if there are maybestates, create the parameterLifter + if (!maybeStates.empty()) { + // Create the vector of one-step probabilities to go to target states. + std::vector<typename SparseModelType::ValueType> b = this->parametricModel->getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(), true), psiStates); + + parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, this->parametricModel->getTransitionMatrix().getRowFilter(maybeStates), maybeStates); + computePlayer1Matrix(); + + applyPreviousResultAsHint = false; + } + + // We know some bounds for the results + lowerResultBound = storm::utility::zero<ConstantType>(); + upperResultBound = storm::utility::one<ConstantType>(); + } + + template <typename SparseModelType, typename ConstantType> + void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) { + + // get the results for the subformulas + storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel); + STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported"); + storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); + storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); + + // get the maybeStates + std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 = storm::solver::minimize(checkTask.getOptimizationDirection()) ? + storm::utility::graph::performProb01Min(this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(), this->parametricModel->getBackwardTransitions(), phiStates, psiStates) : + storm::utility::graph::performProb01Max(this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(), this->parametricModel->getBackwardTransitions(), phiStates, psiStates); + maybeStates = ~(statesWithProbability01.first | statesWithProbability01.second); + + // set the result for all non-maybe states + resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>()); + storm::utility::vector::setVectorValues(resultsForNonMaybeStates, statesWithProbability01.second, storm::utility::one<ConstantType>()); + + // if there are maybestates, create the parameterLifter + if (!maybeStates.empty()) { + // Create the vector of one-step probabilities to go to target states. + std::vector<typename SparseModelType::ValueType> b = this->parametricModel->getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(), true), statesWithProbability01.second); + + parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, this->parametricModel->getTransitionMatrix().getRowFilter(maybeStates), maybeStates); + computePlayer1Matrix(); + + // Check whether there is an EC consisting of maybestates + applyPreviousResultAsHint = storm::solver::minimize(checkTask.getOptimizationDirection()) || // when minimizing, there can not be an EC within the maybestates + storm::utility::graph::performProb1A(this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(), this->parametricModel->getBackwardTransitions(), maybeStates, ~maybeStates).full(); + } + + // We know some bounds for the results + lowerResultBound = storm::utility::zero<ConstantType>(); + upperResultBound = storm::utility::one<ConstantType>(); + } + + template <typename SparseModelType, typename ConstantType> + void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) { + + // get the results for the subformula + storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel); + STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported"); + storm::storage::BitVector targetStates = std::move(propositionalChecker.check(checkTask.getFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); + + // get the maybeStates + storm::storage::BitVector infinityStates = storm::solver::minimize(checkTask.getOptimizationDirection()) ? + storm::utility::graph::performProb1E(this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(), this->parametricModel->getBackwardTransitions(), storm::storage::BitVector(this->parametricModel->getNumberOfStates(), true), targetStates) : + storm::utility::graph::performProb1A(this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(), this->parametricModel->getBackwardTransitions(), storm::storage::BitVector(this->parametricModel->getNumberOfStates(), true), targetStates); + infinityStates.complement(); + maybeStates = ~(targetStates | infinityStates); + + // set the result for all the non-maybe states + resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>()); + storm::utility::vector::setVectorValues(resultsForNonMaybeStates, infinityStates, storm::utility::infinity<ConstantType>()); + + // if there are maybestates, create the parameterLifter + if (!maybeStates.empty()) { + // Create the reward vector + STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel->hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model."); + + typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel->getRewardModel(checkTask.getRewardModel()) : this->parametricModel->getUniqueRewardModel(); + + std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel->getTransitionMatrix()); + + // We need to handle choices that lead to an infinity state. + // As a maybeState does not have reward infinity, a choice leading to an infinity state will never be picked. Hence, we can unselect the corresponding rows + storm::storage::BitVector selectedRows = this->parametricModel->getTransitionMatrix().getRowFilter(maybeStates, ~infinityStates); + + parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, selectedRows, maybeStates); + computePlayer1Matrix(selectedRows); + + // Check whether there is an EC consisting of maybestates + applyPreviousResultAsHint = !storm::solver::minimize(checkTask.getOptimizationDirection()) || // when maximizing, there can not be an EC within the maybestates + storm::utility::graph::performProb1A(this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(), this->parametricModel->getBackwardTransitions(), maybeStates, ~maybeStates).full(); + } + + // We only know a lower bound for the result + lowerResultBound = storm::utility::zero<ConstantType>(); + + } + + template <typename SparseModelType, typename ConstantType> + void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) { + + // Obtain the stepBound + stepBound = checkTask.getFormula().getBound().evaluateAsInt(); + if (checkTask.getFormula().isBoundStrict()) { + STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero."); + --(*stepBound); + } + STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive."); + + //Every state is a maybeState + maybeStates = storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getColumnCount(), true); + resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates()); + + // Create the reward vector + STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel->hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model."); + typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel->getRewardModel(checkTask.getRewardModel()) : this->parametricModel->getUniqueRewardModel(); + std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel->getTransitionMatrix()); + + parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(), true), maybeStates); + computePlayer1Matrix(); + + applyPreviousResultAsHint = false; + + // We only know a lower bound for the result + lowerResultBound = storm::utility::zero<ConstantType>(); + } + + template <typename SparseModelType, typename ConstantType> + storm::modelchecker::SparseInstantiationModelChecker<SparseModelType, ConstantType>& SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getInstantiationChecker() { + if (!instantiationChecker) { + instantiationChecker = std::make_unique<storm::modelchecker::SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>>(*this->parametricModel); + instantiationChecker->specifyFormula(this->currentCheckTask->template convertValueType<typename SparseModelType::ValueType>()); + instantiationChecker->setInstantiationsAreGraphPreserving(true); + } + return *instantiationChecker; + } + + template <typename SparseModelType, typename ConstantType> + std::unique_ptr<CheckResult> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) { + + if (maybeStates.empty()) { + return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(resultsForNonMaybeStates); + } + + parameterLifter->specifyRegion(region, dirForParameters); + + // Set up the solver + auto solver = solverFactory->create(player1Matrix, parameterLifter->getMatrix()); + if (storm::NumberTraits<ConstantType>::IsExact && dynamic_cast<storm::solver::StandardGameSolver<ConstantType>*>(solver.get())) { + STORM_LOG_INFO("Parameter Lifting: Setting solution method for exact Game Solver to policy iteration"); + auto* standardSolver = dynamic_cast<storm::solver::StandardGameSolver<ConstantType>*>(solver.get()); + auto settings = standardSolver->getSettings(); + settings.setSolutionMethod(storm::solver::StandardGameSolverSettings<ConstantType>::SolutionMethod::PolicyIteration); + standardSolver->setSettings(settings); + } + if (lowerResultBound) solver->setLowerBound(lowerResultBound.get()); + if (upperResultBound) solver->setUpperBound(upperResultBound.get()); + if (applyPreviousResultAsHint) { + solver->setTrackSchedulers(true); + x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>()); + if(storm::solver::minimize(dirForParameters) && minSchedChoices && player1SchedChoices) solver->setSchedulerHints(std::move(player1SchedChoices.get()), std::move(minSchedChoices.get())); + if(storm::solver::maximize(dirForParameters) && maxSchedChoices && player1SchedChoices) solver->setSchedulerHints(std::move(player1SchedChoices.get()), std::move(maxSchedChoices.get())); + } else { + x.assign(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>()); + } + if (this->currentCheckTask->isBoundSet() && this->currentCheckTask->getOptimizationDirection() == dirForParameters && solver->hasSchedulerHints()) { + // If we reach this point, we know that after applying the hints, the x-values can only become larger (if we maximize) or smaller (if we minimize). + std::unique_ptr<storm::solver::TerminationCondition<ConstantType>> termCond; + storm::storage::BitVector relevantStatesInSubsystem = this->currentCheckTask->isOnlyInitialStatesRelevantSet() ? this->parametricModel->getInitialStates() % maybeStates : storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true); + if (storm::solver::minimize(dirForParameters)) { + // Terminate if the value for ALL relevant states is already below the threshold + termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumBelowThreshold<ConstantType>> (relevantStatesInSubsystem, this->currentCheckTask->getBoundThreshold(), true, false); + } else { + // Terminate if the value for ALL relevant states is already above the threshold + termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumExceedsThreshold<ConstantType>> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), true); + } + solver->setTerminationCondition(std::move(termCond)); + } + + // Invoke the solver + if(stepBound) { + assert(*stepBound > 0); + solver->repeatedMultiply(this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, ¶meterLifter->getVector(), *stepBound); + } else { + solver->solveGame(this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, parameterLifter->getVector()); + if(applyPreviousResultAsHint) { + if(storm::solver::minimize(dirForParameters)) { + minSchedChoices = solver->getPlayer2SchedulerChoices(); + } else { + maxSchedChoices = solver->getPlayer2SchedulerChoices(); + } + player1SchedChoices = solver->getPlayer1SchedulerChoices(); + } + } + + // Get the result for the complete model (including maybestates) + std::vector<ConstantType> result = resultsForNonMaybeStates; + auto maybeStateResIt = x.begin(); + for(auto const& maybeState : maybeStates) { + result[maybeState] = *maybeStateResIt; + ++maybeStateResIt; + } + + return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(std::move(result)); + } + + template <typename SparseModelType, typename ConstantType> + void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::computePlayer1Matrix(boost::optional<storm::storage::BitVector> const& selectedRows) { + uint_fast64_t n = 0; + if (selectedRows) { + // only count selected rows + n = selectedRows->getNumberOfSetBits(); + } else { + for (auto const& maybeState : maybeStates) { + n += this->parametricModel->getTransitionMatrix().getRowGroupSize(maybeState); + } + } + + // The player 1 matrix is the identity matrix of size n with the row groups as given by the original matrix (potentially without unselected rows) + storm::storage::SparseMatrixBuilder<storm::storage::sparse::state_type> matrixBuilder(n, n, n, true, true, maybeStates.getNumberOfSetBits()); + uint_fast64_t p1MatrixRow = 0; + for (auto maybeState : maybeStates){ + matrixBuilder.newRowGroup(p1MatrixRow); + if (selectedRows) { + for (uint_fast64_t row = selectedRows->getNextSetIndex(this->parametricModel->getTransitionMatrix().getRowGroupIndices()[maybeState]); row < this->parametricModel->getTransitionMatrix().getRowGroupIndices()[maybeState + 1]; row = selectedRows->getNextSetIndex(row + 1)) { + matrixBuilder.addNextValue(p1MatrixRow, p1MatrixRow, storm::utility::one<storm::storage::sparse::state_type>()); + ++p1MatrixRow; + } + } else { + for (uint_fast64_t endOfGroup = p1MatrixRow + this->parametricModel->getTransitionMatrix().getRowGroupSize(maybeState); p1MatrixRow < endOfGroup; ++p1MatrixRow){ + matrixBuilder.addNextValue(p1MatrixRow, p1MatrixRow, storm::utility::one<storm::storage::sparse::state_type>()); + } + } + } + player1Matrix = matrixBuilder.build(); + } + + template <typename SparseModelType, typename ConstantType> + void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::reset() { + maybeStates.resize(0); + resultsForNonMaybeStates.clear(); + stepBound = boost::none; + instantiationChecker = nullptr; + player1Matrix = storm::storage::SparseMatrix<storm::storage::sparse::state_type>(); + parameterLifter = nullptr; + minSchedChoices = boost::none; + maxSchedChoices = boost::none; + x.clear(); + lowerResultBound = boost::none; + upperResultBound = boost::none; + applyPreviousResultAsHint = false; + } + + template <typename SparseModelType, typename ConstantType> + boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMinScheduler() { + if (!minSchedChoices) { + return boost::none; + } + + storm::storage::Scheduler<ConstantType> result(minSchedChoices->size()); + uint_fast64_t state = 0; + for (auto const& schedulerChoice : minSchedChoices.get()) { + result.setChoice(schedulerChoice, state); + ++state; + } + + return result; + } + + template <typename SparseModelType, typename ConstantType> + boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMaxScheduler() { + if (!maxSchedChoices) { + return boost::none; + } + + storm::storage::Scheduler<ConstantType> result(maxSchedChoices->size()); + uint_fast64_t state = 0; + for (auto const& schedulerChoice : maxSchedChoices.get()) { + result.setChoice(schedulerChoice, state); + ++state; + } + + return result; + } + + template <typename SparseModelType, typename ConstantType> + boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentPlayer1Scheduler() { + if (!player1SchedChoices) { + return boost::none; + } + + storm::storage::Scheduler<ConstantType> result(player1SchedChoices->size()); + uint_fast64_t state = 0; + for (auto const& schedulerChoice : player1SchedChoices.get()) { + result.setChoice(schedulerChoice, state); + ++state; + } + + return result; + } + + template class SparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>; + template class SparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>; + } +} diff --git a/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.h b/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.h new file mode 100644 index 000000000..346bb01f7 --- /dev/null +++ b/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.h @@ -0,0 +1,70 @@ +#pragma once + +#include <vector> +#include <memory> +#include <boost/optional.hpp> + +#include "storm-pars/transformer/ParameterLifter.h" +#include "storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h" +#include "storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.h" + +#include "storm/storage/BitVector.h" +#include "storm/storage/SparseMatrix.h" +#include "storm/storage/sparse/StateType.h" +#include "storm/solver/GameSolver.h" +#include "storm/storage/Scheduler.h" + +namespace storm { + namespace modelchecker { + + template <typename SparseModelType, typename ConstantType> + class SparseMdpParameterLiftingModelChecker : public SparseParameterLiftingModelChecker<SparseModelType, ConstantType> { + public: + SparseMdpParameterLiftingModelChecker(); + SparseMdpParameterLiftingModelChecker(std::unique_ptr<storm::solver::GameSolverFactory<ConstantType>>&& solverFactory); + virtual ~SparseMdpParameterLiftingModelChecker() = default; + + virtual bool canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const override; + virtual void specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) override; + void specify(std::shared_ptr<SparseModelType> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask, bool skipModelSimplification); + + boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMinScheduler(); + boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMaxScheduler(); + boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentPlayer1Scheduler(); + + protected: + + virtual void specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) override; + virtual void specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) override; + virtual void specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) override; + virtual void specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) override; + + virtual storm::modelchecker::SparseInstantiationModelChecker<SparseModelType, ConstantType>& getInstantiationChecker() override; + + virtual std::unique_ptr<CheckResult> computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) override; + + virtual void reset() override; + + + private: + void computePlayer1Matrix(boost::optional<storm::storage::BitVector> const& selectedRows = boost::none); + + storm::storage::BitVector maybeStates; + std::vector<ConstantType> resultsForNonMaybeStates; + boost::optional<uint_fast64_t> stepBound; + + std::unique_ptr<storm::modelchecker::SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>> instantiationChecker; + + storm::storage::SparseMatrix<storm::storage::sparse::state_type> player1Matrix; + std::unique_ptr<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>> parameterLifter; + std::unique_ptr<storm::solver::GameSolverFactory<ConstantType>> solverFactory; + + // Results from the most recent solver call. + boost::optional<std::vector<uint_fast64_t>> minSchedChoices, maxSchedChoices; + boost::optional<std::vector<uint_fast64_t>> player1SchedChoices; + std::vector<ConstantType> x; + boost::optional<ConstantType> lowerResultBound, upperResultBound; + bool applyPreviousResultAsHint; + }; + } +} diff --git a/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.cpp new file mode 100644 index 000000000..17610df87 --- /dev/null +++ b/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.cpp @@ -0,0 +1,176 @@ +#include "storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h" + +#include "storm/adapters/RationalFunctionAdapter.h" +#include "storm/logic/FragmentSpecification.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" +#include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/Mdp.h" +#include "storm/models/sparse/StandardRewardModel.h" + +#include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/NotSupportedException.h" + +namespace storm { + namespace modelchecker { + + template <typename SparseModelType, typename ConstantType> + SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseParameterLiftingModelChecker() { + //Intentionally left empty + } + + template <typename SparseModelType, typename ConstantType> + void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) { + + currentFormula = checkTask.getFormula().asSharedPointer(); + currentCheckTask = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, ConstantType>>(checkTask.substituteFormula(*currentFormula).template convertValueType<ConstantType>()); + + if(currentCheckTask->getFormula().isProbabilityOperatorFormula()) { + auto const& probOpFormula = currentCheckTask->getFormula().asProbabilityOperatorFormula(); + if(probOpFormula.getSubformula().isBoundedUntilFormula()) { + specifyBoundedUntilFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asBoundedUntilFormula())); + } else if(probOpFormula.getSubformula().isUntilFormula()) { + specifyUntilFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asUntilFormula())); + } else if (probOpFormula.getSubformula().isEventuallyFormula()) { + specifyReachabilityProbabilityFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asEventuallyFormula())); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); + } + } else if (currentCheckTask->getFormula().isRewardOperatorFormula()) { + auto const& rewOpFormula = currentCheckTask->getFormula().asRewardOperatorFormula(); + if(rewOpFormula.getSubformula().isEventuallyFormula()) { + specifyReachabilityRewardFormula(currentCheckTask->substituteFormula(rewOpFormula.getSubformula().asEventuallyFormula())); + } else if (rewOpFormula.getSubformula().isCumulativeRewardFormula()) { + specifyCumulativeRewardFormula(currentCheckTask->substituteFormula(rewOpFormula.getSubformula().asCumulativeRewardFormula())); + } + } + } + + template <typename SparseModelType, typename ConstantType> + RegionResult SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::analyzeRegion(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionResult const& initialResult, bool sampleVerticesOfRegion) { + + STORM_LOG_THROW(this->currentCheckTask->isOnlyInitialStatesRelevantSet(), storm::exceptions::NotSupportedException, "Analyzing regions with parameter lifting requires a property where only the value in the initial states is relevant."); + STORM_LOG_THROW(this->currentCheckTask->isBoundSet(), storm::exceptions::NotSupportedException, "Analyzing regions with parameter lifting requires a bounded property."); + STORM_LOG_THROW(this->parametricModel->getInitialStates().getNumberOfSetBits() == 1, storm::exceptions::NotSupportedException, "Analyzing regions with parameter lifting requires a model with a single initial state."); + + RegionResult result = initialResult; + + // Check if we need to check the formula on one point to decide whether to show AllSat or AllViolated + if (result == RegionResult::Unknown) { + result = getInstantiationChecker().check(region.getCenterPoint())->asExplicitQualitativeCheckResult()[*this->parametricModel->getInitialStates().begin()] ? RegionResult::CenterSat : RegionResult::CenterViolated; + } + + // try to prove AllSat or AllViolated, depending on the obtained result + if (result == RegionResult::ExistsSat || result == RegionResult::CenterSat) { + // show AllSat: + storm::solver::OptimizationDirection parameterOptimizationDirection = isLowerBound(this->currentCheckTask->getBound().comparisonType) ? storm::solver::OptimizationDirection::Minimize : storm::solver::OptimizationDirection::Maximize; + if (this->check(region, parameterOptimizationDirection)->asExplicitQualitativeCheckResult()[*this->parametricModel->getInitialStates().begin()]) { + result = RegionResult::AllSat; + } else if (sampleVerticesOfRegion) { + result = sampleVertices(region, result); + } + } else if (result == RegionResult::ExistsViolated || result == RegionResult::CenterViolated) { + // show AllViolated: + storm::solver::OptimizationDirection parameterOptimizationDirection = isLowerBound(this->currentCheckTask->getBound().comparisonType) ? storm::solver::OptimizationDirection::Maximize : storm::solver::OptimizationDirection::Minimize; + if (!this->check(region, parameterOptimizationDirection)->asExplicitQualitativeCheckResult()[*this->parametricModel->getInitialStates().begin()]) { + result = RegionResult::AllViolated; + } else if (sampleVerticesOfRegion) { + result = sampleVertices(region, result); + } + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "When analyzing a region, an invalid initial result was given: " << initialResult); + } + return result; + } + + template <typename SparseModelType, typename ConstantType> + RegionResult SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::sampleVertices(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionResult const& initialResult) { + RegionResult result = initialResult; + + if (result == RegionResult::AllSat || result == RegionResult::AllViolated) { + return result; + } + + bool hasSatPoint = result == RegionResult::ExistsSat || result == RegionResult::CenterSat; + bool hasViolatedPoint = result == RegionResult::ExistsViolated || result == RegionResult::CenterViolated; + + // Check if there is a point in the region for which the property is satisfied + auto vertices = region.getVerticesOfRegion(region.getVariables()); + auto vertexIt = vertices.begin(); + while (vertexIt != vertices.end() && !(hasSatPoint && hasViolatedPoint)) { + if (getInstantiationChecker().check(*vertexIt)->asExplicitQualitativeCheckResult()[*this->parametricModel->getInitialStates().begin()]) { + hasSatPoint = true; + } else { + hasViolatedPoint = true; + } + ++vertexIt; + } + + if (hasSatPoint) { + if (hasViolatedPoint) { + result = RegionResult::ExistsBoth; + } else if (result != RegionResult::CenterSat) { + result = RegionResult::ExistsSat; + } + } else if (hasViolatedPoint && result != RegionResult::CenterViolated) { + result = RegionResult::ExistsViolated; + } + + return result; + } + + + template <typename SparseModelType, typename ConstantType> + std::unique_ptr<CheckResult> SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::check(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) { + auto quantitativeResult = computeQuantitativeValues(region, dirForParameters); + if(currentCheckTask->getFormula().hasQuantitativeResult()) { + return quantitativeResult; + } else { + return quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>()); + } + } + + template <typename SparseModelType, typename ConstantType> + SparseModelType const& SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::getConsideredParametricModel() const { + return *parametricModel; + } + + template <typename SparseModelType, typename ConstantType> + CheckTask<storm::logic::Formula, ConstantType> const& SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentCheckTask() const { + return *currentCheckTask; + } + + template <typename SparseModelType, typename ConstantType> + void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyBoundedUntilFormula(CheckTask<logic::BoundedUntilFormula, ConstantType> const& checkTask) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); + } + + template <typename SparseModelType, typename ConstantType> + void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyUntilFormula(CheckTask<logic::UntilFormula, ConstantType> const& checkTask) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); + } + + template <typename SparseModelType, typename ConstantType> + void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityProbabilityFormula(CheckTask<logic::EventuallyFormula, ConstantType> const& checkTask) { + // transform to until formula + auto untilFormula = std::make_shared<storm::logic::UntilFormula const>(storm::logic::Formula::getTrueFormula(), checkTask.getFormula().getSubformula().asSharedPointer()); + specifyUntilFormula(currentCheckTask->substituteFormula(*untilFormula)); + } + + template <typename SparseModelType, typename ConstantType> + void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityRewardFormula(CheckTask<logic::EventuallyFormula, ConstantType> const& checkTask) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); + } + + template <typename SparseModelType, typename ConstantType> + void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyCumulativeRewardFormula(CheckTask<logic::CumulativeRewardFormula, ConstantType> const& checkTask) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); + } + + template class SparseParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>; + template class SparseParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>; + template class SparseParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>; + template class SparseParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>; + + } +} diff --git a/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h b/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h new file mode 100644 index 000000000..b8abd518c --- /dev/null +++ b/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h @@ -0,0 +1,83 @@ +#pragma once + +#include "storm-pars/modelchecker/region/RegionModelChecker.h" +#include "storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h" +#include "storm-pars/storage/ParameterRegion.h" +#include "storm-pars/utility/parametric.h" + +#include "storm/logic/Formulas.h" +#include "storm/modelchecker/CheckTask.h" +#include "storm/modelchecker/results/CheckResult.h" +#include "storm/solver/OptimizationDirection.h" + +namespace storm { + namespace modelchecker { + + /*! + * Class to approximatively check a formula on a parametric model for all parameter valuations within a region + * It is assumed that all considered valuations are graph-preserving and well defined, i.e., + * * all non-const transition probabilities evaluate to some non-zero value + * * the sum of all outgoing transitions is one + */ + template <typename SparseModelType, typename ConstantType> + class SparseParameterLiftingModelChecker : public RegionModelChecker<typename SparseModelType::ValueType> { + public: + SparseParameterLiftingModelChecker(); + virtual ~SparseParameterLiftingModelChecker() = default; + + + /*! + * Analyzes the given region by means of parameter lifting. + * We first check whether there is one point in the region for which the property is satisfied/violated. + * If the given initialResults already indicates that there is such a point, this step is skipped. + * Then, we check whether ALL points in the region violate/satisfy the property + * + */ + virtual RegionResult analyzeRegion(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionResult const& initialResult = RegionResult::Unknown, bool sampleVerticesOfRegion = false) override; + + /*! + * Analyzes the 2^#parameters corner points of the given region. + */ + RegionResult sampleVertices(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionResult const& initialResult = RegionResult::Unknown); + + /*! + * Checks the specified formula on the given region by applying parameter lifting (Parameter choices are lifted to nondeterministic choices) + * This yields a (sound) approximative model checking result. + + * @param region the region on which parameter lifting is applied + * @param dirForParameters The optimization direction for the parameter choices. If this is, e.g., minimize, then the returned result will be a lower bound for all results induced by the parameter evaluations inside the region. + */ + std::unique_ptr<CheckResult> check(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters); + + + SparseModelType const& getConsideredParametricModel() const; + CheckTask<storm::logic::Formula, ConstantType> const& getCurrentCheckTask() const; + + protected: + void specifyFormula(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask); + + // Resets all data that correspond to the currently defined property. + virtual void reset() = 0; + + virtual void specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask); + virtual void specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask); + virtual void specifyReachabilityProbabilityFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask); + virtual void specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask); + virtual void specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask); + + + virtual storm::modelchecker::SparseInstantiationModelChecker<SparseModelType, ConstantType>& getInstantiationChecker() = 0; + + virtual std::unique_ptr<CheckResult> computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) = 0; + + + std::shared_ptr<SparseModelType> parametricModel; + std::unique_ptr<CheckTask<storm::logic::Formula, ConstantType>> currentCheckTask; + + private: + // store the current formula. Note that currentCheckTask only stores a reference to the formula. + std::shared_ptr<storm::logic::Formula const> currentFormula; + + }; + } +} diff --git a/src/storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.cpp new file mode 100644 index 000000000..2ab8c3103 --- /dev/null +++ b/src/storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.cpp @@ -0,0 +1,67 @@ +#include "storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.h" +#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h" + +#include "storm/models/sparse/Dtmc.h" +#include "storm/utility/macros.h" + +#include "storm/exceptions/UnexpectedException.h" + +namespace storm { + namespace modelchecker { + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + ValidatingSparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::ValidatingSparseDtmcParameterLiftingModelChecker() { + // Intentionally left empty + } + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + void ValidatingSparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) { + STORM_LOG_ASSERT(this->canHandle(parametricModel, checkTask), "specified model and formula can not be handled by this."); + + auto dtmc = parametricModel->template as<SparseModelType>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier<SparseModelType>(*dtmc); + + if (!simplifier.simplify(checkTask.getFormula())) { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull."); + } + + auto simplifiedTask = checkTask.substituteFormula(*simplifier.getSimplifiedFormula()); + + impreciseChecker.specify(simplifier.getSimplifiedModel(), simplifiedTask, true); + preciseChecker.specify(simplifier.getSimplifiedModel(), simplifiedTask, true); + } + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType>& ValidatingSparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getImpreciseChecker() { + return impreciseChecker; + } + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType> const& ValidatingSparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getImpreciseChecker() const { + return impreciseChecker; + } + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + SparseParameterLiftingModelChecker<SparseModelType, PreciseType>& ValidatingSparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getPreciseChecker() { + return preciseChecker; + } + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + SparseParameterLiftingModelChecker<SparseModelType, PreciseType> const& ValidatingSparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getPreciseChecker() const { + return preciseChecker; + } + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + void ValidatingSparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::applyHintsToPreciseChecker() { + + if (impreciseChecker.getCurrentMaxScheduler()) { + preciseChecker.getCurrentMaxScheduler() = impreciseChecker.getCurrentMaxScheduler()->template toValueType<PreciseType>(); + } + if (impreciseChecker.getCurrentMinScheduler()) { + preciseChecker.getCurrentMinScheduler() = impreciseChecker.getCurrentMinScheduler()->template toValueType<PreciseType>(); + } + } + + template class ValidatingSparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber>; + } +} diff --git a/src/storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.h b/src/storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.h new file mode 100644 index 000000000..9fd696be2 --- /dev/null +++ b/src/storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.h @@ -0,0 +1,31 @@ +#pragma once + +#include "storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.h" +#include "storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h" + +namespace storm { + namespace modelchecker { + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + class ValidatingSparseDtmcParameterLiftingModelChecker : public ValidatingSparseParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType> { + public: + ValidatingSparseDtmcParameterLiftingModelChecker(); + virtual ~ValidatingSparseDtmcParameterLiftingModelChecker() = default; + + virtual void specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) override; + + protected: + virtual SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType>& getImpreciseChecker() override; + virtual SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType> const& getImpreciseChecker() const override; + virtual SparseParameterLiftingModelChecker<SparseModelType, PreciseType>& getPreciseChecker() override; + virtual SparseParameterLiftingModelChecker<SparseModelType, PreciseType> const& getPreciseChecker() const override; + + virtual void applyHintsToPreciseChecker() override ; + + private: + SparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType> impreciseChecker; + SparseDtmcParameterLiftingModelChecker<SparseModelType, PreciseType> preciseChecker; + + }; + } +} diff --git a/src/storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.cpp new file mode 100644 index 000000000..014cf6267 --- /dev/null +++ b/src/storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.cpp @@ -0,0 +1,71 @@ +#include "storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.h" +#include "storm-pars/transformer/SparseParametricMdpSimplifier.h" + +#include "storm/models/sparse/Mdp.h" +#include "storm/utility/macros.h" + +#include "storm/exceptions/UnexpectedException.h" + +namespace storm { + namespace modelchecker { + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + ValidatingSparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::ValidatingSparseMdpParameterLiftingModelChecker() { + // Intentionally left empty + } + + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + void ValidatingSparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) { + STORM_LOG_ASSERT(this->canHandle(parametricModel, checkTask), "specified model and formula can not be handled by this."); + + auto mdp = parametricModel->template as<SparseModelType>(); + auto simplifier = storm::transformer::SparseParametricMdpSimplifier<SparseModelType>(*mdp); + + if (!simplifier.simplify(checkTask.getFormula())) { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull."); + } + + auto simplifiedTask = checkTask.substituteFormula(*simplifier.getSimplifiedFormula()); + + impreciseChecker.specify(simplifier.getSimplifiedModel(), simplifiedTask, true); + preciseChecker.specify(simplifier.getSimplifiedModel(), simplifiedTask, true); + } + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType>& ValidatingSparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getImpreciseChecker() { + return impreciseChecker; + } + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType> const& ValidatingSparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getImpreciseChecker() const { + return impreciseChecker; + } + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + SparseParameterLiftingModelChecker<SparseModelType, PreciseType>& ValidatingSparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getPreciseChecker() { + return preciseChecker; + } + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + SparseParameterLiftingModelChecker<SparseModelType, PreciseType> const& ValidatingSparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getPreciseChecker() const { + return preciseChecker; + } + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + void ValidatingSparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::applyHintsToPreciseChecker() { + + if (impreciseChecker.getCurrentMaxScheduler()) { + preciseChecker.getCurrentMaxScheduler() = impreciseChecker.getCurrentMaxScheduler()->template toValueType<PreciseType>(); + } + if (impreciseChecker.getCurrentMinScheduler()) { + preciseChecker.getCurrentMinScheduler() = impreciseChecker.getCurrentMinScheduler()->template toValueType<PreciseType>(); + } + if (impreciseChecker.getCurrentPlayer1Scheduler()) { + preciseChecker.getCurrentPlayer1Scheduler() = impreciseChecker.getCurrentPlayer1Scheduler()->template toValueType<PreciseType>(); + } + } + + template class ValidatingSparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber>; + } +} diff --git a/src/storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.h b/src/storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.h new file mode 100644 index 000000000..1f56818c6 --- /dev/null +++ b/src/storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.h @@ -0,0 +1,31 @@ +#pragma once + +#include "storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.h" +#include "storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.h" + +namespace storm { + namespace modelchecker { + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + class ValidatingSparseMdpParameterLiftingModelChecker : public ValidatingSparseParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType> { + public: + ValidatingSparseMdpParameterLiftingModelChecker(); + virtual ~ValidatingSparseMdpParameterLiftingModelChecker() = default; + + virtual void specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) override; + + protected: + virtual SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType>& getImpreciseChecker() override; + virtual SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType> const& getImpreciseChecker() const override; + virtual SparseParameterLiftingModelChecker<SparseModelType, PreciseType>& getPreciseChecker() override; + virtual SparseParameterLiftingModelChecker<SparseModelType, PreciseType> const& getPreciseChecker() const override; + + virtual void applyHintsToPreciseChecker() override ; + + private: + SparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType> impreciseChecker; + SparseMdpParameterLiftingModelChecker<SparseModelType, PreciseType> preciseChecker; + + }; + } +} diff --git a/src/storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.cpp new file mode 100644 index 000000000..d3dabab63 --- /dev/null +++ b/src/storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.cpp @@ -0,0 +1,73 @@ +#include "storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.h" + +#include "storm/adapters/RationalFunctionAdapter.h" +#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/CoreSettings.h" +#include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/Mdp.h" + +namespace storm { + namespace modelchecker { + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + ValidatingSparseParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::ValidatingSparseParameterLiftingModelChecker() : numOfWrongRegions(0) { + // Intentionally left empty + } + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + ValidatingSparseParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::~ValidatingSparseParameterLiftingModelChecker() { + if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) { + STORM_PRINT_AND_LOG("Validating Parameter Lifting Model Checker detected " << numOfWrongRegions << " regions where the imprecise method was wrong." << std::endl); + } + } + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + bool ValidatingSparseParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const { + return getImpreciseChecker().canHandle(parametricModel, checkTask) && getPreciseChecker().canHandle(parametricModel, checkTask); + }; + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + RegionResult ValidatingSparseParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::analyzeRegion(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionResult const& initialResult, bool sampleVerticesOfRegion) { + + RegionResult currentResult = getImpreciseChecker().analyzeRegion(region, initialResult); + + if (currentResult == RegionResult::AllSat || currentResult == RegionResult::AllViolated) { + applyHintsToPreciseChecker(); + + storm::solver::OptimizationDirection parameterOptDir = getPreciseChecker().getCurrentCheckTask().getOptimizationDirection(); + if (currentResult == RegionResult::AllViolated) { + parameterOptDir = storm::solver::invert(parameterOptDir); + } + + bool preciseResult = getPreciseChecker().check(region, parameterOptDir)->asExplicitQualitativeCheckResult()[*getPreciseChecker().getConsideredParametricModel().getInitialStates().begin()]; + bool preciseResultAgrees = preciseResult == (currentResult == RegionResult::AllSat); + + if (!preciseResultAgrees) { + // Imprecise result is wrong! + currentResult = RegionResult::Unknown; + ++numOfWrongRegions; + + // Check the other direction + parameterOptDir = storm::solver::invert(parameterOptDir); + preciseResult = getPreciseChecker().check(region, parameterOptDir)->asExplicitQualitativeCheckResult()[*getPreciseChecker().getConsideredParametricModel().getInitialStates().begin()]; + if (preciseResult && parameterOptDir == getPreciseChecker().getCurrentCheckTask().getOptimizationDirection()) { + currentResult = RegionResult::AllSat; + } else if (!preciseResult && parameterOptDir == storm::solver::invert(getPreciseChecker().getCurrentCheckTask().getOptimizationDirection())) { + currentResult = RegionResult::AllViolated; + } + } + } + + if (sampleVerticesOfRegion && currentResult != RegionResult::AllSat && currentResult != RegionResult::AllViolated) { + currentResult = getPreciseChecker().sampleVertices(region, currentResult); + } + + return currentResult; + } + + template class ValidatingSparseParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber>; + template class ValidatingSparseParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber>; + + } +} diff --git a/src/storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.h b/src/storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.h new file mode 100644 index 000000000..7f9789ebf --- /dev/null +++ b/src/storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.h @@ -0,0 +1,44 @@ +#pragma once + +#include "storm-pars/modelchecker/region/RegionModelChecker.h" +#include "storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h" +#include "storm-pars/storage/ParameterRegion.h" +#include "storm/utility/NumberTraits.h" + +namespace storm { + namespace modelchecker { + + template <typename SparseModelType, typename ImpreciseType, typename PreciseType> + class ValidatingSparseParameterLiftingModelChecker : public RegionModelChecker<typename SparseModelType::ValueType> { + static_assert(storm::NumberTraits<PreciseType>::IsExact, "Specified type for exact computations is not exact."); + + public: + ValidatingSparseParameterLiftingModelChecker(); + virtual ~ValidatingSparseParameterLiftingModelChecker(); + + virtual bool canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const override; + + /*! + * Analyzes the given region by means of parameter lifting. + * We first apply unsound solution methods (standard value iteratio with doubles) and then validate the obtained result + * by means of exact and soud methods. + */ + virtual RegionResult analyzeRegion(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionResult const& initialResult = RegionResult::Unknown, bool sampleVerticesOfRegion = false) override; + + protected: + + virtual SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType>& getImpreciseChecker() = 0; + virtual SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType> const& getImpreciseChecker() const = 0; + virtual SparseParameterLiftingModelChecker<SparseModelType, PreciseType>& getPreciseChecker() = 0; + virtual SparseParameterLiftingModelChecker<SparseModelType, PreciseType> const& getPreciseChecker() const = 0; + + virtual void applyHintsToPreciseChecker() = 0; + + private: + + // Information for statistics + uint_fast64_t numOfWrongRegions; + + }; + } +} diff --git a/src/storm-pars/modelchecker/results/RegionCheckResult.cpp b/src/storm-pars/modelchecker/results/RegionCheckResult.cpp new file mode 100644 index 000000000..2759034e9 --- /dev/null +++ b/src/storm-pars/modelchecker/results/RegionCheckResult.cpp @@ -0,0 +1,117 @@ +#include "storm-pars/modelchecker/results/RegionCheckResult.h" + +#include <map> + +#include "storm/adapters/RationalFunctionAdapter.h" +#include "storm/utility/constants.h" +#include "storm/utility/macros.h" + +namespace storm { + namespace modelchecker { + + template<typename ValueType> + RegionCheckResult<ValueType>::RegionCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>> const& regionResults) : regionResults(regionResults) { + auto overallArea = storm::utility::zero<typename storm::storage::ParameterRegion<ValueType>::CoefficientType>(); + for (auto const& res : this->regionResults) { + overallArea += res.first.area(); + } + initFractions(overallArea); + } + + template<typename ValueType> + RegionCheckResult<ValueType>::RegionCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>>&& regionResults) : regionResults(std::move(regionResults)) { + auto overallArea = storm::utility::zero<typename storm::storage::ParameterRegion<ValueType>::CoefficientType>(); + for (auto const& res : this->regionResults) { + overallArea += res.first.area(); + } + initFractions(overallArea); + } + + template<typename ValueType> + bool RegionCheckResult<ValueType>::isRegionCheckResult() const { + return true; + } + + template<typename ValueType> + bool RegionCheckResult<ValueType>::isRegionRefinementCheckResult() const { + return false; + } + + template<typename ValueType> + std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>> const& RegionCheckResult<ValueType>::getRegionResults() const { + return regionResults; + } + + template<typename ValueType> + typename storm::storage::ParameterRegion<ValueType>::CoefficientType const& RegionCheckResult<ValueType>::getSatFraction() const { + return satFraction; + } + + template<typename ValueType> + typename storm::storage::ParameterRegion<ValueType>::CoefficientType const& RegionCheckResult<ValueType>::getUnsatFraction() const { + return unsatFraction; + } + + template<typename ValueType> + std::ostream& RegionCheckResult<ValueType>::writeToStream(std::ostream& out) const { + writeCondensedToStream(out); + out << std::endl << "Region results: " << std::endl; + for (auto const& res : this->regionResults) { + out << res.first.toString() << ": \t" << res.second << std::endl; + } + return out; + } + + template<typename ValueType> + std::ostream& RegionCheckResult<ValueType>::writeCondensedToStream(std::ostream& out) const { + double satPercent = storm::utility::convertNumber<double>(satFraction) * 100.0; + double unsatPercent = storm::utility::convertNumber<double>(unsatFraction) * 100.0; + auto oneHundred = storm::utility::convertNumber<typename storm::storage::ParameterRegion<ValueType>::CoefficientType>(100.0); + auto one = storm::utility::convertNumber<typename storm::storage::ParameterRegion<ValueType>::CoefficientType>(1.0); + out << " Fraction of satisfied area: " << satPercent << "%" << std::endl; + out << "Fraction of unsatisfied area: " << unsatPercent << "%" << std::endl; + out << " Unknown fraction: " << (100.0 - satPercent - unsatPercent) << "%" << std::endl; + out << " Total number of regions: " << regionResults.size() << std::endl; + std::map<storm::modelchecker::RegionResult, uint_fast64_t> counters; + for (auto const& res : this->regionResults) { + ++counters[res.second]; + } + for (auto const& counter : counters) { + out << std::setw(28) << counter.first << ": " << counter.second << std::endl; + } + return out; + } + + template<typename ValueType> + std::ostream& RegionCheckResult<ValueType>::writeIllustrationToStream(std::ostream& out) const { + STORM_LOG_WARN("Writing illustration of region check result to a stream is not implemented."); + return out; + } + + template<typename ValueType> + void RegionCheckResult<ValueType>::initFractions(typename storm::storage::ParameterRegion<ValueType>::CoefficientType const& overallArea) { + auto satArea = storm::utility::zero<typename storm::storage::ParameterRegion<ValueType>::CoefficientType>(); + auto unsatArea = storm::utility::zero<typename storm::storage::ParameterRegion<ValueType>::CoefficientType>(); + for (auto const& res : this->regionResults) { + if (res.second == storm::modelchecker::RegionResult::AllSat) { + satArea += res.first.area(); + } else if (res.second == storm::modelchecker::RegionResult::AllViolated) { + unsatArea += res.first.area(); + } + } + satFraction = satArea / overallArea; + unsatFraction = unsatArea / overallArea; + } + + template<typename ValueType> + void RegionCheckResult<ValueType>::filter(QualitativeCheckResult const& filter) { + // Filtering has no effect as we only store the result w.r.t. a single state anyway. + // Hence, this is intentionally left empty. + } + + +#ifdef STORM_HAVE_CARL + template class RegionCheckResult<storm::RationalFunction>; +#endif + } +} diff --git a/src/storm-pars/modelchecker/results/RegionCheckResult.h b/src/storm-pars/modelchecker/results/RegionCheckResult.h new file mode 100644 index 000000000..7bb144cf6 --- /dev/null +++ b/src/storm-pars/modelchecker/results/RegionCheckResult.h @@ -0,0 +1,40 @@ +#pragma once + +#include <vector> + +#include "storm/modelchecker/results/CheckResult.h" +#include "storm-pars/modelchecker/region/RegionResult.h" +#include "storm-pars/storage/ParameterRegion.h" + +namespace storm { + namespace modelchecker { + template<typename ValueType> + class RegionCheckResult : public CheckResult { + public: + + RegionCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>> const& regionResults); + RegionCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>>&& regionResults); + virtual ~RegionCheckResult() = default; + + virtual bool isRegionCheckResult() const; + virtual bool isRegionRefinementCheckResult() const; + + std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>> const& getRegionResults() const; + typename storm::storage::ParameterRegion<ValueType>::CoefficientType const& getSatFraction() const; + typename storm::storage::ParameterRegion<ValueType>::CoefficientType const& getUnsatFraction() const; + + virtual std::ostream& writeToStream(std::ostream& out) const override; + virtual std::ostream& writeCondensedToStream(std::ostream& out) const; + virtual std::ostream& writeIllustrationToStream(std::ostream& out) const; + + virtual void filter(QualitativeCheckResult const& filter) override; + + protected: + virtual void initFractions(typename storm::storage::ParameterRegion<ValueType>::CoefficientType const& overallArea); + + std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>> regionResults; + typename storm::storage::ParameterRegion<ValueType>::CoefficientType satFraction, unsatFraction; + + }; + } +} diff --git a/src/storm-pars/modelchecker/results/RegionRefinementCheckResult.cpp b/src/storm-pars/modelchecker/results/RegionRefinementCheckResult.cpp new file mode 100644 index 000000000..3cf8d1e1d --- /dev/null +++ b/src/storm-pars/modelchecker/results/RegionRefinementCheckResult.cpp @@ -0,0 +1,100 @@ +#include "storm-pars/modelchecker/results/RegionRefinementCheckResult.h" + +#include <map> + +#include "storm/adapters/RationalFunctionAdapter.h" +#include "storm/utility/constants.h" +#include "storm/utility/macros.h" + +namespace storm { + namespace modelchecker { + + template<typename ValueType> + RegionRefinementCheckResult<ValueType>::RegionRefinementCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>> const& regionResults, storm::storage::ParameterRegion<ValueType> const& parameterSpace) : RegionCheckResult<ValueType>(regionResults), parameterSpace(parameterSpace) { + this->initFractions(this->parameterSpace.area()); + } + + + template<typename ValueType> + RegionRefinementCheckResult<ValueType>::RegionRefinementCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>>&& regionResults, storm::storage::ParameterRegion<ValueType>&& parameterSpace) : RegionCheckResult<ValueType>(std::move(regionResults)), parameterSpace(std::move(parameterSpace)) { + this->initFractions(this->parameterSpace.area()); + } + + template<typename ValueType> + bool RegionRefinementCheckResult<ValueType>::isRegionRefinementCheckResult() const { + return true; + } + + template<typename ValueType> + storm::storage::ParameterRegion<ValueType> const& RegionRefinementCheckResult<ValueType>::getParameterSpace() const { + return parameterSpace; + } + + template<typename ValueType> + std::ostream& RegionRefinementCheckResult<ValueType>::writeIllustrationToStream(std::ostream& out) const { + if (this->getParameterSpace().getVariables().size() == 2) { + + typedef typename storm::storage::ParameterRegion<ValueType>::CoefficientType CoefficientType; + auto x = *this->getParameterSpace().getVariables().begin(); + auto y = *(this->getParameterSpace().getVariables().rbegin()); + + uint_fast64_t const sizeX = 128; + uint_fast64_t const sizeY = 64; + + out << "Region refinement Check result (visualization):" << std::endl; + out << " \t x-axis: " << x << " \t y-axis: " << y << " \t S=safe, [ ]=unsafe, -=ambiguous " << std::endl; + for (uint_fast64_t i = 0; i < sizeX+2; ++i) out << "#"; out << std::endl; + + CoefficientType deltaX = (getParameterSpace().getUpperBoundary(x) - getParameterSpace().getLowerBoundary(x)) / storm::utility::convertNumber<CoefficientType>(sizeX); + CoefficientType deltaY = (getParameterSpace().getUpperBoundary(y) - getParameterSpace().getLowerBoundary(y)) / storm::utility::convertNumber<CoefficientType>(sizeY); + CoefficientType printedRegionArea = deltaX * deltaY; + for (CoefficientType yUpper = getParameterSpace().getUpperBoundary(y); yUpper != getParameterSpace().getLowerBoundary(y); yUpper -= deltaY) { + CoefficientType yLower = yUpper - deltaY; + out << "#"; + for (CoefficientType xLower = getParameterSpace().getLowerBoundary(x); xLower != getParameterSpace().getUpperBoundary(x); xLower += deltaX) { + CoefficientType xUpper = xLower + deltaX; + bool currRegionSafe = false; + bool currRegionUnSafe = false; + bool currRegionComplete = false; + CoefficientType coveredArea = storm::utility::zero<CoefficientType>(); + for (auto const& r : this->getRegionResults()) { + CoefficientType interesctionSizeY = std::min(yUpper, r.first.getUpperBoundary(y)) - std::max(yLower, r.first.getLowerBoundary(y)); + interesctionSizeY = std::max(interesctionSizeY, storm::utility::zero<CoefficientType>()); + CoefficientType interesctionSizeX = std::min(xUpper, r.first.getUpperBoundary(x)) - std::max(xLower, r.first.getLowerBoundary(x)); + interesctionSizeX = std::max(interesctionSizeX, storm::utility::zero<CoefficientType>()); + CoefficientType instersectionArea = interesctionSizeY * interesctionSizeX; + if(!storm::utility::isZero(instersectionArea)) { + currRegionSafe = currRegionSafe || r.second == storm::modelchecker::RegionResult::AllSat; + currRegionUnSafe = currRegionUnSafe || r.second == storm::modelchecker::RegionResult::AllViolated; + coveredArea += instersectionArea; + if(currRegionSafe && currRegionUnSafe) { + break; + } + if(coveredArea == printedRegionArea) { + currRegionComplete = true; + break; + } + } + } + if (currRegionComplete && currRegionSafe && !currRegionUnSafe) { + out << "S"; + } else if (currRegionComplete && currRegionUnSafe && !currRegionSafe) { + out << " "; + } else { + out << "-"; + } + } + out << "#" << std::endl; + } + for (uint_fast64_t i = 0; i < sizeX+2; ++i) out << "#"; out << std::endl; + } else { + STORM_LOG_WARN("Writing illustration of region check result to a stream is only implemented for two parameters."); + } + return out; + } + +#ifdef STORM_HAVE_CARL + template class RegionRefinementCheckResult<storm::RationalFunction>; +#endif + } +} diff --git a/src/storm-pars/modelchecker/results/RegionRefinementCheckResult.h b/src/storm-pars/modelchecker/results/RegionRefinementCheckResult.h new file mode 100644 index 000000000..8b37afcca --- /dev/null +++ b/src/storm-pars/modelchecker/results/RegionRefinementCheckResult.h @@ -0,0 +1,30 @@ +#pragma once + +#include <vector> + +#include "storm-pars/modelchecker/results/RegionCheckResult.h" +#include "storm-pars/modelchecker/region/RegionResult.h" +#include "storm-pars/storage/ParameterRegion.h" + +namespace storm { + namespace modelchecker { + template<typename ValueType> + class RegionRefinementCheckResult : public RegionCheckResult<ValueType> { + public: + + RegionRefinementCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>> const& regionResults, storm::storage::ParameterRegion<ValueType> const& parameterSpace); + RegionRefinementCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>>&& regionResults, storm::storage::ParameterRegion<ValueType>&& parameterSpace); + virtual ~RegionRefinementCheckResult() = default; + + virtual bool isRegionRefinementCheckResult() const override; + + storm::storage::ParameterRegion<ValueType> const& getParameterSpace() const; + + virtual std::ostream& writeIllustrationToStream(std::ostream& out) const override; + + + protected: + storm::storage::ParameterRegion<ValueType> parameterSpace; + }; + } +} diff --git a/src/storm-pars/parser/ParameterRegionParser.cpp b/src/storm-pars/parser/ParameterRegionParser.cpp new file mode 100644 index 000000000..f6345eef1 --- /dev/null +++ b/src/storm-pars/parser/ParameterRegionParser.cpp @@ -0,0 +1,97 @@ +#include "storm-pars/parser/ParameterRegionParser.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/InvalidArgumentException.h" +#include "storm/utility/constants.h" +#include "storm/utility/file.h" + +namespace storm { + namespace parser { + + template<typename ParametricType> + void ParameterRegionParser<ParametricType>::parseParameterBoundaries(Valuation& lowerBoundaries, Valuation& upperBoundaries, std::string const& parameterBoundariesString, std::set<VariableType> const& consideredVariables) { + + std::string::size_type positionOfFirstRelation = parameterBoundariesString.find("<="); + STORM_LOG_THROW(positionOfFirstRelation!=std::string::npos, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find a '<=' after the first number"); + std::string::size_type positionOfSecondRelation = parameterBoundariesString.find("<=", positionOfFirstRelation+2); + STORM_LOG_THROW(positionOfSecondRelation!=std::string::npos, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find a '<=' after the parameter"); + + std::string parameter = parameterBoundariesString.substr(positionOfFirstRelation+2,positionOfSecondRelation-(positionOfFirstRelation+2)); + //removes all whitespaces from the parameter string: + parameter.erase(std::remove_if (parameter.begin(), parameter.end(), ::isspace), parameter.end()); + STORM_LOG_THROW(parameter.length()>0, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find a parameter"); + + std::unique_ptr<VariableType> var; + for (auto const& v : consideredVariables) { + std::stringstream stream; + stream << v; + std::string vAsString = stream.str(); + if (parameter == stream.str()) { + var = std::make_unique<VariableType>(v); + } + } + STORM_LOG_ASSERT(var, "Could not find parameter " << parameter << " in the set of considered variables"); + + CoefficientType lb = storm::utility::convertNumber<CoefficientType>(parameterBoundariesString.substr(0,positionOfFirstRelation)); + CoefficientType ub = storm::utility::convertNumber<CoefficientType>(parameterBoundariesString.substr(positionOfSecondRelation+2)); + lowerBoundaries.emplace(std::make_pair(*var, lb)); + upperBoundaries.emplace(std::make_pair(*var, ub)); + } + + template<typename ParametricType> + storm::storage::ParameterRegion<ParametricType> ParameterRegionParser<ParametricType>::parseRegion(std::string const& regionString, std::set<VariableType> const& consideredVariables) { + Valuation lowerBoundaries; + Valuation upperBoundaries; + std::vector<std::string> parameterBoundaries; + boost::split(parameterBoundaries, regionString, boost::is_any_of(",")); + for (auto const& parameterBoundary : parameterBoundaries){ + if (!std::all_of(parameterBoundary.begin(),parameterBoundary.end(), ::isspace)){ //skip this string if it only consists of space + parseParameterBoundaries(lowerBoundaries, upperBoundaries, parameterBoundary, consideredVariables); + } + } + return storm::storage::ParameterRegion<ParametricType>(std::move(lowerBoundaries), std::move(upperBoundaries)); + } + + template<typename ParametricType> + std::vector<storm::storage::ParameterRegion<ParametricType>> ParameterRegionParser<ParametricType>::parseMultipleRegions(std::string const& regionsString, std::set<VariableType> const& consideredVariables) { + std::vector<storm::storage::ParameterRegion<ParametricType>> result; + std::vector<std::string> regionsStrVec; + boost::split(regionsStrVec, regionsString, boost::is_any_of(";")); + for (auto const& regionStr : regionsStrVec){ + if (!std::all_of(regionStr.begin(),regionStr.end(), ::isspace)){ //skip this string if it only consists of space + result.emplace_back(parseRegion(regionStr, consideredVariables)); + } + } + return result; + } + + template<typename ParametricType> + std::vector<storm::storage::ParameterRegion<ParametricType>> ParameterRegionParser<ParametricType>::parseMultipleRegionsFromFile(std::string const& fileName, std::set<VariableType> const& consideredVariables) { + + // Open file and initialize result. + std::ifstream inputFileStream; + storm::utility::openFile(fileName, inputFileStream); + + std::vector<storm::storage::ParameterRegion<ParametricType>> result; + + // Now try to parse the contents of the file. + try { + std::string fileContent((std::istreambuf_iterator<char>(inputFileStream)), (std::istreambuf_iterator<char>())); + result = parseMultipleRegions(fileContent, consideredVariables); + } catch(std::exception& e) { + // In case of an exception properly close the file before passing exception. + storm::utility::closeFile(inputFileStream); + throw e; + } + + // Close the stream in case everything went smoothly and return result. + storm::utility::closeFile(inputFileStream); + return result; + } + +#ifdef STORM_HAVE_CARL + template class ParameterRegionParser<storm::RationalFunction>; +#endif + } +} + diff --git a/src/storm-pars/parser/ParameterRegionParser.h b/src/storm-pars/parser/ParameterRegionParser.h new file mode 100644 index 000000000..99063a4d6 --- /dev/null +++ b/src/storm-pars/parser/ParameterRegionParser.h @@ -0,0 +1,47 @@ +#pragma once + +#include <map> + +#include "storm-pars/storage/ParameterRegion.h" + +namespace storm { + namespace parser { + template<typename ParametricType> + class ParameterRegionParser{ + public: + + typedef typename storm::storage::ParameterRegion<ParametricType>::VariableType VariableType; + typedef typename storm::storage::ParameterRegion<ParametricType>::CoefficientType CoefficientType; + typedef typename storm::storage::ParameterRegion<ParametricType>::Valuation Valuation; + + /* + * Parse a single parameter with its boundaries from a string of the form "0.3<=p<=0.5". + * The results will be inserted in the given maps + * + */ + static void parseParameterBoundaries( Valuation& lowerBoundaries, Valuation& upperBoundaries, std::string const& parameterBoundariesString, std::set<VariableType> const& consideredVariables); + + /* + * Parse a single region from a string of the form "0.3<=p<=0.5,0.4<=q<=0.7". + * + */ + static storm::storage::ParameterRegion<ParametricType> parseRegion(std::string const& regionString, std::set<VariableType> const& consideredVariables); + + /* + * Parse a vector of region from a string of the form "0.3<=p<=0.5,0.4<=q<=0.7;0.1<=p<=0.3,0.2<=q<=0.4". + * + */ + static std::vector<storm::storage::ParameterRegion<ParametricType>> parseMultipleRegions(std::string const& regionsString, std::set<VariableType> const& consideredVariables); + + + /* + * Parse multiple regions from a file + * + */ + static std::vector<storm::storage::ParameterRegion<ParametricType>> parseMultipleRegionsFromFile(std::string const& fileName, std::set<VariableType> const& consideredVariables); + + }; + } +} + + diff --git a/src/storm-pars/settings/ParsSettings.cpp b/src/storm-pars/settings/ParsSettings.cpp new file mode 100644 index 000000000..53907dc1c --- /dev/null +++ b/src/storm-pars/settings/ParsSettings.cpp @@ -0,0 +1,53 @@ +#include "storm-pars/settings/ParsSettings.h" + +#include "storm-pars/settings/modules/ParametricSettings.h" +#include "storm-pars/settings/modules/RegionSettings.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/GeneralSettings.h" +#include "storm/settings/modules/CoreSettings.h" +#include "storm/settings/modules/IOSettings.h" +#include "storm/settings/modules/DebugSettings.h" +#include "storm/settings/modules/SylvanSettings.h" +#include "storm/settings/modules/EigenEquationSolverSettings.h" +#include "storm/settings/modules/GmmxxEquationSolverSettings.h" +#include "storm/settings/modules/NativeEquationSolverSettings.h" +#include "storm/settings/modules/EliminationSettings.h" +#include "storm/settings/modules/MinMaxEquationSolverSettings.h" +#include "storm/settings/modules/GameSolverSettings.h" +#include "storm/settings/modules/BisimulationSettings.h" +#include "storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h" +#include "storm/settings/modules/ResourceSettings.h" +#include "storm/settings/modules/JaniExportSettings.h" +#include "storm/settings/modules/JitBuilderSettings.h" + + +namespace storm { + namespace settings { + void initializeParsSettings(std::string const& name, std::string const& executableName) { + storm::settings::mutableManager().setName(name, executableName); + + // Register relevant settings modules. + storm::settings::addModule<storm::settings::modules::GeneralSettings>(); + storm::settings::addModule<storm::settings::modules::IOSettings>(); + storm::settings::addModule<storm::settings::modules::CoreSettings>(); + storm::settings::addModule<storm::settings::modules::ParametricSettings>(); + storm::settings::addModule<storm::settings::modules::RegionSettings>(); + + storm::settings::addModule<storm::settings::modules::DebugSettings>(); + storm::settings::addModule<storm::settings::modules::SylvanSettings>(); + storm::settings::addModule<storm::settings::modules::GmmxxEquationSolverSettings>(); + storm::settings::addModule<storm::settings::modules::EigenEquationSolverSettings>(); + storm::settings::addModule<storm::settings::modules::NativeEquationSolverSettings>(); + storm::settings::addModule<storm::settings::modules::EliminationSettings>(); + storm::settings::addModule<storm::settings::modules::MinMaxEquationSolverSettings>(); + storm::settings::addModule<storm::settings::modules::GameSolverSettings>(); + storm::settings::addModule<storm::settings::modules::BisimulationSettings>(); + storm::settings::addModule<storm::settings::modules::TopologicalValueIterationEquationSolverSettings>(); + storm::settings::addModule<storm::settings::modules::ResourceSettings>(); + storm::settings::addModule<storm::settings::modules::JaniExportSettings>(); + storm::settings::addModule<storm::settings::modules::JitBuilderSettings>(); + } + + } +} \ No newline at end of file diff --git a/src/storm-pars/settings/ParsSettings.h b/src/storm-pars/settings/ParsSettings.h new file mode 100644 index 000000000..724fa2a44 --- /dev/null +++ b/src/storm-pars/settings/ParsSettings.h @@ -0,0 +1,11 @@ +#pragma once + +#include <string> + +namespace storm { + namespace settings { + + void initializeParsSettings(std::string const& name, std::string const& executableName); + + } +} \ No newline at end of file diff --git a/src/storm-pars/settings/modules/ParametricSettings.cpp b/src/storm-pars/settings/modules/ParametricSettings.cpp new file mode 100644 index 000000000..a50ef941e --- /dev/null +++ b/src/storm-pars/settings/modules/ParametricSettings.cpp @@ -0,0 +1,47 @@ +#include "storm-pars/settings/modules/ParametricSettings.h" + +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/IllegalArgumentValueException.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string ParametricSettings::moduleName = "parametric"; + const std::string ParametricSettings::exportResultOptionName = "resultfile"; + const std::string ParametricSettings::derivativesOptionName = "derivatives"; + const std::string ParametricSettings::transformContinuousOptionName = "transformcontinuous"; + const std::string ParametricSettings::transformContinuousShortOptionName = "tc"; + + ParametricSettings::ParametricSettings() : ModuleSettings(moduleName) { + this->addOption(storm::settings::OptionBuilder(moduleName, exportResultOptionName, false, "A path to a file where the parametric result should be saved.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("path", "the location.").addValidatorString(ArgumentValidatorFactory::createWritableFileValidator()).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, derivativesOptionName, false, "Sets whether to generate the derivatives of the resulting rational function.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, transformContinuousOptionName, false, "Sets whether to transform a continuous time input model to a discrete time model.").setShortName(transformContinuousShortOptionName).build()); + } + + bool ParametricSettings::exportResultToFile() const { + return this->getOption(exportResultOptionName).getHasOptionBeenSet(); + } + + std::string ParametricSettings::exportResultPath() const { + return this->getOption(exportResultOptionName).getArgumentByName("path").getValueAsString(); + } + + bool ParametricSettings::isDerivativesSet() const { + return this->getOption(derivativesOptionName).getHasOptionBeenSet(); + } + + bool ParametricSettings::transformContinuousModel() const { + return this->getOption(transformContinuousOptionName).getHasOptionBeenSet(); + } + + + } // namespace modules + } // namespace settings +} // namespace storm diff --git a/src/storm-pars/settings/modules/ParametricSettings.h b/src/storm-pars/settings/modules/ParametricSettings.h new file mode 100644 index 000000000..436faa92d --- /dev/null +++ b/src/storm-pars/settings/modules/ParametricSettings.h @@ -0,0 +1,58 @@ +#ifndef STORM_SETTINGS_MODULES_PARAMETRICSETTINGS_H_ +#define STORM_SETTINGS_MODULES_PARAMETRICSETTINGS_H_ + +#include "storm/settings/modules/ModuleSettings.h" + +namespace storm { + namespace settings { + namespace modules { + + /*! + * This class represents the settings for parametric model checking. + */ + class ParametricSettings : public ModuleSettings { + public: + + /*! + * Creates a new set of parametric model checking settings. + */ + ParametricSettings(); + + /** + * Retrieves whether the model checking result should be exported to a file. + * @return True iff the result should be exported to a file. + */ + bool exportResultToFile() const; + + /** + * The path to a file location which should contain the model checking result. + * @return A path to a file location. + */ + std::string exportResultPath() const; + + /*! + * Retrieves whether or not derivatives of the resulting rational function are to be generated. + * + * @return True if the derivatives are to be generated. + */ + bool isDerivativesSet() const; + + /*! + * Retrieves whether Continuous time models should be transformed to discrete time models + */ + bool transformContinuousModel() const; + + const static std::string moduleName; + + private: + const static std::string exportResultOptionName; + const static std::string derivativesOptionName; + const static std::string transformContinuousOptionName; + const static std::string transformContinuousShortOptionName; + }; + + } // namespace modules + } // namespace settings +} // namespace storm + +#endif /* STORM_SETTINGS_MODULES_PARAMETRICSETTINGS_H_ */ diff --git a/src/storm-pars/settings/modules/RegionSettings.cpp b/src/storm-pars/settings/modules/RegionSettings.cpp new file mode 100644 index 000000000..2dba3c300 --- /dev/null +++ b/src/storm-pars/settings/modules/RegionSettings.cpp @@ -0,0 +1,83 @@ +#include "storm-pars/settings/modules/RegionSettings.h" + +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/IllegalArgumentValueException.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string RegionSettings::moduleName = "region"; + const std::string RegionSettings::regionOptionName = "region"; + const std::string RegionSettings::regionShortOptionName = "reg"; + const std::string RegionSettings::refineOptionName = "refine"; + const std::string RegionSettings::checkEngineOptionName = "engine"; + const std::string RegionSettings::printNoIllustrationOptionName = "noillustration"; + const std::string RegionSettings::printFullResultOptionName = "printfullresult"; + + RegionSettings::RegionSettings() : ModuleSettings(moduleName) { + this->addOption(storm::settings::OptionBuilder(moduleName, regionOptionName, false, "Sets the region(s) considered for analysis.").setShortName(regionShortOptionName) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("regioninput", "The region(s) given in format a<=x<=b,c<=y<=d seperated by ';'. Can also be a file.").build()).build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, refineOptionName, false, "Enables region refinement.") + .addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("threshold", "Refinement converges if the fraction of unknown area falls below this threshold.").setDefaultValueDouble(0.05).addValidatorDouble(storm::settings::ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0,1.0)).build()).build()); + + std::vector<std::string> engines = {"pl", "exactpl", "validatingpl"}; + this->addOption(storm::settings::OptionBuilder(moduleName, checkEngineOptionName, true, "Sets which engine is used for analyzing regions.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the engine to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(engines)).setDefaultValueString("pl").build()).build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, printNoIllustrationOptionName, false, "If set, no illustration of the result is printed.").build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, printFullResultOptionName, false, "If set, the full result for every region is printed.").build()); + } + + bool RegionSettings::isRegionSet() const { + return this->getOption(regionOptionName).getHasOptionBeenSet(); + } + + std::string RegionSettings::getRegionString() const { + return this->getOption(regionOptionName).getArgumentByName("regioninput").getValueAsString(); + } + + bool RegionSettings::isRefineSet() const { + return this->getOption(refineOptionName).getHasOptionBeenSet(); + } + + double RegionSettings::getRefinementThreshold() const { + return this->getOption(refineOptionName).getArgumentByName("threshold").getValueAsDouble(); + } + + storm::modelchecker::RegionCheckEngine RegionSettings::getRegionCheckEngine() const { + std::string engineString = this->getOption(checkEngineOptionName).getArgumentByName("name").getValueAsString(); + + storm::modelchecker::RegionCheckEngine result; + if (engineString == "pl") { + result = storm::modelchecker::RegionCheckEngine::ParameterLifting; + } else if (engineString == "exactpl") { + result = storm::modelchecker::RegionCheckEngine::ExactParameterLifting; + } else if (engineString == "validatingpl") { + result = storm::modelchecker::RegionCheckEngine::ValidatingParameterLifting; + } else { + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown region check engine '" << engineString << "'."); + } + + return result; + } + + bool RegionSettings::isPrintNoIllustrationSet() const { + return this->getOption(printNoIllustrationOptionName).getHasOptionBeenSet(); + } + + bool RegionSettings::isPrintFullResultSet() const { + return this->getOption(printFullResultOptionName).getHasOptionBeenSet(); + } + + + } // namespace modules + } // namespace settings +} // namespace storm diff --git a/src/storm-pars/settings/modules/RegionSettings.h b/src/storm-pars/settings/modules/RegionSettings.h new file mode 100644 index 000000000..e668a3146 --- /dev/null +++ b/src/storm-pars/settings/modules/RegionSettings.h @@ -0,0 +1,72 @@ +#pragma once + +#include "storm-pars/modelchecker/region/RegionCheckEngine.h" + +#include "storm/settings/modules/ModuleSettings.h" + +namespace storm { + namespace settings { + namespace modules { + + /*! + * This class represents the settings for parametric model checking. + */ + class RegionSettings : public ModuleSettings { + public: + + /*! + * Creates a new set of parametric model checking settings. + */ + RegionSettings(); + + /*! + * Retrieves whether region(s) were declared + */ + bool isRegionSet() const; + + /*! + * Retrieves the region definition string + */ + std::string getRegionString() const; + + /*! + * Retrieves whether region refinement is enabled + */ + bool isRefineSet() const; + + /*! + * Retrieves the threshold considered for iterative region refinement. + * The refinement converges as soon as the fraction of unknown area falls below this threshold + */ + double getRefinementThreshold() const; + + /*! + * Retrieves which type of region check should be performed + */ + storm::modelchecker::RegionCheckEngine getRegionCheckEngine() const; + + /*! + * Retrieves whether no illustration of the result should be printed. + */ + bool isPrintNoIllustrationSet() const; + + /*! + * Retrieves whether the full result should be printed + */ + bool isPrintFullResultSet() const; + + const static std::string moduleName; + + private: + const static std::string regionOptionName; + const static std::string regionShortOptionName; + const static std::string refineOptionName; + const static std::string checkEngineOptionName; + const static std::string printNoIllustrationOptionName; + const static std::string printFullResultOptionName; + }; + + } // namespace modules + } // namespace settings +} // namespace storm + diff --git a/src/storm/storage/ParameterRegion.cpp b/src/storm-pars/storage/ParameterRegion.cpp similarity index 71% rename from src/storm/storage/ParameterRegion.cpp rename to src/storm-pars/storage/ParameterRegion.cpp index 9e5287d05..3d9e36c93 100644 --- a/src/storm/storage/ParameterRegion.cpp +++ b/src/storm-pars/storage/ParameterRegion.cpp @@ -1,13 +1,17 @@ -#include "ParameterRegion.h" +#include "storm-pars/storage/ParameterRegion.h" #include "storm/utility/macros.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/utility/constants.h" -#include "storm/utility/file.h" namespace storm { namespace storage { + template<typename ParametricType> + ParameterRegion<ParametricType>::ParameterRegion() { + init(); + } + template<typename ParametricType> ParameterRegion<ParametricType>::ParameterRegion(Valuation const& lowerBoundaries, Valuation const& upperBoundaries) : lowerBoundaries(lowerBoundaries), upperBoundaries(upperBoundaries) { init(); @@ -164,67 +168,17 @@ namespace storm { regionstring = regionstring.substr(0, regionstring.length() - 1) + ";"; return regionstring; } - - - template<typename ParametricType> - void ParameterRegion<ParametricType>::parseParameterBoundaries(Valuation& lowerBoundaries, Valuation& upperBoundaries, std::string const& parameterBoundariesString, std::set<VariableType> const& consideredVariables) { - - std::string::size_type positionOfFirstRelation = parameterBoundariesString.find("<="); - STORM_LOG_THROW(positionOfFirstRelation!=std::string::npos, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find a '<=' after the first number"); - std::string::size_type positionOfSecondRelation = parameterBoundariesString.find("<=", positionOfFirstRelation+2); - STORM_LOG_THROW(positionOfSecondRelation!=std::string::npos, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find a '<=' after the parameter"); - - std::string parameter = parameterBoundariesString.substr(positionOfFirstRelation+2,positionOfSecondRelation-(positionOfFirstRelation+2)); - //removes all whitespaces from the parameter string: - parameter.erase(std::remove_if(parameter.begin(), parameter.end(), ::isspace), parameter.end()); - STORM_LOG_THROW(parameter.length()>0, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find a parameter"); - - std::unique_ptr<VariableType> var; - for (auto const& v : consideredVariables) { - std::stringstream stream; - stream << v; - std::string vAsString = stream.str(); - if(parameter == stream.str()) { - var = std::make_unique<VariableType>(v); - } - } - STORM_LOG_ASSERT(var, "Could not find parameter " << parameter << " in the set of considered variables"); - - CoefficientType lb = storm::utility::convertNumber<CoefficientType>(parameterBoundariesString.substr(0,positionOfFirstRelation)); - CoefficientType ub = storm::utility::convertNumber<CoefficientType>(parameterBoundariesString.substr(positionOfSecondRelation+2)); - lowerBoundaries.emplace(std::make_pair(*var, lb)); - upperBoundaries.emplace(std::make_pair(*var, ub)); - } - - template<typename ParametricType> - ParameterRegion<ParametricType> ParameterRegion<ParametricType>::parseRegion(std::string const& regionString, std::set<VariableType> const& consideredVariables) { - Valuation lowerBoundaries; - Valuation upperBoundaries; - std::vector<std::string> parameterBoundaries; - boost::split(parameterBoundaries, regionString, boost::is_any_of(",")); - for(auto const& parameterBoundary : parameterBoundaries){ - if(!std::all_of(parameterBoundary.begin(),parameterBoundary.end(), ::isspace)){ //skip this string if it only consists of space - parseParameterBoundaries(lowerBoundaries, upperBoundaries, parameterBoundary, consideredVariables); - } - } - return ParameterRegion(std::move(lowerBoundaries), std::move(upperBoundaries)); + + template <typename ParametricType> + std::ostream& operator<<(std::ostream& out, ParameterRegion<ParametricType> const& region) { + out << region.toString(); + return out; } - template<typename ParametricType> - std::vector<ParameterRegion<ParametricType>> ParameterRegion<ParametricType>::parseMultipleRegions(std::string const& regionsString, std::set<VariableType> const& consideredVariables) { - std::vector<ParameterRegion> result; - std::vector<std::string> regionsStrVec; - boost::split(regionsStrVec, regionsString, boost::is_any_of(";")); - for(auto const& regionStr : regionsStrVec){ - if(!std::all_of(regionStr.begin(),regionStr.end(), ::isspace)){ //skip this string if it only consists of space - result.emplace_back(parseRegion(regionStr, consideredVariables)); - } - } - return result; - } - + #ifdef STORM_HAVE_CARL template class ParameterRegion<storm::RationalFunction>; + template std::ostream& operator<<(std::ostream& out, ParameterRegion<storm::RationalFunction> const& region); #endif } } diff --git a/src/storm/storage/ParameterRegion.h b/src/storm-pars/storage/ParameterRegion.h similarity index 68% rename from src/storm/storage/ParameterRegion.h rename to src/storm-pars/storage/ParameterRegion.h index add11e0be..95a98aa87 100644 --- a/src/storm/storage/ParameterRegion.h +++ b/src/storm-pars/storage/ParameterRegion.h @@ -2,7 +2,7 @@ #include <map> -#include "storm/utility/parametric.h" +#include "storm-pars/utility/parametric.h" namespace storm { namespace storage { @@ -13,6 +13,7 @@ namespace storm { typedef typename storm::utility::parametric::CoefficientType<ParametricType>::type CoefficientType; typedef typename storm::utility::parametric::Valuation<ParametricType> Valuation; + ParameterRegion(); ParameterRegion(Valuation const& lowerBoundaries, Valuation const& upperBoundaries); ParameterRegion(Valuation&& lowerBoundaries, Valuation&& upperBoundaries); ParameterRegion(ParameterRegion const& other) = default; @@ -62,28 +63,6 @@ namespace storm { //returns the region as string in the format 0.3<=p<=0.4,0.2<=q<=0.5; std::string toString(bool boundariesAsDouble = false) const; - /* - * Can be used to parse a single parameter with its boundaries from a string of the form "0.3<=p<=0.5". - * The numbers are parsed as doubles and then converted to SparseDtmcRegionModelChecker::CoefficientType. - * The results will be inserted in the given maps - * - */ - static void parseParameterBoundaries( Valuation& lowerBoundaries, Valuation& upperBoundaries, std::string const& parameterBoundariesString, std::set<VariableType> const& consideredVariables); - - /* - * Can be used to parse a single region from a string of the form "0.3<=p<=0.5,0.4<=q<=0.7". - * The numbers are parsed as doubles and then converted to SparseDtmcRegionModelChecker::CoefficientType. - * - */ - static ParameterRegion parseRegion(std::string const& regionString, std::set<VariableType> const& consideredVariables); - - /* - * Can be used to parse a vector of region from a string of the form "0.3<=p<=0.5,0.4<=q<=0.7;0.1<=p<=0.3,0.2<=q<=0.4". - * The numbers are parsed as doubles and then converted to SparseDtmcRegionModelChecker::CoefficientType. - * - */ - static std::vector<ParameterRegion> parseMultipleRegions(std::string const& regionsString, std::set<VariableType> const& consideredVariables); - private: void init(); @@ -92,6 +71,10 @@ namespace storm { Valuation upperBoundaries; std::set<VariableType> variables; }; + + template<typename ParametricType> + std::ostream& operator<<(std::ostream& out, ParameterRegion<ParametricType> const& region); + } } diff --git a/src/storm/transformer/ParameterLifter.cpp b/src/storm-pars/transformer/ParameterLifter.cpp similarity index 99% rename from src/storm/transformer/ParameterLifter.cpp rename to src/storm-pars/transformer/ParameterLifter.cpp index 43c76fd55..551529c4c 100644 --- a/src/storm/transformer/ParameterLifter.cpp +++ b/src/storm-pars/transformer/ParameterLifter.cpp @@ -1,4 +1,4 @@ -#include "storm/transformer/ParameterLifter.h" +#include "storm-pars/transformer/ParameterLifter.h" #include "storm/adapters/RationalFunctionAdapter.h" diff --git a/src/storm/transformer/ParameterLifter.h b/src/storm-pars/transformer/ParameterLifter.h similarity index 98% rename from src/storm/transformer/ParameterLifter.h rename to src/storm-pars/transformer/ParameterLifter.h index e29e648a6..ab16e5a88 100644 --- a/src/storm/transformer/ParameterLifter.h +++ b/src/storm-pars/transformer/ParameterLifter.h @@ -6,10 +6,10 @@ #include <set> +#include "storm-pars/storage/ParameterRegion.h" +#include "storm-pars/utility/parametric.h" #include "storm/storage/BitVector.h" #include "storm/storage/SparseMatrix.h" -#include "storm/utility/parametric.h" -#include "storm/storage/ParameterRegion.h" #include "storm/solver/OptimizationDirection.h" namespace storm { diff --git a/src/storm/transformer/SparseParametricDtmcSimplifier.cpp b/src/storm-pars/transformer/SparseParametricDtmcSimplifier.cpp similarity index 99% rename from src/storm/transformer/SparseParametricDtmcSimplifier.cpp rename to src/storm-pars/transformer/SparseParametricDtmcSimplifier.cpp index a150efe9b..ed05131e4 100644 --- a/src/storm/transformer/SparseParametricDtmcSimplifier.cpp +++ b/src/storm-pars/transformer/SparseParametricDtmcSimplifier.cpp @@ -1,4 +1,4 @@ -#include "storm/transformer/SparseParametricDtmcSimplifier.h" +#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h" #include "storm/adapters/RationalFunctionAdapter.h" diff --git a/src/storm/transformer/SparseParametricDtmcSimplifier.h b/src/storm-pars/transformer/SparseParametricDtmcSimplifier.h similarity index 95% rename from src/storm/transformer/SparseParametricDtmcSimplifier.h rename to src/storm-pars/transformer/SparseParametricDtmcSimplifier.h index 5f34b483b..efbbf231b 100644 --- a/src/storm/transformer/SparseParametricDtmcSimplifier.h +++ b/src/storm-pars/transformer/SparseParametricDtmcSimplifier.h @@ -1,7 +1,7 @@ #pragma once -#include "storm/transformer/SparseParametricModelSimplifier.h" +#include "storm-pars/transformer/SparseParametricModelSimplifier.h" namespace storm { namespace transformer { diff --git a/src/storm/transformer/SparseParametricMdpSimplifier.cpp b/src/storm-pars/transformer/SparseParametricMdpSimplifier.cpp similarity index 99% rename from src/storm/transformer/SparseParametricMdpSimplifier.cpp rename to src/storm-pars/transformer/SparseParametricMdpSimplifier.cpp index a6d8bf99e..1862936f4 100644 --- a/src/storm/transformer/SparseParametricMdpSimplifier.cpp +++ b/src/storm-pars/transformer/SparseParametricMdpSimplifier.cpp @@ -1,4 +1,4 @@ -#include "storm/transformer/SparseParametricMdpSimplifier.h" +#include "storm-pars/transformer/SparseParametricMdpSimplifier.h" #include "storm/adapters/RationalFunctionAdapter.h" diff --git a/src/storm/transformer/SparseParametricMdpSimplifier.h b/src/storm-pars/transformer/SparseParametricMdpSimplifier.h similarity index 97% rename from src/storm/transformer/SparseParametricMdpSimplifier.h rename to src/storm-pars/transformer/SparseParametricMdpSimplifier.h index ebe16f994..3a7c223bc 100644 --- a/src/storm/transformer/SparseParametricMdpSimplifier.h +++ b/src/storm-pars/transformer/SparseParametricMdpSimplifier.h @@ -1,7 +1,7 @@ #pragma once -#include "storm/transformer/SparseParametricModelSimplifier.h" +#include "storm-pars/transformer/SparseParametricModelSimplifier.h" namespace storm { namespace transformer { diff --git a/src/storm/transformer/SparseParametricModelSimplifier.cpp b/src/storm-pars/transformer/SparseParametricModelSimplifier.cpp similarity index 99% rename from src/storm/transformer/SparseParametricModelSimplifier.cpp rename to src/storm-pars/transformer/SparseParametricModelSimplifier.cpp index 3dd6fbd56..343fc06e3 100644 --- a/src/storm/transformer/SparseParametricModelSimplifier.cpp +++ b/src/storm-pars/transformer/SparseParametricModelSimplifier.cpp @@ -1,4 +1,4 @@ -#include "storm/transformer/SparseParametricModelSimplifier.h" +#include "storm-pars/transformer/SparseParametricModelSimplifier.h" #include "storm/adapters/RationalFunctionAdapter.h" diff --git a/src/storm/transformer/SparseParametricModelSimplifier.h b/src/storm-pars/transformer/SparseParametricModelSimplifier.h similarity index 100% rename from src/storm/transformer/SparseParametricModelSimplifier.h rename to src/storm-pars/transformer/SparseParametricModelSimplifier.h diff --git a/src/storm/utility/ModelInstantiator.cpp b/src/storm-pars/utility/ModelInstantiator.cpp similarity index 99% rename from src/storm/utility/ModelInstantiator.cpp rename to src/storm-pars/utility/ModelInstantiator.cpp index e28049862..f59649ab7 100644 --- a/src/storm/utility/ModelInstantiator.cpp +++ b/src/storm-pars/utility/ModelInstantiator.cpp @@ -1,4 +1,4 @@ -#include "storm/utility/ModelInstantiator.h" +#include "storm-pars/utility/ModelInstantiator.h" #include "storm/models/sparse/StandardRewardModel.h" namespace storm { diff --git a/src/storm/utility/ModelInstantiator.h b/src/storm-pars/utility/ModelInstantiator.h similarity index 99% rename from src/storm/utility/ModelInstantiator.h rename to src/storm-pars/utility/ModelInstantiator.h index fa1ba8099..e96a4dda8 100644 --- a/src/storm/utility/ModelInstantiator.h +++ b/src/storm-pars/utility/ModelInstantiator.h @@ -5,12 +5,12 @@ #include <memory> #include <type_traits> +#include "storm-pars/utility/parametric.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/Ctmc.h" #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/models/sparse/StochasticTwoPlayerGame.h" -#include "storm/utility/parametric.h" #include "storm/utility/constants.h" namespace storm { diff --git a/src/storm/utility/parameterlifting.h b/src/storm-pars/utility/parameterlifting.h similarity index 81% rename from src/storm/utility/parameterlifting.h rename to src/storm-pars/utility/parameterlifting.h index 3c8cdbf73..a32418d91 100644 --- a/src/storm/utility/parameterlifting.h +++ b/src/storm-pars/utility/parameterlifting.h @@ -3,8 +3,8 @@ #include <vector> +#include "storm-pars/utility/parametric.h" #include "storm/models/sparse/Model.h" -#include "storm/utility/parametric.h" #include "storm/utility/macros.h" #include "storm/logic/Formula.h" #include "storm/logic/FragmentSpecification.h" @@ -31,37 +31,38 @@ namespace storm { * @return true iff it was successfully validated that parameter lifting is sound on the provided model. */ template<typename ValueType> - static bool validateParameterLiftingSound(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, std::shared_ptr<storm::logic::Formula const> const& formula) { + static bool validateParameterLiftingSound(storm::models::sparse::Model<ValueType> const& model, storm::logic::Formula const& formula) { // Check whether all numbers occurring in the model are multilinear // Transition matrix - if (model->isOfType(storm::models::ModelType::Dtmc) || model->isOfType(storm::models::ModelType::Mdp) || model->isOfType(storm::models::ModelType::Ctmc)) { - for (auto const& entry : model->getTransitionMatrix()) { + if (model.isOfType(storm::models::ModelType::Dtmc) || model.isOfType(storm::models::ModelType::Mdp) || model.isOfType(storm::models::ModelType::Ctmc)) { + for (auto const& entry : model.getTransitionMatrix()) { if (!storm::utility::parametric::isMultiLinearPolynomial(entry.getValue())) { STORM_LOG_WARN("The input model contains a non-linear polynomial as transition: '" << entry.getValue() << "'. Can not validate that parameter lifting is sound on this model."); return false; } } - } else if (model->isOfType(storm::models::ModelType::MarkovAutomaton)) { + } else if (model.isOfType(storm::models::ModelType::MarkovAutomaton)) { + auto const& ma = dynamic_cast<storm::models::sparse::MarkovAutomaton<ValueType> const&>(model); // Markov Automata store the probability matrix and the exit rate vector. However, we need to considert the rate matrix. - if (!model->template as<storm::models::sparse::MarkovAutomaton<ValueType>>()->isClosed()) { + if (!ma.isClosed()) { STORM_LOG_ERROR("parameter lifting requires a closed Markov automaton."); return false; } - auto const& rateVector = model->template as<storm::models::sparse::MarkovAutomaton<ValueType>>()->getExitRates(); - auto const& markovianStates = model->template as<storm::models::sparse::MarkovAutomaton<ValueType>>()->getMarkovianStates(); - for (uint_fast64_t state = 0; state < model->getNumberOfStates(); ++state) { + auto const& rateVector = ma.getExitRates(); + auto const& markovianStates = ma.getMarkovianStates(); + for (uint_fast64_t state = 0; state < model.getNumberOfStates(); ++state) { if (markovianStates.get(state)) { auto const& exitRate = rateVector[state]; - for (auto const& entry : model->getTransitionMatrix().getRowGroup(state)) { + for (auto const& entry : model.getTransitionMatrix().getRowGroup(state)) { if (!storm::utility::parametric::isMultiLinearPolynomial(storm::utility::simplify(entry.getValue() * exitRate))) { STORM_LOG_WARN("The input model contains a non-linear polynomial as transition rate: '" << storm::utility::simplify(entry.getValue() * exitRate) << "'. Can not validate that parameter lifting is sound on this model."); return false; } } } else { - for (auto const& entry : model->getTransitionMatrix().getRowGroup(state)) { + for (auto const& entry : model.getTransitionMatrix().getRowGroup(state)) { if (!storm::utility::parametric::isMultiLinearPolynomial(entry.getValue())) { STORM_LOG_WARN("The input model contains a non-linear polynomial as transition: '" << entry.getValue() << "'. Can not validate that parameter lifting is sound on this model."); return false; @@ -75,10 +76,10 @@ namespace storm { } // Rewards - if (formula->isRewardOperatorFormula()) { - storm::models::sparse::StandardRewardModel<ValueType> const& rewardModel = formula->asRewardOperatorFormula().hasRewardModelName() ? - model->getRewardModel(formula->asRewardOperatorFormula().getRewardModelName()) : - model->getUniqueRewardModel(); + if (formula.isRewardOperatorFormula()) { + storm::models::sparse::StandardRewardModel<ValueType> const& rewardModel = formula.asRewardOperatorFormula().hasRewardModelName() ? + model.getRewardModel(formula.asRewardOperatorFormula().getRewardModelName()) : + model.getUniqueRewardModel(); if (rewardModel.hasStateRewards()) { for (auto const& rew : rewardModel.getStateRewardVector()) { if (!storm::utility::parametric::isMultiLinearPolynomial(rew)) { @@ -91,7 +92,7 @@ namespace storm { // Note: This check could also be done action-wise. std::set<typename storm::utility::parametric::VariableType<ValueType>::type> collectedRewardParameters; if (rewardModel.hasStateActionRewards()) { - if (model->isOfType(storm::models::ModelType::Ctmc) || model->isOfType(storm::models::ModelType::MarkovAutomaton)) { + if (model.isOfType(storm::models::ModelType::Ctmc) || model.isOfType(storm::models::ModelType::MarkovAutomaton)) { for (auto const& rew : rewardModel.getStateActionRewardVector()) { if (!storm::utility::parametric::isMultiLinearPolynomial(rew)) { STORM_LOG_WARN("The input model contains a non-linear polynomial as action reward: '" << rew << "'. Can not validate that parameter lifting is sound on this model."); @@ -120,7 +121,7 @@ namespace storm { } if (!collectedRewardParameters.empty()) { - std::set<typename storm::utility::parametric::VariableType<ValueType>::type> transitionParameters = storm::models::sparse::getProbabilityParameters(*model); + std::set<typename storm::utility::parametric::VariableType<ValueType>::type> transitionParameters = storm::models::sparse::getProbabilityParameters(model); auto rewParIt = collectedRewardParameters.begin(); auto trParIt = transitionParameters.begin(); while (rewParIt != collectedRewardParameters.end() && trParIt != transitionParameters.end()) { diff --git a/src/storm/utility/parametric.cpp b/src/storm-pars/utility/parametric.cpp similarity index 97% rename from src/storm/utility/parametric.cpp rename to src/storm-pars/utility/parametric.cpp index 78bb0b880..3b6934a3e 100644 --- a/src/storm/utility/parametric.cpp +++ b/src/storm-pars/utility/parametric.cpp @@ -1,6 +1,6 @@ #include <string> -#include "storm/utility/parametric.h" +#include "storm-pars/utility/parametric.h" #include "storm/utility/constants.h" #include "storm/utility/macros.h" #include "storm/settings/SettingsManager.h" diff --git a/src/storm/utility/parametric.h b/src/storm-pars/utility/parametric.h similarity index 100% rename from src/storm/utility/parametric.h rename to src/storm-pars/utility/parametric.h diff --git a/src/storm/api/storm.h b/src/storm/api/storm.h index c2856da48..ffc4c75a6 100644 --- a/src/storm/api/storm.h +++ b/src/storm/api/storm.h @@ -4,6 +4,7 @@ #include "storm/api/properties.h" #include "storm/api/builder.h" #include "storm/api/bisimulation.h" +#include "storm/api/transformation.h" #include "storm/api/verification.h" #include "storm/api/counterexamples.h" #include "storm/api/export.h" diff --git a/src/storm/api/transformation.h b/src/storm/api/transformation.h new file mode 100644 index 000000000..204e283db --- /dev/null +++ b/src/storm/api/transformation.h @@ -0,0 +1,80 @@ +#pragma once + +#include "storm/transformer/ContinuousToDiscreteTimeModelTransformer.h" +#include "storm/transformer/SymbolicToSparseTransformer.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/InvalidOperationException.h" +#include "storm/exceptions/NotSupportedException.h" + +namespace storm { + namespace api { + + /*! + * Transforms the given continuous model to a discrete time model. + * If such a transformation does not preserve one of the given formulas, an error is issued. + */ + template <typename ValueType> + std::shared_ptr<storm::models::sparse::Model<ValueType>> transformContinuousToDiscreteTimeSparseModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) { + + storm::transformer::ContinuousToDiscreteTimeModelTransformer<ValueType> transformer; + + for (auto const& formula : formulas) { + STORM_LOG_THROW(transformer.preservesFormula(*formula), storm::exceptions::InvalidOperationException, "Transformation to discrete time model does not preserve formula " << *formula << "."); + } + + if (model->isOfType(storm::models::ModelType::Ctmc)) { + return transformer.transform(*model->template as<storm::models::sparse::Ctmc<ValueType>>()); + } else if (model->isOfType(storm::models::ModelType::MarkovAutomaton)) { + return transformer.transform(*model->template as<storm::models::sparse::MarkovAutomaton<ValueType>>()); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Transformation of a " << model->getType() << " to a discrete time model is not supported"); + } + return nullptr; + } + + /*! + * Transforms the given continuous model to a discrete time model IN PLACE. + * This means that the input continuous time model is replaced by the new discrete time model. + * If such a transformation does not preserve one of the given formulas, an error is issued. + */ + template <typename ValueType> + std::shared_ptr<storm::models::sparse::Model<ValueType>> transformContinuousToDiscreteTimeSparseModel(storm::models::sparse::Model<ValueType>&& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) { + + storm::transformer::ContinuousToDiscreteTimeModelTransformer<ValueType> transformer; + + for (auto const& formula : formulas) { + STORM_LOG_THROW(transformer.preservesFormula(*formula), storm::exceptions::InvalidOperationException, "Transformation to discrete time model does not preserve formula " << *formula << "."); + } + + if (model.isOfType(storm::models::ModelType::Ctmc)) { + return transformer.transform(std::move(*model.template as<storm::models::sparse::Ctmc<ValueType>>())); + } else if (model.isOfType(storm::models::ModelType::MarkovAutomaton)) { + return transformer.transform(std::move(*model.template as<storm::models::sparse::MarkovAutomaton<ValueType>>())); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Transformation of a " << model.getType() << " to a discrete time model is not supported."); + } + return nullptr; + + } + + /*! + * Transforms the given symbolic model to a sparse model. + */ + template<storm::dd::DdType Type, typename ValueType> + std::shared_ptr<storm::models::sparse::Model<ValueType>> transformSymbolicToSparseModel(std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> const& symbolicModel) { + switch (symbolicModel->getType()) { + case storm::models::ModelType::Dtmc: + return storm::transformer::SymbolicDtmcToSparseDtmcTransformer<Type, ValueType>().translate(*symbolicModel->template as<storm::models::symbolic::Dtmc<Type, ValueType>>()); + case storm::models::ModelType::Mdp: + return storm::transformer::SymbolicMdpToSparseMdpTransformer<Type, ValueType>::translate(*symbolicModel->template as<storm::models::symbolic::Mdp<Type, ValueType>>()); + case storm::models::ModelType::Ctmc: + return storm::transformer::SymbolicCtmcToSparseCtmcTransformer<Type, ValueType>::translate(*symbolicModel->template as<storm::models::symbolic::Ctmc<Type, ValueType>>()); + default: + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Transformation of symbolic " << symbolicModel->getType() << " to sparse model is not supported."); + } + return nullptr; + } + + } +} diff --git a/src/storm/api/verification.h b/src/storm/api/verification.h index 2bc6ec94e..16c42cd7e 100644 --- a/src/storm/api/verification.h +++ b/src/storm/api/verification.h @@ -255,131 +255,5 @@ namespace storm { return result; } - template<typename ParametricType> - std::unique_ptr<storm::modelchecker::CheckResult> verifyWithParameterLifting(std::shared_ptr<storm::models::sparse::Model<ParametricType>>, std::shared_ptr<storm::logic::Formula const> const&) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter-lifting is unavailable for this data-type."); - } - - template<> - inline std::unique_ptr<storm::modelchecker::CheckResult> verifyWithParameterLifting(std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> markovModel, std::shared_ptr<storm::logic::Formula const> const& formula) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Parameter-lifting is currently unavailable from the API."); -// storm::utility::Stopwatch parameterLiftingStopWatch(true); -// std::shared_ptr<storm::logic::Formula const> 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<storm::settings::modules::ParametricSettings>().isParameterSpaceSet(), storm::exceptions::InvalidSettingsException, "Invoked Parameter lifting but no parameter space was defined."); -// auto parameterSpaceAsString = storm::settings::getModule<storm::settings::modules::ParametricSettings>().getParameterSpace(); -// auto parameterSpace = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion(parameterSpaceAsString, modelParameters); -// auto refinementThreshold = storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(storm::settings::getModule<storm::settings::modules::ParametricSettings>().getRefinementThreshold()); -// std::vector<std::pair<storm::storage::ParameterRegion<storm::RationalFunction>, 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<double>(refinementThreshold) << " ..." << std::endl); -// -// storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction> task(*consideredFormula, true); -// std::string resultVisualization; -// -// if (markovModel->isOfType(storm::models::ModelType::Dtmc)) { -// if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isExactSet()) { -// storm::modelchecker::parametric::SparseDtmcRegionChecker <storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber> regionChecker(*markovModel->template as<storm::models::sparse::Dtmc<storm::RationalFunction>>()); -// 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 <storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*markovModel->template as<storm::models::sparse::Dtmc<storm::RationalFunction>>()); -// 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<storm::settings::modules::GeneralSettings>().isExactSet()) { -// storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber> regionChecker(*markovModel->template as<storm::models::sparse::Mdp<storm::RationalFunction>>()); -// 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<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*markovModel->template as<storm::models::sparse::Mdp<storm::RationalFunction>>()); -// 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<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(); -// auto unsatArea = storm::utility::zero<typename storm::storage::ParameterRegion<storm::RationalFunction>::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<storm::RationalFunction>::CoefficientType satAreaFraction = satArea / parameterSpace.area(); -// typename storm::storage::ParameterRegion<storm::RationalFunction>::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<double>(satAreaFraction) * 100 << "% of the parameter space is safe, and " -// << storm::utility::convertNumber<double>(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<storm::settings::modules::ParametricSettings>().exportResultToFile()) { -// std::string path = storm::settings::getModule<storm::settings::modules::ParametricSettings>().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; -// } -// } -// } -// } - } - } } diff --git a/src/storm/cli/cli.cpp b/src/storm/cli/cli.cpp index 0f53aa2d3..b28f068c3 100644 --- a/src/storm/cli/cli.cpp +++ b/src/storm/cli/cli.cpp @@ -26,7 +26,6 @@ #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/ResourceSettings.h" -#include "storm/settings/modules/ParametricSettings.h" #include <type_traits> @@ -658,13 +657,6 @@ namespace storm { std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithSparseEngine<ValueType>(sparseModel, storm::api::createTask<ValueType>(formula, true)); result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(sparseModel->getInitialStates())); return result; - }, - [&sparseModel] (std::unique_ptr<storm::modelchecker::CheckResult> const& result) { - auto parametricSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>(); - if (std::is_same<ValueType, storm::RationalFunction>::value && sparseModel->isOfType(storm::models::ModelType::Dtmc) && parametricSettings.exportResultToFile()) { - auto dtmc = sparseModel->template as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); - storm::api::exportParametricResultToFile(result->asExplicitQuantitativeCheckResult<storm::RationalFunction>()[*sparseModel->getInitialStates().begin()], storm::analysis::ConstraintCollector<storm::RationalFunction>(*dtmc), parametricSettings.exportResultPath()); - } }); } diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index c555fd0e8..50e26ddae 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -200,12 +200,16 @@ namespace storm { template <typename ValueType, typename RewardModelType> std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeReachabilityRewards(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) { - std::vector<ValueType> stateRewardWeights(transitionMatrix.getRowGroupCount()); + + // Get a reward model where the state rewards are scaled accordingly + std::vector<ValueType> stateRewardWeights(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>()); for (auto const markovianState : markovianStates) { stateRewardWeights[markovianState] = storm::utility::one<ValueType>() / exitRateVector[markovianState]; } std::vector<ValueType> totalRewardVector = rewardModel.getTotalActionRewardVector(transitionMatrix, stateRewardWeights); - return computeExpectedRewards(dir, transitionMatrix, backwardTransitions, psiStates, totalRewardVector, minMaxLinearEquationSolverFactory); + RewardModelType scaledRewardModel(boost::none, std::move(totalRewardVector)); + + return SparseMdpPrctlHelper<ValueType>::computeReachabilityRewards(dir, transitionMatrix, backwardTransitions, scaledRewardModel, psiStates, false, false, minMaxLinearEquationSolverFactory).values; } template<typename ValueType> @@ -365,112 +369,15 @@ namespace storm { template <typename ValueType> std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeReachabilityTimes(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) { + + // Get a reward model representing expected sojourn times std::vector<ValueType> rewardValues(transitionMatrix.getRowCount(), storm::utility::zero<ValueType>()); for (auto const markovianState : markovianStates) { rewardValues[transitionMatrix.getRowGroupIndices()[markovianState]] = storm::utility::one<ValueType>() / exitRateVector[markovianState]; } - return computeExpectedRewards(dir, transitionMatrix, backwardTransitions, psiStates, rewardValues, minMaxLinearEquationSolverFactory); - } - - template<typename ValueType> - std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeExpectedRewards(OptimizationDirection dir, - storm::storage::SparseMatrix<ValueType> const &transitionMatrix, - storm::storage::SparseMatrix<ValueType> const &backwardTransitions, - storm::storage::BitVector const &goalStates, - std::vector<ValueType> const &stateActionRewardVector, - storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const &minMaxLinearEquationSolverFactory) { - - uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount(); - - // First, we need to check which states have infinite expected time (by definition). - storm::storage::BitVector infinityStates; - if (dir == OptimizationDirection::Minimize) { - // If we need to compute the minimum expected times, we have to set the values of those states to infinity that, under all schedulers, - // reach a bottom SCC without a goal state. - - // So we start by computing all bottom SCCs without goal states. - storm::storage::StronglyConnectedComponentDecomposition<ValueType> sccDecomposition(transitionMatrix, - ~goalStates, true, - true); - - // Now form the union of all these SCCs. - storm::storage::BitVector unionOfNonGoalBSccs(numberOfStates); - for (auto const &scc : sccDecomposition) { - for (auto state : scc) { - unionOfNonGoalBSccs.set(state); - } - } - - // Finally, if this union is non-empty, compute the states such that all schedulers reach some state of the union. - if (!unionOfNonGoalBSccs.empty()) { - infinityStates = storm::utility::graph::performProbGreater0A(transitionMatrix, - transitionMatrix.getRowGroupIndices(), - backwardTransitions, - storm::storage::BitVector( - numberOfStates, true), - unionOfNonGoalBSccs); - } else { - // Otherwise, we have no infinity states. - infinityStates = storm::storage::BitVector(numberOfStates); - } - } else { - // If we maximize the property, the expected time of a state is infinite, if an end-component without any goal state is reachable. - - // So we start by computing all MECs that have no goal state. - storm::storage::MaximalEndComponentDecomposition<ValueType> mecDecomposition(transitionMatrix, - backwardTransitions, - ~goalStates); - - // Now we form the union of all states in these end components. - storm::storage::BitVector unionOfNonGoalMaximalEndComponents(numberOfStates); - for (auto const &mec : mecDecomposition) { - for (auto const &stateActionPair : mec) { - unionOfNonGoalMaximalEndComponents.set(stateActionPair.first); - } - } - - if (!unionOfNonGoalMaximalEndComponents.empty()) { - // Now we need to check for which states there exists a scheduler that reaches one of the previously computed states. - infinityStates = storm::utility::graph::performProbGreater0E(backwardTransitions, - storm::storage::BitVector( - numberOfStates, true), - unionOfNonGoalMaximalEndComponents); - } else { - // Otherwise, we have no infinity states. - infinityStates = storm::storage::BitVector(numberOfStates); - } - } - // Now we identify the states for which values need to be computed. - storm::storage::BitVector maybeStates = ~(goalStates | infinityStates); - - // Create resulting vector. - std::vector<ValueType> result(numberOfStates); - - if (!maybeStates.empty()) { - // Then, we can eliminate the rows and columns for all states whose values are already known. - std::vector<ValueType> x(maybeStates.getNumberOfSetBits()); - storm::storage::SparseMatrix<ValueType> submatrix = transitionMatrix.getSubmatrix(true, maybeStates, - maybeStates); - - // Finally, prepare the actual right-hand side. - std::vector<ValueType> b(submatrix.getRowCount()); - storm::utility::vector::selectVectorValues(b, maybeStates, - transitionMatrix.getRowGroupIndices(), - stateActionRewardVector); - - // Solve the corresponding system of equations. - std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = minMaxLinearEquationSolverFactory.create( - submatrix); - solver->solveEquations(dir, x, b); - - // Set values of resulting vector according to previous result and return the result. - storm::utility::vector::setVectorValues<ValueType>(result, maybeStates, x); - } - - storm::utility::vector::setVectorValues(result, goalStates, storm::utility::zero<ValueType>()); - storm::utility::vector::setVectorValues(result, infinityStates, storm::utility::infinity<ValueType>()); - - return result; + storm::models::sparse::StandardRewardModel<ValueType> rewardModel(boost::none, std::move(rewardValues)); + + return SparseMdpPrctlHelper<ValueType>::computeReachabilityRewards(dir, transitionMatrix, backwardTransitions, rewardModel, psiStates, false, false, minMaxLinearEquationSolverFactory).values; } template<typename ValueType> @@ -550,8 +457,6 @@ namespace storm { template double SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, std::vector<double> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& goalStates, storm::storage::MaximalEndComponent const& mec); - template std::vector<double> SparseMarkovAutomatonCslHelper::computeExpectedRewards(OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, storm::storage::BitVector const& goalStates, std::vector<double> const& stateRewards, storm::solver::MinMaxLinearEquationSolverFactory<double> const& minMaxLinearEquationSolverFactory); - template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, std::vector<storm::RationalNumber> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory<storm::RationalNumber> const& minMaxLinearEquationSolverFactory); template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory<storm::RationalNumber> const& minMaxLinearEquationSolverFactory); @@ -566,8 +471,6 @@ namespace storm { template storm::RationalNumber SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, std::vector<storm::RationalNumber> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& goalStates, storm::storage::MaximalEndComponent const& mec); - template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeExpectedRewards(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, storm::storage::BitVector const& goalStates, std::vector<storm::RationalNumber> const& stateRewards, storm::solver::MinMaxLinearEquationSolverFactory<storm::RationalNumber> const& minMaxLinearEquationSolverFactory); - } } } diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index d61baf0c2..20d6c9598 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -55,22 +55,6 @@ namespace storm { */ template <typename ValueType> static ValueType computeLraForMaximalEndComponent(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& goalStates, storm::storage::MaximalEndComponent const& mec); - - /*! - * Computes the expected reward that is gained from each state before entering any of the goal states. - * - * @param dir Indicates whether minimal or maximal rewards are to be computed. - * @param transitionMatrix The transition matrix of the underlying Markov automaton. - * @param backwardTransitions The reversed transition relation of the underlying Markov automaton. - * @param goalStates The goal states that define until which point rewards are gained. - * @param stateRewards A vector that defines the reward gained in each state. For probabilistic states, - * this is an instantaneous reward that is fully gained and for Markovian states the actually gained - * reward is dependent on the expected time to stay in the state, i.e. it is gouverned by the exit rate - * of the state. - * @return A vector that contains the expected reward for each state of the model. - */ - template <typename ValueType> - static std::vector<ValueType> computeExpectedRewards(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& goalStates, std::vector<ValueType> const& stateRewards, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory); }; } diff --git a/src/storm/modelchecker/parametric/RegionCheckResult.cpp b/src/storm/modelchecker/parametric/RegionCheckResult.cpp deleted file mode 100644 index 48f743462..000000000 --- a/src/storm/modelchecker/parametric/RegionCheckResult.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "storm/modelchecker/parametric/RegionCheckResult.h" - -#include "storm/utility/macros.h" -#include "storm/exceptions/NotImplementedException.h" - -namespace storm { - namespace modelchecker { - namespace parametric { - std::ostream& operator<<(std::ostream& os, RegionCheckResult const& regionCheckResult) { - switch (regionCheckResult) { - case RegionCheckResult::Unknown: - os << "Unknown"; - break; - case RegionCheckResult::ExistsSat: - os << "ExistsSat"; - break; - case RegionCheckResult::ExistsViolated: - os << "ExistsViolated"; - break; - case RegionCheckResult::CenterSat: - os << "CenterSat"; - break; - case RegionCheckResult::CenterViolated: - os << "CenterViolated"; - break; - case RegionCheckResult::ExistsBoth: - os << "ExistsBoth"; - break; - case RegionCheckResult::AllSat: - os << "AllSat"; - break; - case RegionCheckResult::AllViolated: - os << "AllViolated"; - break; - default: - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Could not get a string from the region check result. The case has not been implemented"); - } - return os; - } - } - } -} diff --git a/src/storm/modelchecker/parametric/RegionCheckResult.h b/src/storm/modelchecker/parametric/RegionCheckResult.h deleted file mode 100644 index 267b6e665..000000000 --- a/src/storm/modelchecker/parametric/RegionCheckResult.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include <ostream> - -namespace storm { - namespace modelchecker { - namespace parametric { - /*! - * The results for a single Parameter region - */ - enum class RegionCheckResult { - Unknown, /*!< the result is unknown */ - ExistsSat, /*!< the formula is satisfied for at least one parameter evaluation that lies in the given region */ - ExistsViolated, /*!< the formula is violated for at least one parameter evaluation that lies in the given region */ - CenterSat, /*!< the formula is satisfied for the parameter Valuation that corresponds to the center point of the region */ - CenterViolated, /*!< the formula is violated for the parameter Valuation that corresponds to the center point of the region */ - ExistsBoth, /*!< the formula is satisfied for some parameters but also violated for others */ - AllSat, /*!< the formula is satisfied for all parameters in the given region */ - AllViolated /*!< the formula is violated for all parameters in the given region */ - }; - - std::ostream& operator<<(std::ostream& os, RegionCheckResult const& regionCheckResult); - } - } -} - diff --git a/src/storm/modelchecker/parametric/RegionChecker.cpp b/src/storm/modelchecker/parametric/RegionChecker.cpp deleted file mode 100644 index 163e28b7a..000000000 --- a/src/storm/modelchecker/parametric/RegionChecker.cpp +++ /dev/null @@ -1,326 +0,0 @@ -#include <sstream> -#include <queue> - -#include "storm/modelchecker/parametric/RegionChecker.h" - -#include "storm/adapters/RationalFunctionAdapter.h" - -#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" - -#include "storm/utility/vector.h" -#include "storm/models/sparse/StandardRewardModel.h" -#include "storm/models/sparse/Dtmc.h" -#include "storm/models/sparse/Mdp.h" - -#include "storm/exceptions/NotSupportedException.h" -#include "storm/exceptions/InvalidStateException.h" -#include "storm/exceptions/InvalidArgumentException.h" - -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/CoreSettings.h" -#include "storm/settings/modules/ParametricSettings.h" - - -namespace storm { - namespace modelchecker { - namespace parametric { - - RegionCheckerSettings::RegionCheckerSettings() { - this->applyExactValidation = storm::settings::getModule<storm::settings::modules::ParametricSettings>().isExactValidationSet(); - } - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - RegionChecker<SparseModelType, ConstantType, ExactConstantType>::RegionChecker(SparseModelType const& parametricModel) : parametricModel(parametricModel), numOfCorrectedRegions(0) { - initializationStopwatch.start(); - STORM_LOG_THROW(parametricModel.getInitialStates().getNumberOfSetBits() == 1, storm::exceptions::NotSupportedException, "Parameter lifting requires models with only one initial state"); - initializationStopwatch.stop(); - } - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - RegionCheckerSettings const& RegionChecker<SparseModelType, ConstantType, ExactConstantType>::getSettings() const { - return settings; - } - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - void RegionChecker<SparseModelType, ConstantType, ExactConstantType>::setSettings(RegionCheckerSettings const& newSettings) { - settings = newSettings; - } - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - void RegionChecker<SparseModelType, ConstantType, ExactConstantType>::specifyFormula(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) { - initializationStopwatch.start(); - STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::NotSupportedException, "Parameter lifting requires a property where only the value in the initial states is relevant."); - STORM_LOG_THROW(checkTask.isBoundSet(), storm::exceptions::NotSupportedException, "Parameter lifting requires a bounded property."); - - simplifyParametricModel(checkTask); - initializeUnderlyingCheckers(); - currentCheckTask = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, typename SparseModelType::ValueType>>(checkTask.substituteFormula(*currentFormula)); - - STORM_LOG_THROW(parameterLiftingChecker->canHandle(*currentCheckTask) && - (!exactParameterLiftingChecker || exactParameterLiftingChecker->canHandle(*currentCheckTask)), - storm::exceptions::NotSupportedException, "Parameter lifting is not supported for this property."); - if (exactParameterLiftingChecker) { - exactParameterLiftingChecker->specifyFormula(*currentCheckTask); - } - parameterLiftingChecker->specifyFormula(*currentCheckTask); - instantiationChecker->specifyFormula(*currentCheckTask); - initializationStopwatch.stop(); - } - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - RegionCheckResult RegionChecker<SparseModelType, ConstantType, ExactConstantType>::analyzeRegion(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionCheckResult const& initialResult, bool sampleVerticesOfRegion) { - RegionCheckResult result = initialResult; - - // Check if we need to check the formula on one point to decide whether to show AllSat or AllViolated - instantiationCheckerStopwatch.start(); - if (result == RegionCheckResult::Unknown) { - result = instantiationChecker->check(region.getCenterPoint())->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()] ? RegionCheckResult::CenterSat : RegionCheckResult::CenterViolated; - } - instantiationCheckerStopwatch.stop(); - - // try to prove AllSat or AllViolated, depending on the obtained result - parameterLiftingCheckerStopwatch.start(); - if(result == RegionCheckResult::ExistsSat || result == RegionCheckResult::CenterSat) { - // show AllSat: - storm::solver::OptimizationDirection parameterOptimizationDirection = isLowerBound(this->currentCheckTask->getBound().comparisonType) ? storm::solver::OptimizationDirection::Minimize : storm::solver::OptimizationDirection::Maximize; - if(parameterLiftingChecker->check(region, parameterOptimizationDirection)->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) { - result = RegionCheckResult::AllSat; - } else if (sampleVerticesOfRegion) { - parameterLiftingCheckerStopwatch.stop(); instantiationCheckerStopwatch.start(); - // Check if there is a point in the region for which the property is violated - auto vertices = region.getVerticesOfRegion(region.getVariables()); - for (auto const& v : vertices) { - if (!instantiationChecker->check(v)->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) { - result = RegionCheckResult::ExistsBoth; - } - } - instantiationCheckerStopwatch.stop(); parameterLiftingCheckerStopwatch.start(); - } - } else if (result == RegionCheckResult::ExistsViolated || result == RegionCheckResult::CenterViolated) { - // show AllViolated: - storm::solver::OptimizationDirection parameterOptimizationDirection = isLowerBound(this->currentCheckTask->getBound().comparisonType) ? storm::solver::OptimizationDirection::Maximize : storm::solver::OptimizationDirection::Minimize; - if(!parameterLiftingChecker->check(region, parameterOptimizationDirection)->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) { - result = RegionCheckResult::AllViolated; - } else if (sampleVerticesOfRegion) { - parameterLiftingCheckerStopwatch.stop(); instantiationCheckerStopwatch.start(); - // Check if there is a point in the region for which the property is satisfied - auto vertices = region.getVerticesOfRegion(region.getVariables()); - for (auto const& v : vertices) { - if (instantiationChecker->check(v)->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) { - result = RegionCheckResult::ExistsBoth; - } - } - instantiationCheckerStopwatch.stop(); parameterLiftingCheckerStopwatch.start(); - } - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "When analyzing a region, an invalid initial result was given: " << initialResult); - } - parameterLiftingCheckerStopwatch.stop(); - return result; - } - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - RegionCheckResult RegionChecker<SparseModelType, ConstantType, ExactConstantType>::analyzeRegionExactValidation(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionCheckResult const& initialResult) { - RegionCheckResult numericResult = analyzeRegion(region, initialResult, false); - parameterLiftingCheckerStopwatch.start(); - if (numericResult == RegionCheckResult::AllSat || numericResult == RegionCheckResult::AllViolated) { - applyHintsToExactChecker(); - } - if (numericResult == RegionCheckResult::AllSat) { - if(!exactParameterLiftingChecker->check(region, this->currentCheckTask->getOptimizationDirection())->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) { - // Numerical result is wrong; Check whether the region is AllViolated! - STORM_LOG_INFO("Numerical result was wrong for one region... Applying exact methods to obtain the actual result..."); - ++numOfCorrectedRegions; - if(!exactParameterLiftingChecker->check(region, storm::solver::invert(this->currentCheckTask->getOptimizationDirection()))->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) { - parameterLiftingCheckerStopwatch.stop(); - return RegionCheckResult::AllViolated; - } else { - parameterLiftingCheckerStopwatch.stop(); - return RegionCheckResult::Unknown; - } - } - } else if (numericResult == RegionCheckResult::AllViolated) { - if(exactParameterLiftingChecker->check(region, storm::solver::invert(this->currentCheckTask->getOptimizationDirection()))->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) { - // Numerical result is wrong; Check whether the region is AllSat! - STORM_LOG_INFO("Numerical result was wrong for one region... Applying exact methods to obtain the actual result..."); - ++numOfCorrectedRegions; - if(exactParameterLiftingChecker->check(region, this->currentCheckTask->getOptimizationDirection())->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) { - parameterLiftingCheckerStopwatch.stop(); - return RegionCheckResult::AllSat; - } else { - parameterLiftingCheckerStopwatch.stop(); - return RegionCheckResult::Unknown; - } - } - } - parameterLiftingCheckerStopwatch.stop(); - return numericResult; - } - - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - std::vector<std::pair<storm::storage::ParameterRegion<typename SparseModelType::ValueType>, RegionCheckResult>> RegionChecker<SparseModelType, ConstantType, ExactConstantType>::performRegionRefinement(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, CoefficientType const& threshold) { - STORM_LOG_INFO("Applying refinement on region: " << region.toString(true) << " ."); - - auto areaOfParameterSpace = region.area(); - auto fractionOfUndiscoveredArea = storm::utility::one<CoefficientType>(); - auto fractionOfAllSatArea = storm::utility::zero<CoefficientType>(); - auto fractionOfAllViolatedArea = storm::utility::zero<CoefficientType>(); - - std::queue<std::pair<storm::storage::ParameterRegion<typename SparseModelType::ValueType>, RegionCheckResult>> unprocessedRegions; - std::vector<std::pair<storm::storage::ParameterRegion<typename SparseModelType::ValueType>, RegionCheckResult>> result; - unprocessedRegions.emplace(region, RegionCheckResult::Unknown); - uint_fast64_t numOfAnalyzedRegions = 0; - numOfCorrectedRegions = 0; - CoefficientType displayedProgress = storm::utility::zero<CoefficientType>(); - if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) { - STORM_PRINT_AND_LOG("Progress (solved fraction) :" << std::endl << "0% ["); - while (displayedProgress < storm::utility::one<CoefficientType>() - threshold) { - STORM_PRINT_AND_LOG(" "); - displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01); - } - while (displayedProgress < storm::utility::one<CoefficientType>()) { - STORM_PRINT_AND_LOG("-"); - displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01); - } - STORM_PRINT_AND_LOG("] 100%" << std::endl << " ["); - displayedProgress = storm::utility::zero<CoefficientType>(); - } - - while (fractionOfUndiscoveredArea > threshold) { - STORM_LOG_THROW(!unprocessedRegions.empty(), storm::exceptions::InvalidStateException, "Threshold for undiscovered area not reached but no unprocessed regions left."); - STORM_LOG_INFO("Analyzing region #" << numOfAnalyzedRegions << " (" << storm::utility::convertNumber<double>(fractionOfUndiscoveredArea) * 100 << "% still unknown)"); - auto& currentRegion = unprocessedRegions.front().first; - auto& res = unprocessedRegions.front().second; - if (settings.applyExactValidation) { - res = analyzeRegionExactValidation(currentRegion, res); - } else { - res = analyzeRegion(currentRegion, res, false); - } - switch (res) { - case RegionCheckResult::AllSat: - fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace; - fractionOfAllSatArea += currentRegion.area() / areaOfParameterSpace; - result.push_back(std::move(unprocessedRegions.front())); - break; - case RegionCheckResult::AllViolated: - fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace; - fractionOfAllViolatedArea += currentRegion.area() / areaOfParameterSpace; - result.push_back(std::move(unprocessedRegions.front())); - break; - default: - std::vector<storm::storage::ParameterRegion<typename SparseModelType::ValueType>> newRegions; - currentRegion.split(currentRegion.getCenterPoint(), newRegions); - RegionCheckResult initResForNewRegions = (res == RegionCheckResult::CenterSat) ? RegionCheckResult::ExistsSat : - ((res == RegionCheckResult::CenterViolated) ? RegionCheckResult::ExistsViolated : - RegionCheckResult::Unknown); - for(auto& newRegion : newRegions) { - unprocessedRegions.emplace(std::move(newRegion), initResForNewRegions); - } - break; - } - ++numOfAnalyzedRegions; - unprocessedRegions.pop(); - if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) { - while (displayedProgress < storm::utility::one<CoefficientType>() - fractionOfUndiscoveredArea) { - STORM_PRINT_AND_LOG("#"); - displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01); - } - } - } - - if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) { - while (displayedProgress < storm::utility::one<CoefficientType>()) { - STORM_PRINT_AND_LOG("-"); - displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01); - } - STORM_PRINT_AND_LOG("]" << std::endl); - - STORM_PRINT_AND_LOG("Parameter Lifting Statistics:" << std::endl); - STORM_PRINT_AND_LOG(" Analyzed a total of " << numOfAnalyzedRegions << " regions." << std::endl); - if (settings.applyExactValidation) { - STORM_PRINT_AND_LOG(" Exact validation corrected " << numOfCorrectedRegions << " regions." << std::endl); - } - STORM_PRINT_AND_LOG(" Initialization took " << initializationStopwatch << " seconds." << std::endl); - STORM_PRINT_AND_LOG(" Checking sampled models took " << instantiationCheckerStopwatch << " seconds." << std::endl); - STORM_PRINT_AND_LOG(" Checking lifted models took " << parameterLiftingCheckerStopwatch << " seconds." << std::endl); - } - return result; - } - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - SparseModelType const& RegionChecker<SparseModelType, ConstantType, ExactConstantType>::getConsideredParametricModel() const { - if (simplifiedModel) { - return *simplifiedModel; - } else { - return parametricModel; - } - } - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - std::string RegionChecker<SparseModelType, ConstantType, ExactConstantType>::visualizeResult(std::vector<std::pair<storm::storage::ParameterRegion<typename SparseModelType::ValueType>, RegionCheckResult>> const& result, storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& parameterSpace, typename storm::storage::ParameterRegion<typename SparseModelType::ValueType>::VariableType const& x, typename storm::storage::ParameterRegion<typename SparseModelType::ValueType>::VariableType const& y) { - - std::stringstream stream; - - uint_fast64_t const sizeX = 128; - uint_fast64_t const sizeY = 64; - - stream << "Parameter lifting result (visualization):" << std::endl; - stream << " \t x-axis: " << x << " \t y-axis: " << y << " \t S=safe, [ ]=unsafe, -=ambiguous " << std::endl; - for (uint_fast64_t i = 0; i < sizeX+2; ++i) stream << "#"; stream << std::endl; - - CoefficientType deltaX = (parameterSpace.getUpperBoundary(x) - parameterSpace.getLowerBoundary(x)) / storm::utility::convertNumber<CoefficientType>(sizeX); - CoefficientType deltaY = (parameterSpace.getUpperBoundary(y) - parameterSpace.getLowerBoundary(y)) / storm::utility::convertNumber<CoefficientType>(sizeY); - CoefficientType printedRegionArea = deltaX * deltaY; - for (CoefficientType yUpper = parameterSpace.getUpperBoundary(y); yUpper != parameterSpace.getLowerBoundary(y); yUpper -= deltaY) { - CoefficientType yLower = yUpper - deltaY; - stream << "#"; - for (CoefficientType xLower = parameterSpace.getLowerBoundary(x); xLower != parameterSpace.getUpperBoundary(x); xLower += deltaX) { - CoefficientType xUpper = xLower + deltaX; - bool currRegionSafe = false; - bool currRegionUnSafe = false; - bool currRegionComplete = false; - CoefficientType coveredArea = storm::utility::zero<CoefficientType>(); - for (auto const& r : result) { - CoefficientType interesctionSizeY = std::min(yUpper, r.first.getUpperBoundary(y)) - std::max(yLower, r.first.getLowerBoundary(y)); - interesctionSizeY = std::max(interesctionSizeY, storm::utility::zero<CoefficientType>()); - CoefficientType interesctionSizeX = std::min(xUpper, r.first.getUpperBoundary(x)) - std::max(xLower, r.first.getLowerBoundary(x)); - interesctionSizeX = std::max(interesctionSizeX, storm::utility::zero<CoefficientType>()); - CoefficientType instersectionArea = interesctionSizeY * interesctionSizeX; - if(!storm::utility::isZero(instersectionArea)) { - currRegionSafe = currRegionSafe || r.second == RegionCheckResult::AllSat; - currRegionUnSafe = currRegionUnSafe || r.second == RegionCheckResult::AllViolated; - coveredArea += instersectionArea; - if(currRegionSafe && currRegionUnSafe) { - break; - } - if(coveredArea == printedRegionArea) { - currRegionComplete = true; - break; - } - } - } - if (currRegionComplete && currRegionSafe && !currRegionUnSafe) { - stream << "S"; - } else if (currRegionComplete && currRegionUnSafe && !currRegionSafe) { - stream << " "; - } else { - stream << "-"; - } - } - stream << "#" << std::endl; - } - for (uint_fast64_t i = 0; i < sizeX+2; ++i) stream << "#"; stream << std::endl; - return stream.str(); - } - -#ifdef STORM_HAVE_CARL - template class RegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber>; - template class RegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber>; - template class RegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>; - template class RegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>; -#endif - } // namespace parametric - } //namespace modelchecker -} //namespace storm - diff --git a/src/storm/modelchecker/parametric/RegionChecker.h b/src/storm/modelchecker/parametric/RegionChecker.h deleted file mode 100644 index 64bdcd580..000000000 --- a/src/storm/modelchecker/parametric/RegionChecker.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include <memory> - -#include "storm/modelchecker/parametric/RegionCheckResult.h" -#include "storm/modelchecker/parametric/SparseInstantiationModelChecker.h" -#include "storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h" -#include "storm/modelchecker/CheckTask.h" -#include "storm/storage/ParameterRegion.h" -#include "storm/utility/Stopwatch.h" -#include "storm/utility/NumberTraits.h" - -namespace storm { - namespace modelchecker{ - namespace parametric{ - - struct RegionCheckerSettings { - RegionCheckerSettings(); - - bool applyExactValidation; - }; - - template<typename SparseModelType, typename ConstantType, typename ExactConstantType = ConstantType> - class RegionChecker { - static_assert(storm::NumberTraits<ExactConstantType>::IsExact, "Specified type for exact computations is not exact."); - - public: - - typedef typename storm::storage::ParameterRegion<typename SparseModelType::ValueType>::CoefficientType CoefficientType; - - RegionChecker(SparseModelType const& parametricModel); - virtual ~RegionChecker() = default; - - RegionCheckerSettings const& getSettings() const; - void setSettings(RegionCheckerSettings const& newSettings); - - void specifyFormula(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask); - - /*! - * Analyzes the given region by means of parameter lifting. - * We first check whether there is one point in the region for which the property is satisfied/violated. - * If the given initialResults already indicates that there is such a point, this step is skipped. - * Then, we check whether ALL points in the region violate/satisfy the property - * - */ - RegionCheckResult analyzeRegion(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionCheckResult const& initialResult = RegionCheckResult::Unknown, bool sampleVerticesOfRegion = false); - /*! - * Similar to analyze region but additionaly invokes exact parameter lifting to validate results AllSat or AllViolated - */ - RegionCheckResult analyzeRegionExactValidation(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionCheckResult const& initialResult = RegionCheckResult::Unknown); - - /*! - * Iteratively refines the region until parameter lifting yields a conclusive result (AllSat or AllViolated). - * The refinement stops as soon as the fraction of the area of the subregions with inconclusive result is less then the given threshold - */ - std::vector<std::pair<storm::storage::ParameterRegion<typename SparseModelType::ValueType>, RegionCheckResult>> performRegionRefinement(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, CoefficientType const& threshold); - - static std::string visualizeResult(std::vector<std::pair<storm::storage::ParameterRegion<typename SparseModelType::ValueType>, RegionCheckResult>> const& result, storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& parameterSpace, typename storm::storage::ParameterRegion<typename SparseModelType::ValueType>::VariableType const& x, typename storm::storage::ParameterRegion<typename SparseModelType::ValueType>::VariableType const& y); - - protected: - SparseModelType const& getConsideredParametricModel() const; - - virtual void initializeUnderlyingCheckers() = 0; - virtual void simplifyParametricModel(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) = 0; - virtual void applyHintsToExactChecker() = 0; - - SparseModelType const& parametricModel; - RegionCheckerSettings settings; - std::unique_ptr<CheckTask<storm::logic::Formula, typename SparseModelType::ValueType>> currentCheckTask; - std::shared_ptr<storm::logic::Formula const> currentFormula; - std::shared_ptr<SparseModelType> simplifiedModel; - - - std::unique_ptr<SparseParameterLiftingModelChecker<SparseModelType, ConstantType>> parameterLiftingChecker; - std::unique_ptr<SparseParameterLiftingModelChecker<SparseModelType, ExactConstantType>> exactParameterLiftingChecker; - std::unique_ptr<SparseInstantiationModelChecker<SparseModelType, ConstantType>> instantiationChecker; - - // Information for statistics - mutable storm::utility::Stopwatch initializationStopwatch, instantiationCheckerStopwatch, parameterLiftingCheckerStopwatch; - mutable uint_fast64_t numOfCorrectedRegions; - }; - - } //namespace parametric - } //namespace modelchecker -} //namespace storm diff --git a/src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.cpp b/src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.cpp deleted file mode 100644 index 6b3d376a8..000000000 --- a/src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.cpp +++ /dev/null @@ -1,149 +0,0 @@ -#include "SparseDtmcInstantiationModelChecker.h" - -#include "storm/logic/FragmentSpecification.h" -#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" -#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" -#include "storm/modelchecker/hints/ExplicitModelCheckerHint.h" -#include "storm/utility/vector.h" - -#include "storm/exceptions/InvalidArgumentException.h" -#include "storm/exceptions/InvalidStateException.h" -namespace storm { - namespace modelchecker { - namespace parametric { - - template <typename SparseModelType, typename ConstantType> - SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::SparseDtmcInstantiationModelChecker(SparseModelType const& parametricModel) : SparseInstantiationModelChecker<SparseModelType, ConstantType>(parametricModel), modelInstantiator(parametricModel) { - //Intentionally left empty - } - - template <typename SparseModelType, typename ConstantType> - std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) { - STORM_LOG_THROW(this->currentCheckTask, storm::exceptions::InvalidStateException, "Checking has been invoked but no property has been specified before."); - auto const& instantiatedModel = modelInstantiator.instantiate(valuation); - STORM_LOG_ASSERT(instantiatedModel.getTransitionMatrix().isProbabilistic(), "Instantiated matrix is not probabilistic!"); - storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>> modelChecker(instantiatedModel); - - // Check if there are some optimizations implemented for the specified property - if(this->currentCheckTask->getFormula().isInFragment(storm::logic::reachability())) { - return checkReachabilityProbabilityFormula(modelChecker); - } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) { - return checkReachabilityRewardFormula(modelChecker); - } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setProbabilityOperatorsAllowed(true).setBoundedUntilFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) { - return checkBoundedUntilFormula(modelChecker); - } else { - return modelChecker.check(*this->currentCheckTask); - } - } - - template <typename SparseModelType, typename ConstantType> - std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityProbabilityFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker) { - - if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) { - this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>()); - } - ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>(); - std::unique_ptr<CheckResult> result; - - // Check the formula and store the result as a hint for the next call. - // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula - if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) { - result = modelChecker.check(*this->currentCheckTask); - hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()); - } else { - auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false); - std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask); - result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>()); - hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector())); - } - - if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) { - // Extract the maybe states from the current result. - assert(hint.hasResultHint()); - storm::storage::BitVector maybeStates = ~storm::utility::vector::filter<ConstantType>(hint.getResultHint(), - [] (ConstantType const& value) -> bool { return storm::utility::isZero<ConstantType>(value) || storm::utility::isOne<ConstantType>(value); }); - hint.setMaybeStates(std::move(maybeStates)); - hint.setComputeOnlyMaybeStates(true); - } - - return result; - } - - template <typename SparseModelType, typename ConstantType> - std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityRewardFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker) { - - if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) { - this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>()); - } - ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>(); - std::unique_ptr<CheckResult> result; - - // Check the formula and store the result as a hint for the next call. - // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula - if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) { - result = modelChecker.check(*this->currentCheckTask); - this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>().setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()); - } else { - auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false); - std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeRewards(this->currentCheckTask->getFormula().asRewardOperatorFormula().getMeasureType(), newCheckTask); - result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>()); - this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>().setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector())); - } - - if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) { - // Extract the maybe states from the current result. - assert(hint.hasResultHint()); - storm::storage::BitVector maybeStates = ~storm::utility::vector::filterInfinity(hint.getResultHint()); - // We need to exclude the target states from the maybe states. - // Note that we can not consider the states with reward zero since a valuation might set a reward to zero - std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asEventuallyFormula().getSubformula()); - maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector()); - hint.setMaybeStates(std::move(maybeStates)); - hint.setComputeOnlyMaybeStates(true); - } - - return result; - } - - template <typename SparseModelType, typename ConstantType> - std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::checkBoundedUntilFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker) { - - if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) { - this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>()); - } - std::unique_ptr<CheckResult> result; - ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>(); - - if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) { - // We extract the maybestates from the quantitative result - // For qualitative properties, we still need a quantitative result. Hence we perform the check on the subformula - if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) { - result = modelChecker.check(*this->currentCheckTask); - hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()); - } else { - auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false); - std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask); - result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>()); - hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector())); - } - - storm::storage::BitVector maybeStates = storm::utility::vector::filterGreaterZero(hint.getResultHint()); - // We need to exclude the target states from the maybe states. - // Note that we can not consider the states with probability one since a state might reach a target state with prob 1 within >0 steps - std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asBoundedUntilFormula().getRightSubformula()); - maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector()); - hint.setMaybeStates(std::move(maybeStates)); - hint.setComputeOnlyMaybeStates(true); - } else { - result = modelChecker.check(*this->currentCheckTask); - } - - return result; - } - - template class SparseDtmcInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>; - template class SparseDtmcInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>; - - } - } -} \ No newline at end of file diff --git a/src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.h b/src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.h deleted file mode 100644 index 511253107..000000000 --- a/src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include <memory> -#include <boost/optional.hpp> - -#include "storm/models/sparse/Dtmc.h" -#include "storm/models/sparse/StandardRewardModel.h" -#include "storm/modelchecker/parametric/SparseInstantiationModelChecker.h" -#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" -#include "storm/utility/ModelInstantiator.h" - -namespace storm { - namespace modelchecker { - namespace parametric { - - /*! - * Class to efficiently check a formula on a parametric model with different parameter instantiations - */ - template <typename SparseModelType, typename ConstantType> - class SparseDtmcInstantiationModelChecker : public SparseInstantiationModelChecker<SparseModelType, ConstantType> { - public: - SparseDtmcInstantiationModelChecker(SparseModelType const& parametricModel); - - virtual std::unique_ptr<CheckResult> check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) override; - - protected: - - // Optimizations for the different formula types - std::unique_ptr<CheckResult> checkReachabilityProbabilityFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker); - std::unique_ptr<CheckResult> checkReachabilityRewardFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker); - std::unique_ptr<CheckResult> checkBoundedUntilFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker); - - storm::utility::ModelInstantiator<SparseModelType, storm::models::sparse::Dtmc<ConstantType>> modelInstantiator; - }; - } - } -} diff --git a/src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.cpp b/src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.cpp deleted file mode 100644 index 0a802b584..000000000 --- a/src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.cpp +++ /dev/null @@ -1,281 +0,0 @@ -#include "storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.h" - -#include "storm/adapters/RationalFunctionAdapter.h" -#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h" -#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" -#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" -#include "storm/models/sparse/Dtmc.h" -#include "storm/models/sparse/StandardRewardModel.h" -#include "storm/solver/StandardMinMaxLinearEquationSolver.h" -#include "storm/utility/vector.h" -#include "storm/utility/graph.h" -#include "storm/utility/NumberTraits.h" - -#include "storm/exceptions/InvalidArgumentException.h" -#include "storm/exceptions/InvalidPropertyException.h" -#include "storm/exceptions/NotSupportedException.h" - -namespace storm { - namespace modelchecker { - namespace parametric { - - template <typename SparseModelType, typename ConstantType> - SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseDtmcParameterLiftingModelChecker(SparseModelType const& parametricModel) : SparseParameterLiftingModelChecker<SparseModelType, ConstantType>(parametricModel), solverFactory(std::make_unique<storm::solver::GeneralMinMaxLinearEquationSolverFactory<ConstantType>>()) { - } - - template <typename SparseModelType, typename ConstantType> - SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseDtmcParameterLiftingModelChecker(SparseModelType const& parametricModel, std::unique_ptr<storm::solver::MinMaxLinearEquationSolverFactory<ConstantType>>&& solverFactory) : SparseParameterLiftingModelChecker<SparseModelType, ConstantType>(parametricModel), solverFactory(std::move(solverFactory)) { - } - - template <typename SparseModelType, typename ConstantType> - bool SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::canHandle(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const { - return checkTask.getFormula().isInFragment(storm::logic::reachability().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setBoundedUntilFormulasAllowed(true).setCumulativeRewardFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true)); - } - - template <typename SparseModelType, typename ConstantType> - void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) { - - // get the step bound - STORM_LOG_THROW(!checkTask.getFormula().hasLowerBound(), storm::exceptions::NotSupportedException, "Lower step bounds are not supported."); - STORM_LOG_THROW(checkTask.getFormula().hasUpperBound(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with an upper bound."); - STORM_LOG_THROW(checkTask.getFormula().isStepBounded(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with step bounds."); - stepBound = checkTask.getFormula().getUpperBound().evaluateAsInt(); - STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive."); - if (checkTask.getFormula().isUpperBoundStrict()) { - STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero."); - --(*stepBound); - } - STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive."); - - // get the results for the subformulas - storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(this->parametricModel); - STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported"); - storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); - storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); - - // get the maybeStates - maybeStates = storm::utility::graph::performProbGreater0(this->parametricModel.getBackwardTransitions(), phiStates, psiStates, true, *stepBound); - maybeStates &= ~psiStates; - - // set the result for all non-maybe states - resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates(), storm::utility::zero<ConstantType>()); - storm::utility::vector::setVectorValues(resultsForNonMaybeStates, psiStates, storm::utility::one<ConstantType>()); - - // if there are maybestates, create the parameterLifter - if (!maybeStates.empty()) { - // Create the vector of one-step probabilities to go to target states. - std::vector<typename SparseModelType::ValueType> b = this->parametricModel.getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getRowCount(), true), psiStates); - - parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, maybeStates, maybeStates); - } - - // We know some bounds for the results so set them - lowerResultBound = storm::utility::zero<ConstantType>(); - upperResultBound = storm::utility::one<ConstantType>(); - } - - template <typename SparseModelType, typename ConstantType> - void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) { - - // get the results for the subformulas - storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(this->parametricModel); - STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported"); - storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); - storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); - - // get the maybeStates - std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 = storm::utility::graph::performProb01(this->parametricModel.getBackwardTransitions(), phiStates, psiStates); - maybeStates = ~(statesWithProbability01.first | statesWithProbability01.second); - - // set the result for all non-maybe states - resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates(), storm::utility::zero<ConstantType>()); - storm::utility::vector::setVectorValues(resultsForNonMaybeStates, statesWithProbability01.second, storm::utility::one<ConstantType>()); - - // if there are maybestates, create the parameterLifter - if (!maybeStates.empty()) { - // Create the vector of one-step probabilities to go to target states. - std::vector<typename SparseModelType::ValueType> b = this->parametricModel.getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getRowCount(), true), psiStates); - - parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, maybeStates, maybeStates); - } - - // We know some bounds for the results so set them - lowerResultBound = storm::utility::zero<ConstantType>(); - upperResultBound = storm::utility::one<ConstantType>(); - } - - template <typename SparseModelType, typename ConstantType> - void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) { - - // get the results for the subformula - storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(this->parametricModel); - STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported"); - storm::storage::BitVector targetStates = std::move(propositionalChecker.check(checkTask.getFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); - - // get the maybeStates - storm::storage::BitVector infinityStates = storm::utility::graph::performProb1(this->parametricModel.getBackwardTransitions(), storm::storage::BitVector(this->parametricModel.getNumberOfStates(), true), targetStates); - infinityStates.complement(); - maybeStates = ~(targetStates | infinityStates); - - // set the result for all the non-maybe states - resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates(), storm::utility::zero<ConstantType>()); - storm::utility::vector::setVectorValues(resultsForNonMaybeStates, infinityStates, storm::utility::infinity<ConstantType>()); - - // if there are maybestates, create the parameterLifter - if (!maybeStates.empty()) { - // Create the reward vector - STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel.hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel.hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model."); - - typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel.getRewardModel(checkTask.getRewardModel()) : this->parametricModel.getUniqueRewardModel(); - - std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel.getTransitionMatrix()); - - parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, maybeStates, maybeStates); - } - - // We only know a lower bound for the result - lowerResultBound = storm::utility::zero<ConstantType>(); - - } - - template <typename SparseModelType, typename ConstantType> - void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) { - - // Obtain the stepBound - stepBound = checkTask.getFormula().getBound().evaluateAsInt(); - if (checkTask.getFormula().isBoundStrict()) { - STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero."); - --(*stepBound); - } - STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive."); - - //Every state is a maybeState - maybeStates = storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getColumnCount(), true); - resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates()); - - // Create the reward vector - STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel.hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel.hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model."); - typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel.getRewardModel(checkTask.getRewardModel()) : this->parametricModel.getUniqueRewardModel(); - std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel.getTransitionMatrix()); - - parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, maybeStates, maybeStates); - - - // We only know a lower bound for the result - lowerResultBound = storm::utility::zero<ConstantType>(); - } - - template <typename SparseModelType, typename ConstantType> - std::unique_ptr<CheckResult> SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) { - - if(maybeStates.empty()) { - return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(resultsForNonMaybeStates); - } - - parameterLifter->specifyRegion(region, dirForParameters); - - // Set up the solver - auto solver = solverFactory->create(parameterLifter->getMatrix()); - if (storm::NumberTraits<ConstantType>::IsExact && dynamic_cast<storm::solver::StandardMinMaxLinearEquationSolver<ConstantType>*>(solver.get())) { - STORM_LOG_INFO("Parameter Lifting: Setting solution method for exact MinMaxSolver to policy iteration"); - auto* standardSolver = dynamic_cast<storm::solver::StandardMinMaxLinearEquationSolver<ConstantType>*>(solver.get()); - auto settings = standardSolver->getSettings(); - settings.setSolutionMethod(storm::solver::StandardMinMaxLinearEquationSolverSettings<ConstantType>::SolutionMethod::PolicyIteration); - standardSolver->setSettings(settings); - } - if (lowerResultBound) solver->setLowerBound(lowerResultBound.get()); - if (upperResultBound) solver->setUpperBound(upperResultBound.get()); - if (!stepBound) solver->setTrackScheduler(true); - if (storm::solver::minimize(dirForParameters) && minSchedChoices && !stepBound) solver->setSchedulerHint(std::move(minSchedChoices.get())); - if (storm::solver::maximize(dirForParameters) && maxSchedChoices && !stepBound) solver->setSchedulerHint(std::move(maxSchedChoices.get())); - if (this->currentCheckTask->isBoundSet() && solver->hasSchedulerHint()) { - // If we reach this point, we know that after applying the hint, the x-values can only become larger (if we maximize) or smaller (if we minimize). - std::unique_ptr<storm::solver::TerminationCondition<ConstantType>> termCond; - storm::storage::BitVector relevantStatesInSubsystem = this->currentCheckTask->isOnlyInitialStatesRelevantSet() ? this->parametricModel.getInitialStates() % maybeStates : storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true); - if (storm::solver::minimize(dirForParameters)) { - // Terminate if the value for ALL relevant states is already below the threshold - termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumBelowThreshold<ConstantType>> (relevantStatesInSubsystem, this->currentCheckTask->getBoundThreshold(), true, false); - } else { - // Terminate if the value for ALL relevant states is already above the threshold - termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumExceedsThreshold<ConstantType>> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), true); - } - solver->setTerminationCondition(std::move(termCond)); - } - - // Invoke the solver - if(stepBound) { - assert(*stepBound > 0); - x = std::vector<ConstantType>(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>()); - solver->repeatedMultiply(dirForParameters, x, ¶meterLifter->getVector(), *stepBound); - } else { - x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>()); - solver->solveEquations(dirForParameters, x, parameterLifter->getVector()); - if(storm::solver::minimize(dirForParameters)) { - minSchedChoices = solver->getSchedulerChoices(); - } else { - maxSchedChoices = solver->getSchedulerChoices(); - } - } - - // Get the result for the complete model (including maybestates) - std::vector<ConstantType> result = resultsForNonMaybeStates; - auto maybeStateResIt = x.begin(); - for(auto const& maybeState : maybeStates) { - result[maybeState] = *maybeStateResIt; - ++maybeStateResIt; - } - return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(std::move(result)); - } - - - template <typename SparseModelType, typename ConstantType> - void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::reset() { - maybeStates.resize(0); - resultsForNonMaybeStates.clear(); - stepBound = boost::none; - parameterLifter = nullptr; - minSchedChoices = boost::none; - maxSchedChoices = boost::none; - x.clear(); - lowerResultBound = boost::none; - upperResultBound = boost::none; - } - - template <typename SparseModelType, typename ConstantType> - boost::optional<storm::storage::Scheduler<ConstantType>> SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMinScheduler() { - if (!minSchedChoices) { - return boost::none; - } - - storm::storage::Scheduler<ConstantType> result(minSchedChoices->size()); - uint_fast64_t state = 0; - for (auto const& schedulerChoice : minSchedChoices.get()) { - result.setChoice(schedulerChoice, state); - ++state; - } - - return result; - } - - template <typename SparseModelType, typename ConstantType> - boost::optional<storm::storage::Scheduler<ConstantType>> SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMaxScheduler() { - if (!maxSchedChoices) { - return boost::none; - } - - storm::storage::Scheduler<ConstantType> result(maxSchedChoices->size()); - uint_fast64_t state = 0; - for (auto const& schedulerChoice : maxSchedChoices.get()) { - result.setChoice(schedulerChoice, state); - ++state; - } - - return result; - } - - template class SparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>; - template class SparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>; - - } - } -} diff --git a/src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.h b/src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.h deleted file mode 100644 index 73ee17fe7..000000000 --- a/src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include <vector> -#include <memory> -#include <boost/optional.hpp> - -#include "storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h" -#include "storm/storage/BitVector.h" -#include "storm/storage/Scheduler.h" -#include "storm/solver/MinMaxLinearEquationSolver.h" -#include "storm/transformer/ParameterLifter.h" -#include "storm/logic/FragmentSpecification.h" - - -namespace storm { - namespace modelchecker { - namespace parametric { - - template <typename SparseModelType, typename ConstantType> - class SparseDtmcParameterLiftingModelChecker : public SparseParameterLiftingModelChecker<SparseModelType, ConstantType> { - public: - SparseDtmcParameterLiftingModelChecker(SparseModelType const& parametricModel); - SparseDtmcParameterLiftingModelChecker(SparseModelType const& parametricModel, std::unique_ptr<storm::solver::MinMaxLinearEquationSolverFactory<ConstantType>>&& solverFactory); - - virtual bool canHandle(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const override; - - boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMinScheduler(); - boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMaxScheduler(); - - protected: - - virtual void specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) override; - virtual void specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) override; - virtual void specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) override; - virtual void specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) override; - - virtual std::unique_ptr<CheckResult> computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) override; - - virtual void reset() override; - - private: - storm::storage::BitVector maybeStates; - std::vector<ConstantType> resultsForNonMaybeStates; - boost::optional<uint_fast64_t> stepBound; - - std::unique_ptr<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>> parameterLifter; - std::unique_ptr<storm::solver::MinMaxLinearEquationSolverFactory<ConstantType>> solverFactory; - - // Results from the most recent solver call. - boost::optional<std::vector<uint_fast64_t>> minSchedChoices, maxSchedChoices; - std::vector<ConstantType> x; - boost::optional<ConstantType> lowerResultBound, upperResultBound; - }; - } - } -} diff --git a/src/storm/modelchecker/parametric/SparseDtmcRegionChecker.cpp b/src/storm/modelchecker/parametric/SparseDtmcRegionChecker.cpp deleted file mode 100644 index b280bc046..000000000 --- a/src/storm/modelchecker/parametric/SparseDtmcRegionChecker.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "storm/modelchecker/parametric/SparseDtmcRegionChecker.h" - -#include "storm/adapters/RationalFunctionAdapter.h" - -#include "storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.h" -#include "storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.h" -#include "storm/transformer/SparseParametricDtmcSimplifier.h" -#include "storm/models/sparse/StandardRewardModel.h" -#include "storm/models/sparse/Dtmc.h" -#include "storm/utility/NumberTraits.h" - -namespace storm { - namespace modelchecker { - namespace parametric { - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - SparseDtmcRegionChecker<SparseModelType, ConstantType, ExactConstantType>::SparseDtmcRegionChecker(SparseModelType const& parametricModel) : RegionChecker<SparseModelType, ConstantType, ExactConstantType>(parametricModel) { - // Intentionally left empty - } - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - void SparseDtmcRegionChecker<SparseModelType, ConstantType, ExactConstantType>::simplifyParametricModel(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) { - storm::transformer::SparseParametricDtmcSimplifier<SparseModelType> simplifier(this->parametricModel); - if(simplifier.simplify(checkTask.getFormula())) { - this->simplifiedModel = simplifier.getSimplifiedModel(); - this->currentFormula = simplifier.getSimplifiedFormula(); - } else { - this->simplifiedModel = nullptr; - this->currentFormula = checkTask.getFormula().asSharedPointer(); - } - } - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - void SparseDtmcRegionChecker<SparseModelType, ConstantType, ExactConstantType>::initializeUnderlyingCheckers() { - if (this->settings.applyExactValidation) { - STORM_LOG_WARN_COND(!storm::NumberTraits<ConstantType>::IsExact, "Exact validation is not necessarry if the original computation is already exact"); - this->exactParameterLiftingChecker = std::make_unique<SparseDtmcParameterLiftingModelChecker<SparseModelType, ExactConstantType>>(this->getConsideredParametricModel()); - } - this->parameterLiftingChecker = std::make_unique<SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>>(this->getConsideredParametricModel()); - this->instantiationChecker = std::make_unique<SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>>(this->getConsideredParametricModel()); - this->instantiationChecker->setInstantiationsAreGraphPreserving(true); - } - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - void SparseDtmcRegionChecker<SparseModelType, ConstantType, ExactConstantType>::applyHintsToExactChecker() { - auto dtmcPLChecker = dynamic_cast<storm::modelchecker::parametric::SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>*>(this->parameterLiftingChecker.get()); - STORM_LOG_ASSERT(dtmcPLChecker, "Underlying Parameter lifting checker has unexpected type"); - auto exactDtmcPLChecker = dynamic_cast<storm::modelchecker::parametric::SparseDtmcParameterLiftingModelChecker<SparseModelType, ExactConstantType>*>(this->exactParameterLiftingChecker.get()); - STORM_LOG_ASSERT(exactDtmcPLChecker, "Underlying exact parameter lifting checker has unexpected type"); - if (dtmcPLChecker->getCurrentMaxScheduler()) { - exactDtmcPLChecker->getCurrentMaxScheduler() = dtmcPLChecker->getCurrentMaxScheduler()->template toValueType<ExactConstantType>(); - } - if (dtmcPLChecker->getCurrentMinScheduler()) { - exactDtmcPLChecker->getCurrentMinScheduler() = dtmcPLChecker->getCurrentMinScheduler()->template toValueType<ExactConstantType>(); - } - } - -#ifdef STORM_HAVE_CARL - template class SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber>; - template class SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>; -#endif - } // namespace parametric - } //namespace modelchecker -} //namespace storm - diff --git a/src/storm/modelchecker/parametric/SparseDtmcRegionChecker.h b/src/storm/modelchecker/parametric/SparseDtmcRegionChecker.h deleted file mode 100644 index 561594d2e..000000000 --- a/src/storm/modelchecker/parametric/SparseDtmcRegionChecker.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include <memory> - -#include "storm/modelchecker/parametric/RegionChecker.h" - -namespace storm { - namespace modelchecker{ - namespace parametric{ - - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType = ConstantType> - class SparseDtmcRegionChecker : public RegionChecker<SparseModelType, ConstantType, ExactConstantType> { - - public: - SparseDtmcRegionChecker(SparseModelType const& parametricModel); - - protected: - virtual void simplifyParametricModel(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) override; - virtual void initializeUnderlyingCheckers() override; - virtual void applyHintsToExactChecker() override; - - }; - - } //namespace parametric - } //namespace modelchecker -} //namespace storm diff --git a/src/storm/modelchecker/parametric/SparseInstantiationModelChecker.cpp b/src/storm/modelchecker/parametric/SparseInstantiationModelChecker.cpp deleted file mode 100644 index 1a7a004d4..000000000 --- a/src/storm/modelchecker/parametric/SparseInstantiationModelChecker.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "SparseInstantiationModelChecker.h" - -#include "storm/adapters/RationalFunctionAdapter.h" -#include "storm/models/sparse/Dtmc.h" -#include "storm/models/sparse/Mdp.h" -#include "storm/models/sparse/StandardRewardModel.h" - -#include "storm/exceptions/InvalidArgumentException.h" - -namespace storm { - namespace modelchecker { - namespace parametric { - - template <typename SparseModelType, typename ConstantType> - SparseInstantiationModelChecker<SparseModelType, ConstantType>::SparseInstantiationModelChecker(SparseModelType const& parametricModel) : parametricModel(parametricModel), instantiationsAreGraphPreserving(false) { - //Intentionally left empty - } - - - template <typename SparseModelType, typename ConstantType> - void SparseInstantiationModelChecker<SparseModelType, ConstantType>::specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) { - currentFormula = checkTask.getFormula().asSharedPointer(); - currentCheckTask = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, ConstantType>>(checkTask.substituteFormula(*currentFormula).template convertValueType<ConstantType>()); - } - - template <typename SparseModelType, typename ConstantType> - void SparseInstantiationModelChecker<SparseModelType, ConstantType>::setInstantiationsAreGraphPreserving(bool value) { - instantiationsAreGraphPreserving = value; - } - - template <typename SparseModelType, typename ConstantType> - bool SparseInstantiationModelChecker<SparseModelType, ConstantType>::getInstantiationsAreGraphPreserving() const { - return instantiationsAreGraphPreserving; - } - - template class SparseInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>; - template class SparseInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>; - - template class SparseInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>; - template class SparseInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>; - - } - } -} diff --git a/src/storm/modelchecker/parametric/SparseInstantiationModelChecker.h b/src/storm/modelchecker/parametric/SparseInstantiationModelChecker.h deleted file mode 100644 index d51f87f38..000000000 --- a/src/storm/modelchecker/parametric/SparseInstantiationModelChecker.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "storm/logic/Formulas.h" -#include "storm/modelchecker/CheckTask.h" -#include "storm/modelchecker/results/CheckResult.h" -#include "storm/modelchecker/hints/ModelCheckerHint.h" -#include "storm/utility/parametric.h" - -namespace storm { - namespace modelchecker { - namespace parametric { - - /*! - * Class to efficiently check a formula on a parametric model with different parameter instantiations - */ - template <typename SparseModelType, typename ConstantType> - class SparseInstantiationModelChecker { - public: - SparseInstantiationModelChecker(SparseModelType const& parametricModel); - virtual ~SparseInstantiationModelChecker() = default; - - void specifyFormula(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask); - - virtual std::unique_ptr<CheckResult> check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) = 0; - - // If set, it is assumed that all considered model instantiations have the same underlying graph structure. - // This bypasses the graph analysis for the different instantiations. - void setInstantiationsAreGraphPreserving(bool value); - bool getInstantiationsAreGraphPreserving() const; - - protected: - - SparseModelType const& parametricModel; - std::unique_ptr<CheckTask<storm::logic::Formula, ConstantType>> currentCheckTask; - - private: - // store the current formula. Note that currentCheckTask only stores a reference to the formula. - std::shared_ptr<storm::logic::Formula const> currentFormula; - - bool instantiationsAreGraphPreserving; - }; - } - } -} diff --git a/src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.cpp b/src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.cpp deleted file mode 100644 index 1be1e9ac8..000000000 --- a/src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.cpp +++ /dev/null @@ -1,173 +0,0 @@ -#include "SparseMdpInstantiationModelChecker.h" - -#include "storm/logic/FragmentSpecification.h" -#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" -#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" -#include "storm/modelchecker/hints/ExplicitModelCheckerHint.h" -#include "storm/storage/Scheduler.h" -#include "storm/utility/graph.h" -#include "storm/utility/vector.h" - -#include "storm/exceptions/InvalidArgumentException.h" -#include "storm/exceptions/InvalidStateException.h" - -namespace storm { - namespace modelchecker { - namespace parametric { - - template <typename SparseModelType, typename ConstantType> - SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::SparseMdpInstantiationModelChecker(SparseModelType const& parametricModel) : SparseInstantiationModelChecker<SparseModelType, ConstantType>(parametricModel), modelInstantiator(parametricModel) { - //Intentionally left empty - } - - template <typename SparseModelType, typename ConstantType> - std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) { - STORM_LOG_THROW(this->currentCheckTask, storm::exceptions::InvalidStateException, "Checking has been invoked but no property has been specified before."); - auto const& instantiatedModel = modelInstantiator.instantiate(valuation); - STORM_LOG_ASSERT(instantiatedModel.getTransitionMatrix().isProbabilistic(), "Instantiated matrix is not probabilistic!"); - storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>> modelChecker(instantiatedModel); - - // Check if there are some optimizations implemented for the specified property - if(this->currentCheckTask->getFormula().isInFragment(storm::logic::reachability())) { - return checkReachabilityProbabilityFormula(modelChecker, instantiatedModel); - } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) { - return checkReachabilityRewardFormula(modelChecker, instantiatedModel); - } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setProbabilityOperatorsAllowed(true).setBoundedUntilFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) { - return checkBoundedUntilFormula(modelChecker); - } else { - return modelChecker.check(*this->currentCheckTask); - } - } - - template <typename SparseModelType, typename ConstantType> - std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityProbabilityFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel) { - - this->currentCheckTask->setProduceSchedulers(true); - - if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) { - this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>()); - } - ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>(); - std::unique_ptr<CheckResult> result; - - // Check the formula and store the result as a hint for the next call. - // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula - if(this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) { - result = modelChecker.check(*this->currentCheckTask); - storm::storage::Scheduler<ConstantType> const& scheduler = result->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler(); - hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()); - hint.setSchedulerHint(dynamic_cast<storm::storage::Scheduler<ConstantType> const&>(scheduler)); - } else { - auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false); - std::unique_ptr<storm::modelchecker::CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask); - result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>()); - storm::storage::Scheduler<ConstantType>& scheduler = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler(); - hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector())); - hint.setSchedulerHint(std::move(dynamic_cast<storm::storage::Scheduler<ConstantType>&>(scheduler))); - } - - if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) { - // Extract the maybe states from the current result. - assert(hint.hasResultHint()); - storm::storage::BitVector maybeStates = ~storm::utility::vector::filter<ConstantType>(hint.getResultHint(), - [] (ConstantType const& value) -> bool { return storm::utility::isZero<ConstantType>(value) || storm::utility::isOne<ConstantType>(value); }); - hint.setMaybeStates(std::move(maybeStates)); - hint.setComputeOnlyMaybeStates(true); - - // Check if there can be end components within the maybestates - if (storm::solver::minimize(this->currentCheckTask->getOptimizationDirection()) || - storm::utility::graph::performProb1A(instantiatedModel.getTransitionMatrix(), instantiatedModel.getTransitionMatrix().getRowGroupIndices(), instantiatedModel.getBackwardTransitions(), hint.getMaybeStates(), ~hint.getMaybeStates()).full()) { - hint.setNoEndComponentsInMaybeStates(true); - } - } - - return result; - } - - template <typename SparseModelType, typename ConstantType> - std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityRewardFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel) { - - this->currentCheckTask->setProduceSchedulers(true); - - if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) { - this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>()); - } - ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>(); - std::unique_ptr<CheckResult> result; - - // Check the formula and store the result as a hint for the next call. - // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula - if(this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) { - std::unique_ptr<storm::modelchecker::CheckResult> result = modelChecker.check(*this->currentCheckTask); - storm::storage::Scheduler<ConstantType> const& scheduler = result->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler(); - hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()); - hint.setSchedulerHint(dynamic_cast<storm::storage::Scheduler<ConstantType> const&>(scheduler)); - } else { - auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false); - std::unique_ptr<storm::modelchecker::CheckResult> quantitativeResult = modelChecker.computeRewards(this->currentCheckTask->getFormula().asRewardOperatorFormula().getMeasureType(), newCheckTask); - result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>()); - storm::storage::Scheduler<ConstantType>& scheduler = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler(); - hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector())); - hint.setSchedulerHint(std::move(dynamic_cast<storm::storage::Scheduler<ConstantType>&>(scheduler))); - } - - if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) { - // Extract the maybe states from the current result. - assert(hint.hasResultHint()); - storm::storage::BitVector maybeStates = ~storm::utility::vector::filterInfinity(hint.getResultHint()); - // We need to exclude the target states from the maybe states. - // Note that we can not consider the states with reward zero since a valuation might set a reward to zero - std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asEventuallyFormula().getSubformula()); - maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector()); - hint.setMaybeStates(std::move(maybeStates)); - hint.setComputeOnlyMaybeStates(true); - - // Check if there can be end components within the maybestates - if (storm::solver::maximize(this->currentCheckTask->getOptimizationDirection()) || - storm::utility::graph::performProb1A(instantiatedModel.getTransitionMatrix(), instantiatedModel.getTransitionMatrix().getRowGroupIndices(), instantiatedModel.getBackwardTransitions(), hint.getMaybeStates(), ~hint.getMaybeStates()).full()) { - hint.setNoEndComponentsInMaybeStates(true); - } - } - return result; - } - - template <typename SparseModelType, typename ConstantType> - std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::checkBoundedUntilFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker) { - - if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) { - this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>()); - } - std::unique_ptr<CheckResult> result; - ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>(); - - if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) { - // We extract the maybestates from the quantitative result - // For qualitative properties, we still need a quantitative result. Hence we perform the check on the subformula - if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) { - result = modelChecker.check(*this->currentCheckTask); - hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()); - } else { - auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false); - std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask); - result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>()); - hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector())); - } - storm::storage::BitVector maybeStates = storm::utility::vector::filterGreaterZero(hint.getResultHint()); - // We need to exclude the target states from the maybe states. - // Note that we can not consider the states with probability one since a state might reach a target state with prob 1 within >0 steps - std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asBoundedUntilFormula().getRightSubformula()); - maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector()); - hint.setMaybeStates(std::move(maybeStates)); - hint.setComputeOnlyMaybeStates(true); - } else { - result = modelChecker.check(*this->currentCheckTask); - } - return result; - } - - template class SparseMdpInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>; - template class SparseMdpInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>; - - } - } -} diff --git a/src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.h b/src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.h deleted file mode 100644 index a5570acc0..000000000 --- a/src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include <memory> - -#include "storm/models/sparse/Mdp.h" -#include "storm/models/sparse/Dtmc.h" -#include "storm/models/sparse/StandardRewardModel.h" -#include "storm/modelchecker/parametric/SparseInstantiationModelChecker.h" -#include "storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h" -#include "storm/utility/ModelInstantiator.h" - -namespace storm { - namespace modelchecker { - namespace parametric { - - /*! - * Class to efficiently check a formula on a parametric model with different parameter instantiations - */ - template <typename SparseModelType, typename ConstantType> - class SparseMdpInstantiationModelChecker : public SparseInstantiationModelChecker<SparseModelType, ConstantType> { - public: - SparseMdpInstantiationModelChecker(SparseModelType const& parametricModel); - - virtual std::unique_ptr<CheckResult> check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) override; - - protected: - // Optimizations for the different formula types - std::unique_ptr<CheckResult> checkReachabilityProbabilityFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel); - std::unique_ptr<CheckResult> checkReachabilityRewardFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel); - std::unique_ptr<CheckResult> checkBoundedUntilFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker); - - storm::utility::ModelInstantiator<SparseModelType, storm::models::sparse::Mdp<ConstantType>> modelInstantiator; - }; - } - } -} diff --git a/src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.cpp b/src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.cpp deleted file mode 100644 index 7b8df081a..000000000 --- a/src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.cpp +++ /dev/null @@ -1,348 +0,0 @@ -#include "storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.h" - -#include "storm/adapters/RationalFunctionAdapter.h" -#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h" -#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" -#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" -#include "storm/models/sparse/Mdp.h" -#include "storm/models/sparse/StandardRewardModel.h" -#include "storm/utility/vector.h" -#include "storm/utility/graph.h" -#include "storm/utility/NumberTraits.h" -#include "storm/solver/StandardGameSolver.h" -#include "storm/logic/FragmentSpecification.h" - -#include "storm/exceptions/InvalidArgumentException.h" -#include "storm/exceptions/InvalidPropertyException.h" -#include "storm/exceptions/NotSupportedException.h" - -namespace storm { - namespace modelchecker { - namespace parametric { - - template <typename SparseModelType, typename ConstantType> - SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseMdpParameterLiftingModelChecker(SparseModelType const& parametricModel) : SparseParameterLiftingModelChecker<SparseModelType, ConstantType>(parametricModel), solverFactory(std::make_unique<storm::solver::GameSolverFactory<ConstantType>>()) { - } - - template <typename SparseModelType, typename ConstantType> - SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseMdpParameterLiftingModelChecker(SparseModelType const& parametricModel, std::unique_ptr<storm::solver::GameSolverFactory<ConstantType>>&& solverFactory) : SparseParameterLiftingModelChecker<SparseModelType, ConstantType>(parametricModel), solverFactory(std::move(solverFactory)) { - } - - template <typename SparseModelType, typename ConstantType> - bool SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::canHandle(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const { - return checkTask.getFormula().isInFragment(storm::logic::reachability().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setBoundedUntilFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setCumulativeRewardFormulasAllowed(true)); - } - - template <typename SparseModelType, typename ConstantType> - void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) { - - // get the step bound - STORM_LOG_THROW(!checkTask.getFormula().hasLowerBound(), storm::exceptions::NotSupportedException, "Lower step bounds are not supported."); - STORM_LOG_THROW(checkTask.getFormula().hasUpperBound(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with an upper bound."); - STORM_LOG_THROW(checkTask.getFormula().isStepBounded(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with step bounds."); - stepBound = checkTask.getFormula().getUpperBound().evaluateAsInt(); - STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive."); - if (checkTask.getFormula().isUpperBoundStrict()) { - STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero."); - --(*stepBound); - } - STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive."); - - // get the results for the subformulas - storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(this->parametricModel); - STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported"); - storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); - storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); - - // get the maybeStates - maybeStates = storm::solver::minimize(checkTask.getOptimizationDirection()) ? - storm::utility::graph::performProbGreater0A(this->parametricModel.getTransitionMatrix(), this->parametricModel.getTransitionMatrix().getRowGroupIndices(), this->parametricModel.getBackwardTransitions(), phiStates, psiStates, true, *stepBound) : - storm::utility::graph::performProbGreater0E(this->parametricModel.getBackwardTransitions(), phiStates, psiStates, true, *stepBound); - maybeStates &= ~psiStates; - - // set the result for all non-maybe states - resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates(), storm::utility::zero<ConstantType>()); - storm::utility::vector::setVectorValues(resultsForNonMaybeStates, psiStates, storm::utility::one<ConstantType>()); - - // if there are maybestates, create the parameterLifter - if (!maybeStates.empty()) { - // Create the vector of one-step probabilities to go to target states. - std::vector<typename SparseModelType::ValueType> b = this->parametricModel.getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getRowCount(), true), psiStates); - - parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, this->parametricModel.getTransitionMatrix().getRowFilter(maybeStates), maybeStates); - computePlayer1Matrix(); - - applyPreviousResultAsHint = false; - } - - // We know some bounds for the results - lowerResultBound = storm::utility::zero<ConstantType>(); - upperResultBound = storm::utility::one<ConstantType>(); - } - - template <typename SparseModelType, typename ConstantType> - void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) { - - // get the results for the subformulas - storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(this->parametricModel); - STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported"); - storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); - storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); - - // get the maybeStates - std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 = storm::solver::minimize(checkTask.getOptimizationDirection()) ? - storm::utility::graph::performProb01Min(this->parametricModel.getTransitionMatrix(), this->parametricModel.getTransitionMatrix().getRowGroupIndices(), this->parametricModel.getBackwardTransitions(), phiStates, psiStates) : - storm::utility::graph::performProb01Max(this->parametricModel.getTransitionMatrix(), this->parametricModel.getTransitionMatrix().getRowGroupIndices(), this->parametricModel.getBackwardTransitions(), phiStates, psiStates); - maybeStates = ~(statesWithProbability01.first | statesWithProbability01.second); - - // set the result for all non-maybe states - resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates(), storm::utility::zero<ConstantType>()); - storm::utility::vector::setVectorValues(resultsForNonMaybeStates, statesWithProbability01.second, storm::utility::one<ConstantType>()); - - // if there are maybestates, create the parameterLifter - if (!maybeStates.empty()) { - // Create the vector of one-step probabilities to go to target states. - std::vector<typename SparseModelType::ValueType> b = this->parametricModel.getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getRowCount(), true), statesWithProbability01.second); - - parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, this->parametricModel.getTransitionMatrix().getRowFilter(maybeStates), maybeStates); - computePlayer1Matrix(); - - // Check whether there is an EC consisting of maybestates - applyPreviousResultAsHint = storm::solver::minimize(checkTask.getOptimizationDirection()) || // when minimizing, there can not be an EC within the maybestates - storm::utility::graph::performProb1A(this->parametricModel.getTransitionMatrix(), this->parametricModel.getTransitionMatrix().getRowGroupIndices(), this->parametricModel.getBackwardTransitions(), maybeStates, ~maybeStates).full(); - } - - // We know some bounds for the results - lowerResultBound = storm::utility::zero<ConstantType>(); - upperResultBound = storm::utility::one<ConstantType>(); - } - - template <typename SparseModelType, typename ConstantType> - void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) { - - // get the results for the subformula - storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(this->parametricModel); - STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported"); - storm::storage::BitVector targetStates = std::move(propositionalChecker.check(checkTask.getFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector()); - - // get the maybeStates - storm::storage::BitVector infinityStates = storm::solver::minimize(checkTask.getOptimizationDirection()) ? - storm::utility::graph::performProb1E(this->parametricModel.getTransitionMatrix(), this->parametricModel.getTransitionMatrix().getRowGroupIndices(), this->parametricModel.getBackwardTransitions(), storm::storage::BitVector(this->parametricModel.getNumberOfStates(), true), targetStates) : - storm::utility::graph::performProb1A(this->parametricModel.getTransitionMatrix(), this->parametricModel.getTransitionMatrix().getRowGroupIndices(), this->parametricModel.getBackwardTransitions(), storm::storage::BitVector(this->parametricModel.getNumberOfStates(), true), targetStates); - infinityStates.complement(); - maybeStates = ~(targetStates | infinityStates); - - // set the result for all the non-maybe states - resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates(), storm::utility::zero<ConstantType>()); - storm::utility::vector::setVectorValues(resultsForNonMaybeStates, infinityStates, storm::utility::infinity<ConstantType>()); - - // if there are maybestates, create the parameterLifter - if (!maybeStates.empty()) { - // Create the reward vector - STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel.hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel.hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model."); - - typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel.getRewardModel(checkTask.getRewardModel()) : this->parametricModel.getUniqueRewardModel(); - - std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel.getTransitionMatrix()); - - // We need to handle choices that lead to an infinity state. - // As a maybeState does not have reward infinity, a choice leading to an infinity state will never be picked. Hence, we can unselect the corresponding rows - storm::storage::BitVector selectedRows = this->parametricModel.getTransitionMatrix().getRowFilter(maybeStates, ~infinityStates); - - parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, selectedRows, maybeStates); - computePlayer1Matrix(); - - // Check whether there is an EC consisting of maybestates - applyPreviousResultAsHint = !storm::solver::minimize(checkTask.getOptimizationDirection()) || // when maximizing, there can not be an EC within the maybestates - storm::utility::graph::performProb1A(this->parametricModel.getTransitionMatrix(), this->parametricModel.getTransitionMatrix().getRowGroupIndices(), this->parametricModel.getBackwardTransitions(), maybeStates, ~maybeStates).full(); - } - - // We only know a lower bound for the result - lowerResultBound = storm::utility::zero<ConstantType>(); - - } - - template <typename SparseModelType, typename ConstantType> - void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) { - - // Obtain the stepBound - stepBound = checkTask.getFormula().getBound().evaluateAsInt(); - if (checkTask.getFormula().isBoundStrict()) { - STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero."); - --(*stepBound); - } - STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive."); - - //Every state is a maybeState - maybeStates = storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getColumnCount(), true); - resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates()); - - // Create the reward vector - STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel.hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel.hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model."); - typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel.getRewardModel(checkTask.getRewardModel()) : this->parametricModel.getUniqueRewardModel(); - std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel.getTransitionMatrix()); - - parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getRowCount(), true), maybeStates); - computePlayer1Matrix(); - - applyPreviousResultAsHint = false; - - // We only know a lower bound for the result - lowerResultBound = storm::utility::zero<ConstantType>(); - } - - template <typename SparseModelType, typename ConstantType> - std::unique_ptr<CheckResult> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) { - - if(maybeStates.empty()) { - return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(resultsForNonMaybeStates); - } - - parameterLifter->specifyRegion(region, dirForParameters); - - // Set up the solver - auto solver = solverFactory->create(player1Matrix, parameterLifter->getMatrix()); - if (storm::NumberTraits<ConstantType>::IsExact && dynamic_cast<storm::solver::StandardGameSolver<ConstantType>*>(solver.get())) { - STORM_LOG_INFO("Parameter Lifting: Setting solution method for exact Game Solver to policy iteration"); - auto* standardSolver = dynamic_cast<storm::solver::StandardGameSolver<ConstantType>*>(solver.get()); - auto settings = standardSolver->getSettings(); - settings.setSolutionMethod(storm::solver::StandardGameSolverSettings<ConstantType>::SolutionMethod::PolicyIteration); - standardSolver->setSettings(settings); - } - if (lowerResultBound) solver->setLowerBound(lowerResultBound.get()); - if (upperResultBound) solver->setUpperBound(upperResultBound.get()); - if (applyPreviousResultAsHint) { - solver->setTrackSchedulers(true); - x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>()); - if(storm::solver::minimize(dirForParameters) && minSchedChoices && player1SchedChoices) solver->setSchedulerHints(std::move(player1SchedChoices.get()), std::move(minSchedChoices.get())); - if(storm::solver::maximize(dirForParameters) && maxSchedChoices && player1SchedChoices) solver->setSchedulerHints(std::move(player1SchedChoices.get()), std::move(maxSchedChoices.get())); - } else { - x.assign(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>()); - } - if (this->currentCheckTask->isBoundSet() && this->currentCheckTask->getOptimizationDirection() == dirForParameters && solver->hasSchedulerHints()) { - // If we reach this point, we know that after applying the hints, the x-values can only become larger (if we maximize) or smaller (if we minimize). - std::unique_ptr<storm::solver::TerminationCondition<ConstantType>> termCond; - storm::storage::BitVector relevantStatesInSubsystem = this->currentCheckTask->isOnlyInitialStatesRelevantSet() ? this->parametricModel.getInitialStates() % maybeStates : storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true); - if (storm::solver::minimize(dirForParameters)) { - // Terminate if the value for ALL relevant states is already below the threshold - termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumBelowThreshold<ConstantType>> (relevantStatesInSubsystem, this->currentCheckTask->getBoundThreshold(), true, false); - } else { - // Terminate if the value for ALL relevant states is already above the threshold - termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumExceedsThreshold<ConstantType>> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), true); - } - solver->setTerminationCondition(std::move(termCond)); - } - - // Invoke the solver - if(stepBound) { - assert(*stepBound > 0); - solver->repeatedMultiply(this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, ¶meterLifter->getVector(), *stepBound); - } else { - solver->solveGame(this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, parameterLifter->getVector()); - if(applyPreviousResultAsHint) { - if(storm::solver::minimize(dirForParameters)) { - minSchedChoices = solver->getPlayer2SchedulerChoices(); - } else { - maxSchedChoices = solver->getPlayer2SchedulerChoices(); - } - player1SchedChoices = solver->getPlayer1SchedulerChoices(); - } - } - - // Get the result for the complete model (including maybestates) - std::vector<ConstantType> result = resultsForNonMaybeStates; - auto maybeStateResIt = x.begin(); - for(auto const& maybeState : maybeStates) { - result[maybeState] = *maybeStateResIt; - ++maybeStateResIt; - } - return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(std::move(result)); - } - - template <typename SparseModelType, typename ConstantType> - void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::computePlayer1Matrix() { - uint_fast64_t n = 0; - for(auto const& maybeState : maybeStates) { - n += this->parametricModel.getTransitionMatrix().getRowGroupSize(maybeState); - } - // The player 1 matrix is the identity matrix of size n with the row groups as given by the original matrix - storm::storage::SparseMatrixBuilder<storm::storage::sparse::state_type> matrixBuilder(n, n, n, true, true, maybeStates.getNumberOfSetBits()); - uint_fast64_t p1MatrixRow = 0; - for (auto maybeState : maybeStates){ - matrixBuilder.newRowGroup(p1MatrixRow); - for (uint_fast64_t row = this->parametricModel.getTransitionMatrix().getRowGroupIndices()[maybeState]; row < this->parametricModel.getTransitionMatrix().getRowGroupIndices()[maybeState + 1]; ++row){ - matrixBuilder.addNextValue(p1MatrixRow, p1MatrixRow, storm::utility::one<storm::storage::sparse::state_type>()); - ++p1MatrixRow; - } - } - player1Matrix = matrixBuilder.build(); - } - - template <typename SparseModelType, typename ConstantType> - void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::reset() { - maybeStates.resize(0); - resultsForNonMaybeStates.clear(); - stepBound = boost::none; - player1Matrix = storm::storage::SparseMatrix<storm::storage::sparse::state_type>(); - parameterLifter = nullptr; - minSchedChoices = boost::none; - maxSchedChoices = boost::none; - x.clear(); - lowerResultBound = boost::none; - upperResultBound = boost::none; - applyPreviousResultAsHint = false; - } - - template <typename SparseModelType, typename ConstantType> - boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMinScheduler() { - if (!minSchedChoices) { - return boost::none; - } - - storm::storage::Scheduler<ConstantType> result(minSchedChoices->size()); - uint_fast64_t state = 0; - for (auto const& schedulerChoice : minSchedChoices.get()) { - result.setChoice(schedulerChoice, state); - ++state; - } - - return result; - } - - template <typename SparseModelType, typename ConstantType> - boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMaxScheduler() { - if (!maxSchedChoices) { - return boost::none; - } - - storm::storage::Scheduler<ConstantType> result(maxSchedChoices->size()); - uint_fast64_t state = 0; - for (auto const& schedulerChoice : maxSchedChoices.get()) { - result.setChoice(schedulerChoice, state); - ++state; - } - - return result; - } - - template <typename SparseModelType, typename ConstantType> - boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentPlayer1Scheduler() { - if (!player1SchedChoices) { - return boost::none; - } - - storm::storage::Scheduler<ConstantType> result(player1SchedChoices->size()); - uint_fast64_t state = 0; - for (auto const& schedulerChoice : player1SchedChoices.get()) { - result.setChoice(schedulerChoice, state); - ++state; - } - - return result; - } - - template class SparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>; - template class SparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>; - } - } -} diff --git a/src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.h b/src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.h deleted file mode 100644 index 4e0b6e068..000000000 --- a/src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include <vector> -#include <memory> -#include <boost/optional.hpp> - -#include "storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h" -#include "storm/storage/BitVector.h" -#include "storm/storage/SparseMatrix.h" -#include "storm/storage/sparse/StateType.h" -#include "storm/solver/GameSolver.h" -#include "storm/transformer/ParameterLifter.h" -#include "storm/storage/Scheduler.h" - -namespace storm { - namespace modelchecker { - namespace parametric { - - template <typename SparseModelType, typename ConstantType> - class SparseMdpParameterLiftingModelChecker : public SparseParameterLiftingModelChecker<SparseModelType, ConstantType> { - public: - SparseMdpParameterLiftingModelChecker(SparseModelType const& parametricModel); - SparseMdpParameterLiftingModelChecker(SparseModelType const& parametricModel, std::unique_ptr<storm::solver::GameSolverFactory<ConstantType>>&& solverFactory); - - virtual bool canHandle(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const override; - - boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMinScheduler(); - boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMaxScheduler(); - boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentPlayer1Scheduler(); - - protected: - - virtual void specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) override; - virtual void specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) override; - virtual void specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) override; - virtual void specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) override; - - virtual std::unique_ptr<CheckResult> computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) override; - - virtual void reset() override; - - - private: - void computePlayer1Matrix(); - - storm::storage::BitVector maybeStates; - std::vector<ConstantType> resultsForNonMaybeStates; - boost::optional<uint_fast64_t> stepBound; - - storm::storage::SparseMatrix<storm::storage::sparse::state_type> player1Matrix; - std::unique_ptr<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>> parameterLifter; - std::unique_ptr<storm::solver::GameSolverFactory<ConstantType>> solverFactory; - - // Results from the most recent solver call. - boost::optional<std::vector<uint_fast64_t>> minSchedChoices, maxSchedChoices; - boost::optional<std::vector<uint_fast64_t>> player1SchedChoices; - std::vector<ConstantType> x; - boost::optional<ConstantType> lowerResultBound, upperResultBound; - bool applyPreviousResultAsHint; - }; - } - } -} diff --git a/src/storm/modelchecker/parametric/SparseMdpRegionChecker.cpp b/src/storm/modelchecker/parametric/SparseMdpRegionChecker.cpp deleted file mode 100644 index 9ffa707fa..000000000 --- a/src/storm/modelchecker/parametric/SparseMdpRegionChecker.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "storm/modelchecker/parametric/SparseMdpRegionChecker.h" - -#include "storm/adapters/RationalFunctionAdapter.h" - -#include "storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.h" -#include "storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.h" -#include "storm/transformer/SparseParametricMdpSimplifier.h" -#include "storm/models/sparse/StandardRewardModel.h" -#include "storm/models/sparse/Mdp.h" -#include "storm/utility/NumberTraits.h" - - -namespace storm { - namespace modelchecker { - namespace parametric { - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - SparseMdpRegionChecker<SparseModelType, ConstantType, ExactConstantType>::SparseMdpRegionChecker(SparseModelType const& parametricModel) : RegionChecker<SparseModelType, ConstantType, ExactConstantType>(parametricModel) { - // Intentionally left empty - } - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - void SparseMdpRegionChecker<SparseModelType, ConstantType, ExactConstantType>::simplifyParametricModel(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) { - storm::transformer::SparseParametricMdpSimplifier<SparseModelType> simplifier(this->parametricModel); - if(simplifier.simplify(checkTask.getFormula())) { - this->simplifiedModel = simplifier.getSimplifiedModel(); - this->currentFormula = simplifier.getSimplifiedFormula(); - } else { - this->simplifiedModel = nullptr; - this->currentFormula = checkTask.getFormula().asSharedPointer(); - } - } - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - void SparseMdpRegionChecker<SparseModelType, ConstantType, ExactConstantType>::initializeUnderlyingCheckers() { - if (this->settings.applyExactValidation) { - STORM_LOG_WARN_COND(!storm::NumberTraits<ConstantType>::IsExact, "Exact validation is not necessarry if the original computation is already exact"); - this->exactParameterLiftingChecker = std::make_unique<SparseMdpParameterLiftingModelChecker<SparseModelType, ExactConstantType>>(this->getConsideredParametricModel()); - } - this->parameterLiftingChecker = std::make_unique<SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>>(this->getConsideredParametricModel()); - this->instantiationChecker = std::make_unique<SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>>(this->getConsideredParametricModel()); - this->instantiationChecker->setInstantiationsAreGraphPreserving(true); - } - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType> - void SparseMdpRegionChecker<SparseModelType, ConstantType, ExactConstantType>::applyHintsToExactChecker() { - auto MdpPLChecker = dynamic_cast<storm::modelchecker::parametric::SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>*>(this->parameterLiftingChecker.get()); - STORM_LOG_ASSERT(MdpPLChecker, "Underlying Parameter lifting checker has unexpected type"); - auto exactMdpPLChecker = dynamic_cast<storm::modelchecker::parametric::SparseMdpParameterLiftingModelChecker<SparseModelType, ExactConstantType>*>(this->exactParameterLiftingChecker.get()); - STORM_LOG_ASSERT(exactMdpPLChecker, "Underlying exact parameter lifting checker has unexpected type"); - if (MdpPLChecker->getCurrentMaxScheduler()) { - exactMdpPLChecker->getCurrentMaxScheduler() = MdpPLChecker->getCurrentMaxScheduler()->template toValueType<ExactConstantType>(); - } - if (MdpPLChecker->getCurrentMinScheduler()) { - exactMdpPLChecker->getCurrentMinScheduler() = MdpPLChecker->getCurrentMinScheduler()->template toValueType<ExactConstantType>(); - } - if (MdpPLChecker->getCurrentPlayer1Scheduler()) { - exactMdpPLChecker->getCurrentPlayer1Scheduler() = MdpPLChecker->getCurrentPlayer1Scheduler()->template toValueType<ExactConstantType>(); - } - } - - -#ifdef STORM_HAVE_CARL - template class SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber>; - template class SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>; -#endif - } // namespace parametric - } //namespace modelchecker -} //namespace storm - diff --git a/src/storm/modelchecker/parametric/SparseMdpRegionChecker.h b/src/storm/modelchecker/parametric/SparseMdpRegionChecker.h deleted file mode 100644 index 72c355eee..000000000 --- a/src/storm/modelchecker/parametric/SparseMdpRegionChecker.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include <memory> - -#include "storm/modelchecker/parametric/RegionChecker.h" - -namespace storm { - namespace modelchecker{ - namespace parametric{ - - - template <typename SparseModelType, typename ConstantType, typename ExactConstantType = ConstantType> - class SparseMdpRegionChecker : public RegionChecker<SparseModelType, ConstantType, ExactConstantType> { - - public: - SparseMdpRegionChecker(SparseModelType const& parametricModel); - - protected: - - virtual void initializeUnderlyingCheckers() override; - virtual void simplifyParametricModel(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) override; - virtual void applyHintsToExactChecker() override; - - }; - - } //namespace parametric - } //namespace modelchecker -} //namespace storm diff --git a/src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.cpp b/src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.cpp deleted file mode 100644 index 8c9af8957..000000000 --- a/src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "SparseParameterLiftingModelChecker.h" - -#include "storm/adapters/RationalFunctionAdapter.h" -#include "storm/logic/FragmentSpecification.h" -#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" -#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" -#include "storm/models/sparse/Dtmc.h" -#include "storm/models/sparse/Mdp.h" -#include "storm/models/sparse/StandardRewardModel.h" - -#include "storm/exceptions/InvalidArgumentException.h" -#include "storm/exceptions/NotSupportedException.h" - -namespace storm { - namespace modelchecker { - namespace parametric { - - template <typename SparseModelType, typename ConstantType> - SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseParameterLiftingModelChecker(SparseModelType const& parametricModel) : parametricModel(parametricModel) { - //Intentionally left empty - } - - template <typename SparseModelType, typename ConstantType> - void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) { - reset(); - currentFormula = checkTask.getFormula().asSharedPointer(); - currentCheckTask = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, ConstantType>>(checkTask.substituteFormula(*currentFormula).template convertValueType<ConstantType>()); - - if(currentCheckTask->getFormula().isProbabilityOperatorFormula()) { - auto const& probOpFormula = currentCheckTask->getFormula().asProbabilityOperatorFormula(); - if(probOpFormula.getSubformula().isBoundedUntilFormula()) { - specifyBoundedUntilFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asBoundedUntilFormula())); - } else if(probOpFormula.getSubformula().isUntilFormula()) { - specifyUntilFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asUntilFormula())); - } else if (probOpFormula.getSubformula().isEventuallyFormula()) { - specifyReachabilityProbabilityFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asEventuallyFormula())); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); - } - } else if (currentCheckTask->getFormula().isRewardOperatorFormula()) { - auto const& rewOpFormula = currentCheckTask->getFormula().asRewardOperatorFormula(); - if(rewOpFormula.getSubformula().isEventuallyFormula()) { - specifyReachabilityRewardFormula(currentCheckTask->substituteFormula(rewOpFormula.getSubformula().asEventuallyFormula())); - } else if (rewOpFormula.getSubformula().isCumulativeRewardFormula()) { - specifyCumulativeRewardFormula(currentCheckTask->substituteFormula(rewOpFormula.getSubformula().asCumulativeRewardFormula())); - } - } - } - - template <typename SparseModelType, typename ConstantType> - std::unique_ptr<CheckResult> SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::check(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) { - auto quantitativeResult = computeQuantitativeValues(region, dirForParameters); - if(currentCheckTask->getFormula().hasQuantitativeResult()) { - return quantitativeResult; - } else { - return quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>()); - } - } - - template <typename SparseModelType, typename ConstantType> - void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyBoundedUntilFormula(CheckTask<logic::BoundedUntilFormula, ConstantType> const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); - } - - template <typename SparseModelType, typename ConstantType> - void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyUntilFormula(CheckTask<logic::UntilFormula, ConstantType> const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); - } - - template <typename SparseModelType, typename ConstantType> - void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityProbabilityFormula(CheckTask<logic::EventuallyFormula, ConstantType> const& checkTask) { - // transform to until formula - auto untilFormula = std::make_shared<storm::logic::UntilFormula const>(storm::logic::Formula::getTrueFormula(), checkTask.getFormula().getSubformula().asSharedPointer()); - specifyUntilFormula(currentCheckTask->substituteFormula(*untilFormula)); - } - - template <typename SparseModelType, typename ConstantType> - void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityRewardFormula(CheckTask<logic::EventuallyFormula, ConstantType> const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); - } - - template <typename SparseModelType, typename ConstantType> - void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyCumulativeRewardFormula(CheckTask<logic::CumulativeRewardFormula, ConstantType> const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property."); - } - - template class SparseParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>; - template class SparseParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>; - template class SparseParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>; - template class SparseParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>; - - } - } -} diff --git a/src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h b/src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h deleted file mode 100644 index c71d0d25d..000000000 --- a/src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "storm/logic/Formulas.h" -#include "storm/modelchecker/CheckTask.h" -#include "storm/modelchecker/results/CheckResult.h" -#include "storm/storage/ParameterRegion.h" -#include "storm/solver/OptimizationDirection.h" -#include "storm/utility/parametric.h" - -namespace storm { - namespace modelchecker { - namespace parametric { - - /*! - * Class to approximatively check a formula on a parametric model for all parameter valuations within a region - * It is assumed that all considered valuations are graph-preserving and well defined, i.e., - * * all non-const transition probabilities evaluate to some non-zero value - * * the sum of all outgoing transitions is one - */ - template <typename SparseModelType, typename ConstantType> - class SparseParameterLiftingModelChecker { - public: - SparseParameterLiftingModelChecker(SparseModelType const& parametricModel); - virtual ~SparseParameterLiftingModelChecker() = default; - - virtual bool canHandle(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const = 0; - - void specifyFormula(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask); - - /*! - * Checks the specified formula on the given region by applying parameter lifting (Parameter choices are lifted to nondeterministic choices) - * This yields a (sound) approximative model checking result. - - * @param region the region on which parameter lifting is applied - * @param dirForParameters The optimization direction for the parameter choices. If this is, e.g., minimize, then the returned result will be a lower bound for all results induced by the parameter evaluations inside the region. - */ - std::unique_ptr<CheckResult> check(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters); - - protected: - - virtual void specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask); - virtual void specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask); - virtual void specifyReachabilityProbabilityFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask); - virtual void specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask); - virtual void specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask); - - virtual std::unique_ptr<CheckResult> computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) = 0; - - virtual void reset() = 0; - - SparseModelType const& parametricModel; - std::unique_ptr<CheckTask<storm::logic::Formula, ConstantType>> currentCheckTask; - - private: - // store the current formula. Note that currentCheckTask only stores a reference to the formula. - std::shared_ptr<storm::logic::Formula const> currentFormula; - }; - } - } -} diff --git a/src/storm/settings/SettingsManager.cpp b/src/storm/settings/SettingsManager.cpp index a386dc94c..493ea71a2 100644 --- a/src/storm/settings/SettingsManager.cpp +++ b/src/storm/settings/SettingsManager.cpp @@ -30,7 +30,6 @@ #include "storm/settings/modules/GlpkSettings.h" #include "storm/settings/modules/GurobiSettings.h" #include "storm/settings/modules/Smt2SmtSolverSettings.h" -#include "storm/settings/modules/ParametricSettings.h" #include "storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h" #include "storm/settings/modules/ExplorationSettings.h" #include "storm/settings/modules/ResourceSettings.h" @@ -527,7 +526,6 @@ namespace storm { storm::settings::addModule<storm::settings::modules::GlpkSettings>(); storm::settings::addModule<storm::settings::modules::GurobiSettings>(); storm::settings::addModule<storm::settings::modules::TopologicalValueIterationEquationSolverSettings>(); - storm::settings::addModule<storm::settings::modules::ParametricSettings>(); storm::settings::addModule<storm::settings::modules::Smt2SmtSolverSettings>(); storm::settings::addModule<storm::settings::modules::ExplorationSettings>(); storm::settings::addModule<storm::settings::modules::ResourceSettings>(); diff --git a/src/storm/settings/modules/CoreSettings.cpp b/src/storm/settings/modules/CoreSettings.cpp index cb42bfd4b..964518b64 100644 --- a/src/storm/settings/modules/CoreSettings.cpp +++ b/src/storm/settings/modules/CoreSettings.cpp @@ -24,7 +24,6 @@ namespace storm { const std::string CoreSettings::dontFixDeadlockOptionShortName = "ndl"; const std::string CoreSettings::eqSolverOptionName = "eqsolver"; const std::string CoreSettings::lpSolverOptionName = "lpsolver"; - const std::string CoreSettings::parameterLiftingOptionName = "parameterlifting"; const std::string CoreSettings::smtSolverOptionName = "smtsolver"; const std::string CoreSettings::statisticsOptionName = "statistics"; const std::string CoreSettings::statisticsOptionShortName = "stats"; @@ -53,8 +52,6 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, lpSolverOptionName, false, "Sets which LP solver is preferred.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of an LP solver.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(lpSolvers)).setDefaultValueString("glpk").build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, parameterLiftingOptionName, false, "Sets whether parameter lifting is applied.").build()); - std::vector<std::string> smtSolvers = {"z3", "mathsat"}; this->addOption(storm::settings::OptionBuilder(moduleName, smtSolverOptionName, false, "Sets which SMT solver is preferred.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of an SMT solver.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(smtSolvers)).setDefaultValueString("z3").build()).build()); @@ -92,10 +89,6 @@ namespace storm { return this->getOption(eqSolverOptionName).getHasOptionBeenSet(); } - bool CoreSettings::isParameterLiftingSet() const { - return this->getOption(parameterLiftingOptionName).getHasOptionBeenSet(); - } - storm::solver::LpSolverType CoreSettings::getLpSolver() const { std::string lpSolverName = this->getOption(lpSolverOptionName).getArgumentByName("name").getValueAsString(); if (lpSolverName == "gurobi") { diff --git a/src/storm/settings/modules/CoreSettings.h b/src/storm/settings/modules/CoreSettings.h index 719449dd2..4f275b3d0 100644 --- a/src/storm/settings/modules/CoreSettings.h +++ b/src/storm/settings/modules/CoreSettings.h @@ -81,12 +81,6 @@ namespace storm { */ bool isEquationSolverSet() const; - /*! - * Retrieves whether parameter lifting should be applied. - * @return True iff parameter lifting should be applied. - */ - bool isParameterLiftingSet() const; - /*! * Retrieves the selected LP solver. * @@ -150,7 +144,6 @@ namespace storm { static const std::string dontFixDeadlockOptionShortName; static const std::string eqSolverOptionName; static const std::string lpSolverOptionName; - static const std::string parameterLiftingOptionName; static const std::string smtSolverOptionName; static const std::string statisticsOptionName; static const std::string statisticsOptionShortName; diff --git a/src/storm/settings/modules/ParametricSettings.cpp b/src/storm/settings/modules/ParametricSettings.cpp deleted file mode 100644 index e7e764426..000000000 --- a/src/storm/settings/modules/ParametricSettings.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "storm/settings/modules/ParametricSettings.h" - -#include "storm/settings/Option.h" -#include "storm/settings/OptionBuilder.h" -#include "storm/settings/ArgumentBuilder.h" -#include "storm/settings/Argument.h" - -#include "storm/utility/macros.h" -#include "storm/exceptions/IllegalArgumentValueException.h" - -namespace storm { - namespace settings { - namespace modules { - - const std::string ParametricSettings::moduleName = "parametric"; - const std::string ParametricSettings::encodeSmt2StrategyOptionName = "smt2strategy"; - const std::string ParametricSettings::exportSmt2DestinationPathOptionName = "smt2path"; - const std::string ParametricSettings::exportResultDestinationPathOptionName = "resultfile"; - const std::string ParametricSettings::parameterSpaceOptionName = "parameterspace"; - const std::string ParametricSettings::refinementThresholdOptionName = "refinementthreshold"; - const std::string ParametricSettings::exactValidationOptionName = "exactvalidation"; - const std::string ParametricSettings::derivativesOptionName = "derivatives"; - - ParametricSettings::ParametricSettings() : ModuleSettings(moduleName) { - this->addOption(storm::settings::OptionBuilder(moduleName, encodeSmt2StrategyOptionName, true, "Set the smt2 encoding strategy.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("strategy", "the used strategy").build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, exportSmt2DestinationPathOptionName, true, "A path to a file where the result should be saved.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("path", "the location.").addValidatorString(ArgumentValidatorFactory::createWritableFileValidator()).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, exportResultDestinationPathOptionName, true, "A path to a file where the smt2 encoding should be saved.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("path", "the location.").addValidatorString(ArgumentValidatorFactory::createWritableFileValidator()).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, parameterSpaceOptionName, true, "Sets the considered parameter-space (i.e., the initial region) for parameter lifting.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("region", "The parameter-space (given in format a<=x<=b,c<=y<=d).").build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, refinementThresholdOptionName, true, "Parameter space refinement converges if the fraction of unknown area falls below this threshold.") - .addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("threshold", "The threshold").setDefaultValueDouble(0.05).addValidatorDouble(storm::settings::ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0,1.0)).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, exactValidationOptionName, true, "Sets whether numerical results from Parameter lifting should be validated with exact techniques.").build()); - this->addOption(storm::settings::OptionBuilder(moduleName, derivativesOptionName, true, "Sets whether to generate the derivatives of the resulting rational function.").build()); - } - - bool ParametricSettings::exportResultToFile() const { - return this->getOption(exportResultDestinationPathOptionName).getHasOptionBeenSet(); - } - - std::string ParametricSettings::exportResultPath() const { - return this->getOption(exportResultDestinationPathOptionName).getArgumentByName("path").getValueAsString(); - } - - bool ParametricSettings::isParameterSpaceSet() const { - return this->getOption(parameterSpaceOptionName).getHasOptionBeenSet(); - } - - std::string ParametricSettings::getParameterSpace() const { - return this->getOption(parameterSpaceOptionName).getArgumentByName("region").getValueAsString(); - } - - double ParametricSettings::getRefinementThreshold() const { - return this->getOption(refinementThresholdOptionName).getArgumentByName("threshold").getValueAsDouble(); - } - - bool ParametricSettings::isExactValidationSet() const { - return this->getOption(exactValidationOptionName).getHasOptionBeenSet(); - } - - bool ParametricSettings::exportToSmt2File() const { - return this->getOption(exportSmt2DestinationPathOptionName).getHasOptionBeenSet(); - } - - std::string ParametricSettings::exportSmt2Path() const { - return this->getOption(exportSmt2DestinationPathOptionName).getArgumentByName("path").getValueAsString(); - } - - ParametricSettings::Smt2EncodingStrategy ParametricSettings::smt2EncodingStrategy() const { - std::string strategy = this->getOption(encodeSmt2StrategyOptionName).getArgumentByName("strategy").getValueAsString(); - - if(strategy == "fts") { - return Smt2EncodingStrategy::FULL_TRANSITION_SYSTEM; - } else if(strategy == "rf") { - return Smt2EncodingStrategy::RATIONAL_FUNCTION; - } else { - STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown smt2encoding strategy '" << strategy << "'."); - } - } - - bool ParametricSettings::isDerivativesSet() const { - return this->getOption(derivativesOptionName).getHasOptionBeenSet(); - } - - } // namespace modules - } // namespace settings -} // namespace storm diff --git a/src/storm/settings/modules/ParametricSettings.h b/src/storm/settings/modules/ParametricSettings.h deleted file mode 100644 index 54f2bbf86..000000000 --- a/src/storm/settings/modules/ParametricSettings.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef STORM_SETTINGS_MODULES_PARAMETRICSETTINGS_H_ -#define STORM_SETTINGS_MODULES_PARAMETRICSETTINGS_H_ - -#include "storm/settings/modules/ModuleSettings.h" - -namespace storm { - namespace settings { - namespace modules { - - /*! - * This class represents the settings for parametric model checking. - */ - class ParametricSettings : public ModuleSettings { - public: - /** - * A type for saving the Smt2EncondingStrategy. - * - * FULL_TRANSITION_SYSTEM: The transition system should be reduced only with very basic operations. - * ONLY_SCC_ENTRY_STATES: Scc elimination should be performed, but no further reduction. - * HIGH_INDEGREE: State elimination but for states with a high indegree. - * RATIONAL_FUNCTION: The smt file should contain only the rational function. - */ - enum class Smt2EncodingStrategy {FULL_TRANSITION_SYSTEM, ONLY_SCC_ENTRY_STATES, HIGH_INDEGREE, RATIONAL_FUNCTION}; - - /*! - * Creates a new set of parametric model checking settings. - */ - ParametricSettings(); - - /** - * Retrieves whether the model checking result should be exported to a file. - * @return True iff the result should be exported to a file. - */ - bool exportResultToFile() const; - - /** - * The path to a file location which should contain the model checking result. - * @return A path to a file location. - */ - std::string exportResultPath() const; - - /*! - * Retrieves whether the parameter space was declared - */ - bool isParameterSpaceSet() const; - - /*! - * Retrieves the given parameter spcae - */ - std::string getParameterSpace() const; - - /*! - * Retrieves the threshold considered for iterative region refinement. - * The refinement converges as soon as the fraction of unknown area falls below this threshold - */ - double getRefinementThreshold() const; - - /*! - * Retrieves whether exact validation should be performed - */ - bool isExactValidationSet() const; - - /** - * Retrieves whether the encoding of the transition system should be exported to a file. - * @return True iff the smt file should be encoded. - */ - bool exportToSmt2File() const; - - /** - * The path to a file location which should contain the smt2 encoding. - * @return A path to a file location. - */ - std::string exportSmt2Path() const; - - /** - * Retrieves which encoding strategy should be used for generating the smt2 file. - * @return The encoding strategy to be used. - */ - Smt2EncodingStrategy smt2EncodingStrategy() const; - - /*! - * Retrieves whether or not derivatives of the resulting rational function are to be generated. - * - * @return True if the derivatives are to be generated. - */ - bool isDerivativesSet() const; - - const static std::string moduleName; - - private: - const static std::string encodeSmt2StrategyOptionName; - const static std::string exportSmt2DestinationPathOptionName; - const static std::string exportResultDestinationPathOptionName; - const static std::string parameterSpaceOptionName; - const static std::string refinementThresholdOptionName; - const static std::string exactValidationOptionName; - const static std::string derivativesOptionName; - }; - - } // namespace modules - } // namespace settings -} // namespace storm - -#endif /* STORM_SETTINGS_MODULES_PARAMETRICSETTINGS_H_ */ diff --git a/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.cpp b/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.cpp index 0a1c03e4b..20357f400 100644 --- a/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.cpp +++ b/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.cpp @@ -14,72 +14,10 @@ namespace storm { namespace transformer { - - template <typename ValueType, typename RewardModelType> - std::shared_ptr<storm::models::sparse::Model<ValueType>> transformContinuousToDiscreteModel(std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> markovModel, std::shared_ptr<storm::logic::Formula const>& formula) { - boost::optional<std::string> timeRewardModelName; - if (formula->isTimeOperatorFormula()) { - auto const& timeOpFormula = formula->asTimeOperatorFormula(); - if (timeOpFormula.getSubformula().isReachabilityTimeFormula()) { - auto reachabilityRewardFormula = std::make_shared<storm::logic::EventuallyFormula>(storm::logic::CloneVisitor().clone(timeOpFormula.getSubformula().asReachabilityTimeFormula().getSubformula()), storm::logic::FormulaContext::Reward); - timeRewardModelName = "time"; - // make sure that the reward model name is not already in use - while (markovModel->hasRewardModel(*timeRewardModelName)) *timeRewardModelName += "_"; - formula = std::make_shared<storm::logic::RewardOperatorFormula const>(reachabilityRewardFormula, timeRewardModelName, timeOpFormula.getOperatorInformation()); - } - } - - if (markovModel->isOfType(storm::models::ModelType::Ctmc)) { - SparseCtmcToSparseDtmcTransformer<ValueType, RewardModelType> transformer; - if (transformer.transformationPreservesProperty(*formula)) { - STORM_LOG_INFO("Transforming Ctmc to embedded Dtmc..."); - return transformer.translate(*markovModel->template as<storm::models::sparse::Ctmc<ValueType>>(), timeRewardModelName); - } - } else if (markovModel->isOfType(storm::models::ModelType::MarkovAutomaton)) { - SparseMaToSparseMdpTransformer<ValueType, RewardModelType> transformer; - if (transformer.transformationPreservesProperty(*formula)) { - STORM_LOG_INFO("Transforming Markov automaton to embedded Mdp..."); - return transformer.translate(*markovModel->template as<storm::models::sparse::MarkovAutomaton<ValueType>>(), timeRewardModelName); - } - } else { - STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Model type " << markovModel->getType() << " not expected."); - } - return nullptr; - } - - template <typename ValueType, typename RewardModelType> - void transformContinuousToDiscreteModelInPlace(std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>>& markovModel, std::shared_ptr<storm::logic::Formula const>& formula) { - boost::optional<std::string> timeRewardModelName; - if (formula->isTimeOperatorFormula()) { - auto const& timeOpFormula = formula->asTimeOperatorFormula(); - if (timeOpFormula.getSubformula().isReachabilityTimeFormula()) { - auto reachabilityRewardFormula = std::make_shared<storm::logic::EventuallyFormula>(storm::logic::CloneVisitor().clone(timeOpFormula.getSubformula().asReachabilityTimeFormula().getSubformula()), storm::logic::FormulaContext::Reward); - timeRewardModelName = "time"; - // make sure that the reward model name is not already in use - while (markovModel->hasRewardModel(*timeRewardModelName)) *timeRewardModelName += "_"; - formula = std::make_shared<storm::logic::RewardOperatorFormula const>(reachabilityRewardFormula, timeRewardModelName, timeOpFormula.getOperatorInformation()); - } - } - - if (markovModel->isOfType(storm::models::ModelType::Ctmc)) { - SparseCtmcToSparseDtmcTransformer<ValueType, RewardModelType> transformer; - if (transformer.transformationPreservesProperty(*formula)) { - STORM_LOG_INFO("Transforming Ctmc to embedded Dtmc..."); - markovModel = transformer.translate(std::move(*markovModel->template as<storm::models::sparse::Ctmc<ValueType>>()), timeRewardModelName); - } - } else if (markovModel->isOfType(storm::models::ModelType::MarkovAutomaton)) { - SparseMaToSparseMdpTransformer<ValueType, RewardModelType> transformer; - if (transformer.transformationPreservesProperty(*formula)) { - STORM_LOG_INFO("Transforming Markov automaton to embedded Mdp..."); - markovModel = transformer.translate(std::move(*markovModel->template as<storm::models::sparse::MarkovAutomaton<ValueType>>()), timeRewardModelName); - } - } else { - STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Model type " << markovModel->getType() << " not expected."); - } - } + template <typename ValueType, typename RewardModelType> - std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> SparseCtmcToSparseDtmcTransformer<ValueType, RewardModelType>::translate(storm::models::sparse::Ctmc<ValueType, RewardModelType> const& ctmc, boost::optional<std::string> const& timeRewardModelName) { + std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> ContinuousToDiscreteTimeModelTransformer<ValueType, RewardModelType>::transform(storm::models::sparse::Ctmc<ValueType, RewardModelType> const& ctmc, boost::optional<std::string> const& timeRewardModelName) { // Init the dtmc components storm::storage::sparse::ModelComponents<ValueType, RewardModelType> dtmcComponents(ctmc.getTransitionMatrix(), ctmc.getStateLabeling(), ctmc.getRewardModels()); dtmcComponents.choiceLabeling = ctmc.getOptionalChoiceLabeling(); @@ -113,7 +51,7 @@ namespace storm { } template <typename ValueType, typename RewardModelType> - std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> SparseCtmcToSparseDtmcTransformer<ValueType, RewardModelType>::translate(storm::models::sparse::Ctmc<ValueType, RewardModelType>&& ctmc, boost::optional<std::string> const& timeRewardModelName) { + std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> ContinuousToDiscreteTimeModelTransformer<ValueType, RewardModelType>::transform(storm::models::sparse::Ctmc<ValueType, RewardModelType>&& ctmc, boost::optional<std::string> const& timeRewardModelName) { // Init the dtmc components storm::storage::sparse::ModelComponents<ValueType, RewardModelType> dtmcComponents(std::move(ctmc.getTransitionMatrix()), std::move(ctmc.getStateLabeling()), std::move(ctmc.getRewardModels())); dtmcComponents.choiceLabeling = std::move(ctmc.getOptionalChoiceLabeling()); @@ -144,7 +82,7 @@ namespace storm { } template <typename ValueType, typename RewardModelType> - bool SparseCtmcToSparseDtmcTransformer<ValueType, RewardModelType>::transformationPreservesProperty(storm::logic::Formula const& formula) { + bool ContinuousToDiscreteTimeModelTransformer<ValueType, RewardModelType>::preservesFormula(storm::logic::Formula const& formula) { storm::logic::FragmentSpecification fragment = storm::logic::propositional(); fragment.setProbabilityOperatorsAllowed(true); fragment.setGloballyFormulasAllowed(true); @@ -158,7 +96,7 @@ namespace storm { template <typename ValueType, typename RewardModelType> - std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> SparseMaToSparseMdpTransformer<ValueType, RewardModelType>::translate(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType> const& ma, boost::optional<std::string> const& timeRewardModelName) { + std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> ContinuousToDiscreteTimeModelTransformer<ValueType, RewardModelType>::transform(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType> const& ma, boost::optional<std::string> const& timeRewardModelName) { STORM_LOG_THROW(ma.isClosed(), storm::exceptions::InvalidArgumentException, "Transformation of MA to its underlying MDP is only possible for closed MAs"); // Init the mdp components @@ -174,8 +112,12 @@ namespace storm { for (auto& rewardModel : mdpComponents.rewardModels) { if (rewardModel.second.hasStateRewards()) { auto& stateRewards = rewardModel.second.getStateRewardVector(); - for (auto state : ma.getMarkovianStates()) { - stateRewards[state] /= exitRates[state]; + for (uint_fast64_t state = 0; state < stateRewards.size(); ++state) { + if (ma.getMarkovianStates().get(state)) { + stateRewards[state] /= exitRates[state]; + } else { + stateRewards[state] = storm::utility::zero<ValueType>(); + } } } } @@ -195,7 +137,7 @@ namespace storm { } template <typename ValueType, typename RewardModelType> - std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> SparseMaToSparseMdpTransformer<ValueType, RewardModelType>::translate(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType>&& ma, boost::optional<std::string> const& timeRewardModelName) { + std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> ContinuousToDiscreteTimeModelTransformer<ValueType, RewardModelType>::transform(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType>&& ma, boost::optional<std::string> const& timeRewardModelName) { STORM_LOG_THROW(ma.isClosed(), storm::exceptions::InvalidArgumentException, "Transformation of MA to its underlying MDP is only possible for closed MAs"); std::vector<ValueType>& exitRates = ma.getExitRates(); @@ -211,8 +153,12 @@ namespace storm { for (auto& rewardModel : mdpComponents.rewardModels) { if (rewardModel.second.hasStateRewards()) { auto& stateRewards = rewardModel.second.getStateRewardVector(); - for (auto state : ma.getMarkovianStates()) { - stateRewards[state] /= exitRates[state]; + for (uint_fast64_t state = 0; state < stateRewards.size(); ++state) { + if (ma.getMarkovianStates().get(state)) { + stateRewards[state] /= exitRates[state]; + } else { + stateRewards[state] = storm::utility::zero<ValueType>(); + } } } } @@ -231,31 +177,8 @@ namespace storm { return std::make_shared<storm::models::sparse::Mdp<ValueType, RewardModelType>>(std::move(mdpComponents)); } - template <typename ValueType, typename RewardModelType> - bool SparseMaToSparseMdpTransformer<ValueType, RewardModelType>::transformationPreservesProperty(storm::logic::Formula const& formula) { - storm::logic::FragmentSpecification fragment = storm::logic::propositional(); - fragment.setProbabilityOperatorsAllowed(true); - fragment.setGloballyFormulasAllowed(true); - fragment.setReachabilityProbabilityFormulasAllowed(true); - fragment.setNextFormulasAllowed(true); - fragment.setUntilFormulasAllowed(true); - fragment.setRewardOperatorsAllowed(true); - fragment.setReachabilityRewardFormulasAllowed(true); - - return formula.isInFragment(fragment); - } - - template std::shared_ptr<storm::models::sparse::Model<double>> transformContinuousToDiscreteModel(std::shared_ptr<storm::models::sparse::Model<double>> markovModel, std::shared_ptr<storm::logic::Formula const>& formula); - template std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> transformContinuousToDiscreteModel(std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> markovModel, std::shared_ptr<storm::logic::Formula const>& formula); - template std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> transformContinuousToDiscreteModel(std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> markovModel, std::shared_ptr<storm::logic::Formula const>& formula); - template void transformContinuousToDiscreteModelInPlace<double>(std::shared_ptr<storm::models::sparse::Model<double>>& markovModel, std::shared_ptr<storm::logic::Formula const>& formula); - template void transformContinuousToDiscreteModelInPlace<storm::RationalNumber>(std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>>& markovModel, std::shared_ptr<storm::logic::Formula const>& formula); - template void transformContinuousToDiscreteModelInPlace<storm::RationalFunction>(std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>>& markovModel, std::shared_ptr<storm::logic::Formula const>& formula); - template class SparseCtmcToSparseDtmcTransformer<double>; - template class SparseCtmcToSparseDtmcTransformer<storm::RationalNumber>; - template class SparseCtmcToSparseDtmcTransformer<storm::RationalFunction>; - template class SparseMaToSparseMdpTransformer<double>; - template class SparseMaToSparseMdpTransformer<storm::RationalNumber>; - template class SparseMaToSparseMdpTransformer<storm::RationalFunction>; + template class ContinuousToDiscreteTimeModelTransformer<double>; + template class ContinuousToDiscreteTimeModelTransformer<storm::RationalNumber>; + template class ContinuousToDiscreteTimeModelTransformer<storm::RationalFunction>; } } diff --git a/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.h b/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.h index cea1bf367..d26b96c1f 100644 --- a/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.h +++ b/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.h @@ -12,41 +12,23 @@ namespace storm { namespace transformer { - - // Transforms the given continuous model to a discrete time model. - // If such a transformation does not preserve the given formula, the transformation does not take place and the original model is returned - // Moreover, the given formula might be changed (e.g. TimeOperatorFormulas become RewardOperatorFormulas). - template <typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>> - std::shared_ptr<storm::models::sparse::Model<ValueType>> transformContinuousToDiscreteModel(std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> markovModel, std::shared_ptr<storm::logic::Formula const>& formula); - - // Transforms the given continuous model to a discrete time model IN PLACE (i.e., the continuous model will be invalidated). - // If such a transformation does not preserve the given formula, the transformation does not take place. - // Moreover, the given formula might be changed (e.g. TimeOperatorFormulas become RewardOperatorFormulas). template <typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>> - void transformContinuousToDiscreteModelInPlace(std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>>& markovModel, std::shared_ptr<storm::logic::Formula const>& formula); - - template <typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>> - class SparseCtmcToSparseDtmcTransformer { + class ContinuousToDiscreteTimeModelTransformer { public: + + // If this method returns true, the given formula is preserced by the transformation + static bool preservesFormula(storm::logic::Formula const& formula); + // Transforms the given CTMC to its underlying (aka embedded) DTMC. // A reward model for time is added if a corresponding reward model name is given - static std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> translate(storm::models::sparse::Ctmc<ValueType, RewardModelType> const& ctmc, boost::optional<std::string> const& timeRewardModelName = boost::none); - static std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> translate(storm::models::sparse::Ctmc<ValueType, RewardModelType>&& ctmc, boost::optional<std::string> const& timeRewardModelName = boost::none); + static std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> transform(storm::models::sparse::Ctmc<ValueType, RewardModelType> const& ctmc, boost::optional<std::string> const& timeRewardModelName = boost::none); + static std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> transform(storm::models::sparse::Ctmc<ValueType, RewardModelType>&& ctmc, boost::optional<std::string> const& timeRewardModelName = boost::none); - // If this method returns true, the given formula is preserced by the transformation - static bool transformationPreservesProperty(storm::logic::Formula const& formula); - }; - - template <typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>> - class SparseMaToSparseMdpTransformer { - public: // Transforms the given MA to its underlying (aka embedded) MDP. // A reward model for time is added if a corresponding reward model name is given - static std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> translate(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType> const& ma, boost::optional<std::string> const& timeRewardModelName = boost::none); - static std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> translate(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType>&& ma, boost::optional<std::string> const& timeRewardModelName = boost::none); + static std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> transform(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType> const& ma, boost::optional<std::string> const& timeRewardModelName = boost::none); + static std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> transform(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType>&& ma, boost::optional<std::string> const& timeRewardModelName = boost::none); - // If this method returns true, the given formula is preserved by the transformation - static bool transformationPreservesProperty(storm::logic::Formula const& formula); }; } } diff --git a/src/storm/transformer/SymbolicToSparseTransformer.cpp b/src/storm/transformer/SymbolicToSparseTransformer.cpp index ec026968f..69b02acfb 100644 --- a/src/storm/transformer/SymbolicToSparseTransformer.cpp +++ b/src/storm/transformer/SymbolicToSparseTransformer.cpp @@ -11,22 +11,6 @@ namespace storm { namespace transformer { - template<storm::dd::DdType Type, typename ValueType> - std::shared_ptr<storm::models::sparse::Model<ValueType>> transformSymbolicToSparseModel(std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> const& symbolicModel) { - switch (symbolicModel->getType()) { - case storm::models::ModelType::Dtmc: - return SymbolicDtmcToSparseDtmcTransformer<Type, ValueType>().translate(*symbolicModel->template as<storm::models::symbolic::Dtmc<Type, ValueType>>()); - case storm::models::ModelType::Mdp: - return SymbolicMdpToSparseMdpTransformer<Type, ValueType>::translate(*symbolicModel->template as<storm::models::symbolic::Mdp<Type, ValueType>>()); - case storm::models::ModelType::Ctmc: - return SymbolicCtmcToSparseCtmcTransformer<Type, ValueType>::translate(*symbolicModel->template as<storm::models::symbolic::Ctmc<Type, ValueType>>()); - default: - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Transformation of symbolic " << symbolicModel->getType() << " to sparse model is not implemented."); - } - return nullptr; - } - - template<storm::dd::DdType Type, typename ValueType> std::shared_ptr<storm::models::sparse::Dtmc<ValueType>> SymbolicDtmcToSparseDtmcTransformer<Type, ValueType>::translate(storm::models::symbolic::Dtmc<Type, ValueType> const& symbolicDtmc) { this->odd = symbolicDtmc.getReachableStates().createOdd(); @@ -121,11 +105,6 @@ namespace storm { return std::make_shared<storm::models::sparse::Ctmc<ValueType>>(transitionMatrix, labelling, rewardModels); } - template std::shared_ptr<storm::models::sparse::Model<double>> transformSymbolicToSparseModel<storm::dd::DdType::CUDD, double>(std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::CUDD, double>> const& symbolicModel); - template std::shared_ptr<storm::models::sparse::Model<double>> transformSymbolicToSparseModel<storm::dd::DdType::Sylvan, double>(std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::Sylvan, double>> const& symbolicModel); - template std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> transformSymbolicToSparseModel<storm::dd::DdType::Sylvan, storm::RationalNumber>(std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::Sylvan, storm::RationalNumber>> const& symbolicModel); - template std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> transformSymbolicToSparseModel<storm::dd::DdType::Sylvan, storm::RationalFunction>(std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::Sylvan, storm::RationalFunction>> const& symbolicModel); - template class SymbolicDtmcToSparseDtmcTransformer<storm::dd::DdType::CUDD, double>; template class SymbolicDtmcToSparseDtmcTransformer<storm::dd::DdType::Sylvan, double>; template class SymbolicDtmcToSparseDtmcTransformer<storm::dd::DdType::Sylvan, storm::RationalNumber>; diff --git a/src/storm/transformer/SymbolicToSparseTransformer.h b/src/storm/transformer/SymbolicToSparseTransformer.h index b55eb7ea9..5f4bed6c4 100644 --- a/src/storm/transformer/SymbolicToSparseTransformer.h +++ b/src/storm/transformer/SymbolicToSparseTransformer.h @@ -12,9 +12,6 @@ namespace storm { namespace transformer { - template<storm::dd::DdType Type, typename ValueType> - std::shared_ptr<storm::models::sparse::Model<ValueType>> transformSymbolicToSparseModel(std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> const& symbolicModel); - template<storm::dd::DdType Type, typename ValueType> class SymbolicDtmcToSparseDtmcTransformer { public: diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index d6dbe8207..d870d2b21 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -1,23 +1,2 @@ -# Base path for test files -set(STORM_TESTS_BASE_PATH "${PROJECT_SOURCE_DIR}/src/test") - -# Test Sources -file(GLOB_RECURSE ALL_FILES ${STORM_TESTS_BASE_PATH}/*.h ${STORM_TESTS_BASE_PATH}/*.cpp) - -register_source_groups_from_filestructure("${ALL_FILES}" test) - -# Note that the tests also need the source files, except for the main file -include_directories(${GTEST_INCLUDE_DIR}) - -foreach (testsuite abstraction adapter builder logic modelchecker parser permissiveschedulers solver storage transformer utility) - - file(GLOB_RECURSE TEST_${testsuite}_FILES ${STORM_TESTS_BASE_PATH}/${testsuite}/*.h ${STORM_TESTS_BASE_PATH}/${testsuite}/*.cpp) - add_executable (test-${testsuite} ${TEST_${testsuite}_FILES} ${STORM_TESTS_BASE_PATH}/storm-test.cpp) - target_link_libraries(test-${testsuite} storm) - target_link_libraries(test-${testsuite} ${STORM_TEST_LINK_LIBRARIES}) - - add_dependencies(test-${testsuite} test-resources) - add_test(NAME run-test-${testsuite} COMMAND $<TARGET_FILE:test-${testsuite}>) - add_dependencies(tests test-${testsuite}) - -endforeach () +add_subdirectory(storm) +add_subdirectory(storm-pars) \ No newline at end of file diff --git a/src/test/modelchecker/SparseDtmcParameterLiftingTest.cpp b/src/test/modelchecker/SparseDtmcParameterLiftingTest.cpp deleted file mode 100644 index e4fa1d161..000000000 --- a/src/test/modelchecker/SparseDtmcParameterLiftingTest.cpp +++ /dev/null @@ -1,385 +0,0 @@ -#include "gtest/gtest.h" -#include "storm-config.h" - -#ifdef STORM_HAVE_CARL - -#include "storm/adapters/RationalFunctionAdapter.h" - -#include "storm/modelchecker/parametric/SparseDtmcRegionChecker.h" -#include "storm/storage/ParameterRegion.h" - -#include "storm/api/storm.h" - -TEST(SparseDtmcParameterLiftingTest, Brp_Prob) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; - std::string formulaAsString = "P<=0.84 [F s=5 ]"; - std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 - - // Program and formula - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pL<=0.9,0.75<=pK<=0.95", modelParameters); - auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.4<=pL<=0.65,0.75<=pK<=0.95", modelParameters); - auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pL<=0.73,0.2<=pK<=0.715", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseDtmcParameterLiftingTest, Brp_Rew) { - std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm"; - std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]"; - std::string constantsAsString = "pL=0.9,TOAck=0.5"; - carl::VariablePool::getInstance().clear(); - - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters); - auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters); - auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseDtmcParameterLiftingTest, Brp_Rew_Bounded) { - std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm"; - std::string formulaAsString = "R>2.5 [ C<=300]"; - std::string constantsAsString = "pL=0.9,TOAck=0.5"; - carl::VariablePool::getInstance().clear(); - - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters); - auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters); - auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseDtmcParameterLiftingTest, Brp_Prob_exactValidation) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; - std::string formulaAsString = "P<=0.84 [F s=5 ]"; - std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 - - // Program and formula - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - auto settings = regionChecker.getSettings(); - settings.applyExactValidation = true; - regionChecker.setSettings(settings); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pL<=0.9,0.75<=pK<=0.95", modelParameters); - auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.4<=pL<=0.65,0.75<=pK<=0.95", modelParameters); - auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pL<=0.73,0.2<=pK<=0.715", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseDtmcParameterLiftingTest, Brp_Rew_exactValidation) { - std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm"; - std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]"; - std::string constantsAsString = "pL=0.9,TOAck=0.5"; - carl::VariablePool::getInstance().clear(); - - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - auto settings = regionChecker.getSettings(); - settings.applyExactValidation = true; - regionChecker.setSettings(settings); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters); - auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters); - auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseDtmcParameterLiftingTest, Brp_Rew_Bounded_exactValidation) { - std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm"; - std::string formulaAsString = "R>2.5 [ C<=300]"; - std::string constantsAsString = "pL=0.9,TOAck=0.5"; - carl::VariablePool::getInstance().clear(); - - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - auto settings = regionChecker.getSettings(); - settings.applyExactValidation = true; - regionChecker.setSettings(settings); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters); - auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters); - auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseDtmcParameterLiftingTest, Brp_Rew_Infty) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm"; - std::string formulaAsString = "R>2.5 [F (s=0&srep=3) ]"; - std::string constantsAsString = ""; - carl::VariablePool::getInstance().clear(); - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseDtmcParameterLiftingTest, Brp_Rew_4Par) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm"; - std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]"; - std::string constantsAsString = ""; //!! this model will have 4 parameters - carl::VariablePool::getInstance().clear(); - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters); - auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.7,0.2<=pL<=0.8,0.15<=TOMsg<=0.65,0.3<=TOAck<=0.9", modelParameters); - auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.4,0.2<=pL<=0.3,0.15<=TOMsg<=0.3,0.1<=TOAck<=0.2", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseDtmcParameterLiftingTest, Crowds_Prob) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm"; - std::string formulaAsString = "P<0.5 [F \"observe0Greater1\" ]"; - std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 - carl::VariablePool::getInstance().clear(); - - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=PF<=0.75,0.15<=badC<=0.2", modelParameters); - auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.75<=PF<=0.8,0.2<=badC<=0.3", modelParameters); - auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.8<=PF<=0.95,0.2<=badC<=0.2", modelParameters); - auto allVioHardRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.8<=PF<=0.95,0.2<=badC<=0.9", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::CenterViolated, regionChecker.analyzeRegion(allVioHardRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseDtmcParameterLiftingTest, Crowds_Prob_stepBounded) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm"; - std::string formulaAsString = "P<0.5 [F<=300 \"observe0Greater1\" ]"; - std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 - carl::VariablePool::getInstance().clear(); - - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=PF<=0.75,0.15<=badC<=0.2", modelParameters); - auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.75<=PF<=0.8,0.2<=badC<=0.3", modelParameters); - auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.8<=PF<=0.95,0.2<=badC<=0.2", modelParameters); - auto allVioHardRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.8<=PF<=0.95,0.2<=badC<=0.9", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::CenterViolated, regionChecker.analyzeRegion(allVioHardRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseDtmcParameterLiftingTest, Crowds_Prob_1Par) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm"; - std::string formulaAsString = "P>0.75 [F \"observe0Greater1\" ]"; - std::string constantsAsString = "badC=0.3"; //e.g. pL=0.9,TOACK=0.5 - carl::VariablePool::getInstance().clear(); - - - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.9<=PF<=0.99", modelParameters); - auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.8<=PF<=0.9", modelParameters); - auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.01<=PF<=0.8", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseDtmcParameterLiftingTest, Crowds_Prob_Const) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm"; - std::string formulaAsString = "P>0.6 [F \"observe0Greater1\" ]"; - std::string constantsAsString = "PF=0.9,badC=0.2"; - carl::VariablePool::getInstance().clear(); - - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -#endif diff --git a/src/test/modelchecker/SparseMdpParameterLiftingTest.cpp b/src/test/modelchecker/SparseMdpParameterLiftingTest.cpp deleted file mode 100644 index b51b33df0..000000000 --- a/src/test/modelchecker/SparseMdpParameterLiftingTest.cpp +++ /dev/null @@ -1,313 +0,0 @@ -#include "gtest/gtest.h" -#include "storm-config.h" - -#ifdef STORM_HAVE_CARL - -#include "storm/adapters/RationalFunctionAdapter.h" - -#include "storm/modelchecker/parametric/SparseMdpRegionChecker.h" -#include "storm/storage/ParameterRegion.h" - -#include "storm/api/storm.h" - -TEST(SparseMdpParameterLiftingTest, two_dice_Prob) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm"; - std::string formulaFile = "P<=0.17 [ F \"doubles\" ]"; - - carl::VariablePool::getInstance().clear(); - - storm::prism::Program program = storm::api::parseProgram(programFile); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program)); - std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - auto allSatRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters); - auto exBothRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters); - auto allVioRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters); - - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseMdpParameterLiftingTest, two_dice_Prob_bounded) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm"; - std::string formulaFile = "P<=0.17 [ F<100 \"doubles\" ]"; - - carl::VariablePool::getInstance().clear(); - - storm::prism::Program program = storm::api::parseProgram(programFile); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program)); - std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - auto allSatRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters); - auto exBothRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters); - auto allVioRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters); - - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseMdpParameterLiftingTest, two_dice_Prob_exactValidation) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm"; - std::string formulaFile = "P<=0.17 [ F \"doubles\" ]"; - - carl::VariablePool::getInstance().clear(); - - storm::prism::Program program = storm::api::parseProgram(programFile); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program)); - std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - auto allSatRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters); - auto exBothRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters); - auto allVioRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters); - - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseMdpParameterLiftingTest, two_dice_Prob_bounded_exactValidation) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm"; - std::string formulaFile = "P<=0.17 [ F<100 \"doubles\" ]"; - - carl::VariablePool::getInstance().clear(); - - storm::prism::Program program = storm::api::parseProgram(programFile); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program)); - std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - auto allSatRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters); - auto exBothRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters); - auto allVioRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters); - - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseMdpParameterLiftingTest, coin_Prob) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/coin2_2.nm"; - std::string formulaAsString = "P>0.25 [F \"finished\"&\"all_coins_equal_1\" ]"; - - storm::prism::Program program = storm::api::parseProgram(programFile); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.3<=p1<=0.45,0.2<=p2<=0.54", modelParameters); - auto exBothRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.4<=p1<=0.65,0.5<=p2<=0.7", modelParameters); - auto allVioRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.4<=p1<=0.7,0.55<=p2<=0.6", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseMdpParameterLiftingTest, brp_Prop) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm"; - std::string formulaAsString = "P<=0.84 [ F (s=5 & T) ]"; - std::string constantsAsString = "TOMsg=0.0,TOAck=0.0"; - - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pL<=0.9,0.75<=pK<=0.95", modelParameters); - auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.4<=pL<=0.65,0.75<=pK<=0.95", modelParameters); - auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pL<=0.73,0.2<=pK<=0.715", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseMdpParameterLiftingTest, brp_Rew) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm"; - std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]"; - std::string constantsAsString = "pL=0.9,TOAck=0.5"; - - - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters); - auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters); - auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseMdpParameterLiftingTest, brp_Rew_bounded) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm"; - std::string formulaAsString = "R>2.5 [ C<=300 ]"; - std::string constantsAsString = "pL=0.9,TOAck=0.5"; - - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters); - auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters); - auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - - -TEST(SparseMdpParameterLiftingTest, Brp_Rew_Infty) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm"; - std::string formulaAsString = "R>2.5 [F (s=0&srep=3) ]"; - std::string constantsAsString = ""; - carl::VariablePool::getInstance().clear(); - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - -TEST(SparseMdpParameterLiftingTest, Brp_Rew_4Par) { - - std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm"; - std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]"; - std::string constantsAsString = ""; //!! this model will have 4 parameters - carl::VariablePool::getInstance().clear(); - storm::prism::Program program = storm::api::parseProgram(programFile); - program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); - std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); - auto rewParameters = storm::models::sparse::getRewardParameters(*model); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model); - regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true)); - - //start testing - auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters); - auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.7,0.2<=pL<=0.8,0.15<=TOMsg<=0.65,0.3<=TOAck<=0.9", modelParameters); - auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.4,0.2<=pL<=0.3,0.15<=TOMsg<=0.3,0.1<=TOAck<=0.2", modelParameters); - - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true)); - - carl::VariablePool::getInstance().clear(); -} - - - - - -#endif diff --git a/src/test/storm-pars/CMakeLists.txt b/src/test/storm-pars/CMakeLists.txt new file mode 100644 index 000000000..0f2793553 --- /dev/null +++ b/src/test/storm-pars/CMakeLists.txt @@ -0,0 +1,23 @@ +# Base path for test files +set(STORM_TESTS_BASE_PATH "${PROJECT_SOURCE_DIR}/src/test/storm-pars") + +# Test Sources +file(GLOB_RECURSE ALL_FILES ${STORM_TESTS_BASE_PATH}/*.h ${STORM_TESTS_BASE_PATH}/*.cpp) + +register_source_groups_from_filestructure("${ALL_FILES}" test) + +# Note that the tests also need the source files, except for the main file +include_directories(${GTEST_INCLUDE_DIR}) + +foreach (testsuite modelchecker utility) + + file(GLOB_RECURSE TEST_${testsuite}_FILES ${STORM_TESTS_BASE_PATH}/${testsuite}/*.h ${STORM_TESTS_BASE_PATH}/${testsuite}/*.cpp) + add_executable (test-pars-${testsuite} ${TEST_${testsuite}_FILES} ${STORM_TESTS_BASE_PATH}/storm-test.cpp) + target_link_libraries(test-pars-${testsuite} storm-pars) + target_link_libraries(test-pars-${testsuite} ${STORM_TEST_LINK_LIBRARIES}) + + add_dependencies(test-pars-${testsuite} test-resources) + add_test(NAME run-test-pars-${testsuite} COMMAND $<TARGET_FILE:test-pars-${testsuite}>) + add_dependencies(tests test-pars-${testsuite}) + +endforeach () diff --git a/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp b/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp new file mode 100644 index 000000000..31def397a --- /dev/null +++ b/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp @@ -0,0 +1,362 @@ +#include "gtest/gtest.h" +#include "storm-config.h" + +#ifdef STORM_HAVE_CARL + +#include "storm/adapters/RationalFunctionAdapter.h" + +#include "storm-pars/api/storm-pars.h" +#include "storm/api/storm.h" + +TEST(SparseDtmcParameterLiftingTest, Brp_Prob) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; + std::string formulaAsString = "P<=0.84 [F s=5 ]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pL<=0.9,0.75<=pK<=0.95", modelParameters); + auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.4<=pL<=0.65,0.75<=pK<=0.95", modelParameters); + auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.73,0.2<=pK<=0.715", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseDtmcParameterLiftingTest, Brp_Rew) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm"; + std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]"; + std::string constantsAsString = "pL=0.9,TOAck=0.5"; + carl::VariablePool::getInstance().clear(); + + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters); + auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters); + auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseDtmcParameterLiftingTest, Brp_Rew_Bounded) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm"; + std::string formulaAsString = "R>2.5 [ C<=300]"; + std::string constantsAsString = "pL=0.9,TOAck=0.5"; + carl::VariablePool::getInstance().clear(); + + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters); + auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters); + auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseDtmcParameterLiftingTest, Brp_Prob_exactValidation) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; + std::string formulaAsString = "P<=0.84 [F s=5 ]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + + auto regionChecker = storm::api::initializeValidatingRegionModelChecker<storm::RationalFunction, double, storm::RationalNumber>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pL<=0.9,0.75<=pK<=0.95", modelParameters); + auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.4<=pL<=0.65,0.75<=pK<=0.95", modelParameters); + auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.73,0.2<=pK<=0.715", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseDtmcParameterLiftingTest, Brp_Rew_exactValidation) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm"; + std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]"; + std::string constantsAsString = "pL=0.9,TOAck=0.5"; + carl::VariablePool::getInstance().clear(); + + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeValidatingRegionModelChecker<storm::RationalFunction, double, storm::RationalNumber>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters); + auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters); + auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseDtmcParameterLiftingTest, Brp_Rew_Bounded_exactValidation) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm"; + std::string formulaAsString = "R>2.5 [ C<=300]"; + std::string constantsAsString = "pL=0.9,TOAck=0.5"; + carl::VariablePool::getInstance().clear(); + + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeValidatingRegionModelChecker<storm::RationalFunction, double, storm::RationalNumber>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters); + auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters); + auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseDtmcParameterLiftingTest, Brp_Rew_Infty) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm"; + std::string formulaAsString = "R>2.5 [F (s=0&srep=3) ]"; + std::string constantsAsString = ""; + carl::VariablePool::getInstance().clear(); + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseDtmcParameterLiftingTest, Brp_Rew_4Par) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm"; + std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]"; + std::string constantsAsString = ""; //!! this model will have 4 parameters + carl::VariablePool::getInstance().clear(); + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters); + auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.7,0.2<=pL<=0.8,0.15<=TOMsg<=0.65,0.3<=TOAck<=0.9", modelParameters); + auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.4,0.2<=pL<=0.3,0.15<=TOMsg<=0.3,0.1<=TOAck<=0.2", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseDtmcParameterLiftingTest, Crowds_Prob) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm"; + std::string formulaAsString = "P<0.5 [F \"observe0Greater1\" ]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + carl::VariablePool::getInstance().clear(); + + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=PF<=0.75,0.15<=badC<=0.2", modelParameters); + auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.75<=PF<=0.8,0.2<=badC<=0.3", modelParameters); + auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.8<=PF<=0.95,0.2<=badC<=0.2", modelParameters); + auto allVioHardRegion=storm::api::parseRegion<storm::RationalFunction>("0.8<=PF<=0.95,0.2<=badC<=0.9", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::CenterViolated, regionChecker->analyzeRegion(allVioHardRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseDtmcParameterLiftingTest, Crowds_Prob_stepBounded) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm"; + std::string formulaAsString = "P<0.5 [F<=300 \"observe0Greater1\" ]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + carl::VariablePool::getInstance().clear(); + + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=PF<=0.75,0.15<=badC<=0.2", modelParameters); + auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.75<=PF<=0.8,0.2<=badC<=0.3", modelParameters); + auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.8<=PF<=0.95,0.2<=badC<=0.2", modelParameters); + auto allVioHardRegion=storm::api::parseRegion<storm::RationalFunction>("0.8<=PF<=0.95,0.2<=badC<=0.9", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::CenterViolated, regionChecker->analyzeRegion(allVioHardRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseDtmcParameterLiftingTest, Crowds_Prob_1Par) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm"; + std::string formulaAsString = "P>0.75 [F \"observe0Greater1\" ]"; + std::string constantsAsString = "badC=0.3"; //e.g. pL=0.9,TOACK=0.5 + carl::VariablePool::getInstance().clear(); + + + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.9<=PF<=0.99", modelParameters); + auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.8<=PF<=0.9", modelParameters); + auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.01<=PF<=0.8", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseDtmcParameterLiftingTest, Crowds_Prob_Const) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm"; + std::string formulaAsString = "P>0.6 [F \"observe0Greater1\" ]"; + std::string constantsAsString = "PF=0.9,badC=0.2"; + carl::VariablePool::getInstance().clear(); + + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +#endif diff --git a/src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp b/src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp new file mode 100644 index 000000000..fd690b876 --- /dev/null +++ b/src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp @@ -0,0 +1,301 @@ +#include "gtest/gtest.h" +#include "storm-config.h" + +#ifdef STORM_HAVE_CARL + +#include "storm/adapters/RationalFunctionAdapter.h" + +#include "storm-pars/api/storm-pars.h" +#include "storm/api/storm.h" + +TEST(SparseMdpParameterLiftingTest, two_dice_Prob) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm"; + std::string formulaFile = "P<=0.17 [ F \"doubles\" ]"; + + carl::VariablePool::getInstance().clear(); + + storm::prism::Program program = storm::api::parseProgram(programFile); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program)); + std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + auto allSatRegion = storm::api::parseRegion<storm::RationalFunction>("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters); + auto exBothRegion = storm::api::parseRegion<storm::RationalFunction>("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters); + auto allVioRegion = storm::api::parseRegion<storm::RationalFunction>("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters); + + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseMdpParameterLiftingTest, two_dice_Prob_bounded) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm"; + std::string formulaFile = "P<=0.17 [ F<100 \"doubles\" ]"; + + carl::VariablePool::getInstance().clear(); + + storm::prism::Program program = storm::api::parseProgram(programFile); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program)); + std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + auto allSatRegion = storm::api::parseRegion<storm::RationalFunction>("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters); + auto exBothRegion = storm::api::parseRegion<storm::RationalFunction>("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters); + auto allVioRegion = storm::api::parseRegion<storm::RationalFunction>("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters); + + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseMdpParameterLiftingTest, two_dice_Prob_exactValidation) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm"; + std::string formulaFile = "P<=0.17 [ F \"doubles\" ]"; + + carl::VariablePool::getInstance().clear(); + + storm::prism::Program program = storm::api::parseProgram(programFile); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program)); + std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeValidatingRegionModelChecker<storm::RationalFunction, double, storm::RationalNumber>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + auto allSatRegion = storm::api::parseRegion<storm::RationalFunction>("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters); + auto exBothRegion = storm::api::parseRegion<storm::RationalFunction>("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters); + auto allVioRegion = storm::api::parseRegion<storm::RationalFunction>("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters); + + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseMdpParameterLiftingTest, two_dice_Prob_bounded_exactValidation) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm"; + std::string formulaFile = "P<=0.17 [ F<100 \"doubles\" ]"; + + carl::VariablePool::getInstance().clear(); + + storm::prism::Program program = storm::api::parseProgram(programFile); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program)); + std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeValidatingRegionModelChecker<storm::RationalFunction, double, storm::RationalNumber>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + auto allSatRegion = storm::api::parseRegion<storm::RationalFunction>("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters); + auto exBothRegion = storm::api::parseRegion<storm::RationalFunction>("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters); + auto allVioRegion = storm::api::parseRegion<storm::RationalFunction>("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters); + + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseMdpParameterLiftingTest, coin_Prob) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/coin2_2.nm"; + std::string formulaAsString = "P>0.25 [F \"finished\"&\"all_coins_equal_1\" ]"; + + storm::prism::Program program = storm::api::parseProgram(programFile); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion = storm::api::parseRegion<storm::RationalFunction>("0.3<=p1<=0.45,0.2<=p2<=0.54", modelParameters); + auto exBothRegion = storm::api::parseRegion<storm::RationalFunction>("0.4<=p1<=0.65,0.5<=p2<=0.7", modelParameters); + auto allVioRegion = storm::api::parseRegion<storm::RationalFunction>("0.4<=p1<=0.7,0.55<=p2<=0.6", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseMdpParameterLiftingTest, brp_Prop) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm"; + std::string formulaAsString = "P<=0.84 [ F (s=5 & T) ]"; + std::string constantsAsString = "TOMsg=0.0,TOAck=0.0"; + + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pL<=0.9,0.75<=pK<=0.95", modelParameters); + auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.4<=pL<=0.65,0.75<=pK<=0.95", modelParameters); + auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.73,0.2<=pK<=0.715", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseMdpParameterLiftingTest, brp_Rew) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm"; + std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]"; + std::string constantsAsString = "pL=0.9,TOAck=0.5"; + + + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters); + auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters); + auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseMdpParameterLiftingTest, brp_Rew_bounded) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm"; + std::string formulaAsString = "R>2.5 [ C<=300 ]"; + std::string constantsAsString = "pL=0.9,TOAck=0.5"; + + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters); + auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters); + auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + + +TEST(SparseMdpParameterLiftingTest, Brp_Rew_Infty) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm"; + std::string formulaAsString = "R>2.5 [F (s=0&srep=3) ]"; + std::string constantsAsString = ""; + carl::VariablePool::getInstance().clear(); + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + +TEST(SparseMdpParameterLiftingTest, Brp_Rew_4Par) { + + std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm"; + std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]"; + std::string constantsAsString = ""; //!! this model will have 4 parameters + carl::VariablePool::getInstance().clear(); + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*model); + auto rewParameters = storm::models::sparse::getRewardParameters(*model); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true)); + + //start testing + auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters); + auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.7,0.2<=pL<=0.8,0.15<=TOMsg<=0.65,0.3<=TOAck<=0.9", modelParameters); + auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.4,0.2<=pL<=0.3,0.15<=TOMsg<=0.3,0.1<=TOAck<=0.2", modelParameters); + + EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true)); + EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true)); + + carl::VariablePool::getInstance().clear(); +} + + + + + +#endif diff --git a/src/test/storm-pars/storm-test.cpp b/src/test/storm-pars/storm-test.cpp new file mode 100644 index 000000000..203c56b40 --- /dev/null +++ b/src/test/storm-pars/storm-test.cpp @@ -0,0 +1,8 @@ +#include "gtest/gtest.h" +#include "storm/settings/SettingsManager.h" + +int main(int argc, char **argv) { + storm::settings::initializeAll("Storm-pars (Functional) Testing Suite", "test-pars"); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/test/utility/ModelInstantiatorTest.cpp b/src/test/storm-pars/utility/ModelInstantiatorTest.cpp similarity index 99% rename from src/test/utility/ModelInstantiatorTest.cpp rename to src/test/storm-pars/utility/ModelInstantiatorTest.cpp index 07859c600..e66a912d5 100644 --- a/src/test/utility/ModelInstantiatorTest.cpp +++ b/src/test/storm-pars/utility/ModelInstantiatorTest.cpp @@ -11,8 +11,8 @@ #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/GeneralSettings.h" +#include "storm-pars/utility/ModelInstantiator.h" #include "storm/api/storm.h" -#include "utility/ModelInstantiator.h" #include "storm/models/sparse/Model.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/Mdp.h" diff --git a/src/test/storm/CMakeLists.txt b/src/test/storm/CMakeLists.txt new file mode 100644 index 000000000..0ae2fc509 --- /dev/null +++ b/src/test/storm/CMakeLists.txt @@ -0,0 +1,23 @@ +# Base path for test files +set(STORM_TESTS_BASE_PATH "${PROJECT_SOURCE_DIR}/src/test/storm") + +# Test Sources +file(GLOB_RECURSE ALL_FILES ${STORM_TESTS_BASE_PATH}/*.h ${STORM_TESTS_BASE_PATH}/*.cpp) + +register_source_groups_from_filestructure("${ALL_FILES}" test) + +# Note that the tests also need the source files, except for the main file +include_directories(${GTEST_INCLUDE_DIR}) + +foreach (testsuite abstraction adapter builder logic modelchecker parser permissiveschedulers solver storage transformer utility) + + file(GLOB_RECURSE TEST_${testsuite}_FILES ${STORM_TESTS_BASE_PATH}/${testsuite}/*.h ${STORM_TESTS_BASE_PATH}/${testsuite}/*.cpp) + add_executable (test-${testsuite} ${TEST_${testsuite}_FILES} ${STORM_TESTS_BASE_PATH}/storm-test.cpp) + target_link_libraries(test-${testsuite} storm) + target_link_libraries(test-${testsuite} ${STORM_TEST_LINK_LIBRARIES}) + + add_dependencies(test-${testsuite} test-resources) + add_test(NAME run-test-${testsuite} COMMAND $<TARGET_FILE:test-${testsuite}>) + add_dependencies(tests test-${testsuite}) + +endforeach () diff --git a/src/test/abstraction/PrismMenuGameTest.cpp b/src/test/storm/abstraction/PrismMenuGameTest.cpp similarity index 100% rename from src/test/abstraction/PrismMenuGameTest.cpp rename to src/test/storm/abstraction/PrismMenuGameTest.cpp diff --git a/src/test/adapter/MathsatExpressionAdapterTest.cpp b/src/test/storm/adapter/MathsatExpressionAdapterTest.cpp similarity index 100% rename from src/test/adapter/MathsatExpressionAdapterTest.cpp rename to src/test/storm/adapter/MathsatExpressionAdapterTest.cpp diff --git a/src/test/adapter/Z3ExpressionAdapterTest.cpp b/src/test/storm/adapter/Z3ExpressionAdapterTest.cpp similarity index 100% rename from src/test/adapter/Z3ExpressionAdapterTest.cpp rename to src/test/storm/adapter/Z3ExpressionAdapterTest.cpp diff --git a/src/test/builder/DdJaniModelBuilderTest.cpp b/src/test/storm/builder/DdJaniModelBuilderTest.cpp similarity index 100% rename from src/test/builder/DdJaniModelBuilderTest.cpp rename to src/test/storm/builder/DdJaniModelBuilderTest.cpp diff --git a/src/test/builder/DdPrismModelBuilderTest.cpp b/src/test/storm/builder/DdPrismModelBuilderTest.cpp similarity index 100% rename from src/test/builder/DdPrismModelBuilderTest.cpp rename to src/test/storm/builder/DdPrismModelBuilderTest.cpp diff --git a/src/test/builder/ExplicitJaniModelBuilderTest.cpp b/src/test/storm/builder/ExplicitJaniModelBuilderTest.cpp similarity index 100% rename from src/test/builder/ExplicitJaniModelBuilderTest.cpp rename to src/test/storm/builder/ExplicitJaniModelBuilderTest.cpp diff --git a/src/test/builder/ExplicitJitJaniModelBuilderTest.cpp b/src/test/storm/builder/ExplicitJitJaniModelBuilderTest.cpp similarity index 100% rename from src/test/builder/ExplicitJitJaniModelBuilderTest.cpp rename to src/test/storm/builder/ExplicitJitJaniModelBuilderTest.cpp diff --git a/src/test/builder/ExplicitPrismModelBuilderTest.cpp b/src/test/storm/builder/ExplicitPrismModelBuilderTest.cpp similarity index 100% rename from src/test/builder/ExplicitPrismModelBuilderTest.cpp rename to src/test/storm/builder/ExplicitPrismModelBuilderTest.cpp diff --git a/src/test/logic/FragmentCheckerTest.cpp b/src/test/storm/logic/FragmentCheckerTest.cpp similarity index 100% rename from src/test/logic/FragmentCheckerTest.cpp rename to src/test/storm/logic/FragmentCheckerTest.cpp diff --git a/src/test/modelchecker/EigenDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/EigenDtmcPrctlModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/EigenDtmcPrctlModelCheckerTest.cpp rename to src/test/storm/modelchecker/EigenDtmcPrctlModelCheckerTest.cpp diff --git a/src/test/modelchecker/GameBasedDtmcModelCheckerTest.cpp b/src/test/storm/modelchecker/GameBasedDtmcModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/GameBasedDtmcModelCheckerTest.cpp rename to src/test/storm/modelchecker/GameBasedDtmcModelCheckerTest.cpp diff --git a/src/test/modelchecker/GameBasedMdpModelCheckerTest.cpp b/src/test/storm/modelchecker/GameBasedMdpModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/GameBasedMdpModelCheckerTest.cpp rename to src/test/storm/modelchecker/GameBasedMdpModelCheckerTest.cpp diff --git a/src/test/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp b/src/test/storm/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp rename to src/test/storm/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp diff --git a/src/test/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp rename to src/test/storm/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp diff --git a/src/test/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp b/src/test/storm/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp rename to src/test/storm/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp diff --git a/src/test/modelchecker/GmmxxHybridDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/GmmxxHybridDtmcPrctlModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/GmmxxHybridDtmcPrctlModelCheckerTest.cpp rename to src/test/storm/modelchecker/GmmxxHybridDtmcPrctlModelCheckerTest.cpp diff --git a/src/test/modelchecker/GmmxxHybridMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/GmmxxHybridMdpPrctlModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/GmmxxHybridMdpPrctlModelCheckerTest.cpp rename to src/test/storm/modelchecker/GmmxxHybridMdpPrctlModelCheckerTest.cpp diff --git a/src/test/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp rename to src/test/storm/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp diff --git a/src/test/modelchecker/NativeCtmcCslModelCheckerTest.cpp b/src/test/storm/modelchecker/NativeCtmcCslModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/NativeCtmcCslModelCheckerTest.cpp rename to src/test/storm/modelchecker/NativeCtmcCslModelCheckerTest.cpp diff --git a/src/test/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp rename to src/test/storm/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp diff --git a/src/test/modelchecker/NativeHybridCtmcCslModelCheckerTest.cpp b/src/test/storm/modelchecker/NativeHybridCtmcCslModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/NativeHybridCtmcCslModelCheckerTest.cpp rename to src/test/storm/modelchecker/NativeHybridCtmcCslModelCheckerTest.cpp diff --git a/src/test/modelchecker/NativeHybridDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/NativeHybridDtmcPrctlModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/NativeHybridDtmcPrctlModelCheckerTest.cpp rename to src/test/storm/modelchecker/NativeHybridDtmcPrctlModelCheckerTest.cpp diff --git a/src/test/modelchecker/NativeHybridMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/NativeHybridMdpPrctlModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/NativeHybridMdpPrctlModelCheckerTest.cpp rename to src/test/storm/modelchecker/NativeHybridMdpPrctlModelCheckerTest.cpp diff --git a/src/test/modelchecker/NativeMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/NativeMdpPrctlModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/NativeMdpPrctlModelCheckerTest.cpp rename to src/test/storm/modelchecker/NativeMdpPrctlModelCheckerTest.cpp diff --git a/src/test/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp rename to src/test/storm/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp diff --git a/src/test/modelchecker/SparseExplorationModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseExplorationModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/SparseExplorationModelCheckerTest.cpp rename to src/test/storm/modelchecker/SparseExplorationModelCheckerTest.cpp diff --git a/src/test/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp rename to src/test/storm/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp diff --git a/src/test/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp rename to src/test/storm/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp diff --git a/src/test/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp rename to src/test/storm/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp diff --git a/src/test/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp rename to src/test/storm/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp diff --git a/src/test/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp rename to src/test/storm/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp diff --git a/src/test/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp rename to src/test/storm/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp diff --git a/src/test/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp similarity index 100% rename from src/test/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp rename to src/test/storm/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp diff --git a/src/test/parser/.gitignore b/src/test/storm/parser/.gitignore similarity index 100% rename from src/test/parser/.gitignore rename to src/test/storm/parser/.gitignore diff --git a/src/test/parser/AutoParserTest.cpp b/src/test/storm/parser/AutoParserTest.cpp similarity index 100% rename from src/test/parser/AutoParserTest.cpp rename to src/test/storm/parser/AutoParserTest.cpp diff --git a/src/test/parser/DeterministicModelParserTest.cpp b/src/test/storm/parser/DeterministicModelParserTest.cpp similarity index 100% rename from src/test/parser/DeterministicModelParserTest.cpp rename to src/test/storm/parser/DeterministicModelParserTest.cpp diff --git a/src/test/parser/DeterministicSparseTransitionParserTest.cpp b/src/test/storm/parser/DeterministicSparseTransitionParserTest.cpp similarity index 100% rename from src/test/parser/DeterministicSparseTransitionParserTest.cpp rename to src/test/storm/parser/DeterministicSparseTransitionParserTest.cpp diff --git a/src/test/parser/DirectEncodingParserTest.cpp b/src/test/storm/parser/DirectEncodingParserTest.cpp similarity index 100% rename from src/test/parser/DirectEncodingParserTest.cpp rename to src/test/storm/parser/DirectEncodingParserTest.cpp diff --git a/src/test/parser/FormulaParserTest.cpp b/src/test/storm/parser/FormulaParserTest.cpp similarity index 100% rename from src/test/parser/FormulaParserTest.cpp rename to src/test/storm/parser/FormulaParserTest.cpp diff --git a/src/test/parser/MappedFileTest.cpp b/src/test/storm/parser/MappedFileTest.cpp similarity index 100% rename from src/test/parser/MappedFileTest.cpp rename to src/test/storm/parser/MappedFileTest.cpp diff --git a/src/test/parser/MarkovAutomatonParserTest.cpp b/src/test/storm/parser/MarkovAutomatonParserTest.cpp similarity index 100% rename from src/test/parser/MarkovAutomatonParserTest.cpp rename to src/test/storm/parser/MarkovAutomatonParserTest.cpp diff --git a/src/test/parser/MarkovAutomatonSparseTransitionParserTest.cpp b/src/test/storm/parser/MarkovAutomatonSparseTransitionParserTest.cpp similarity index 100% rename from src/test/parser/MarkovAutomatonSparseTransitionParserTest.cpp rename to src/test/storm/parser/MarkovAutomatonSparseTransitionParserTest.cpp diff --git a/src/test/parser/NondeterministicModelParserTest.cpp b/src/test/storm/parser/NondeterministicModelParserTest.cpp similarity index 100% rename from src/test/parser/NondeterministicModelParserTest.cpp rename to src/test/storm/parser/NondeterministicModelParserTest.cpp diff --git a/src/test/parser/NondeterministicSparseTransitionParserTest.cpp b/src/test/storm/parser/NondeterministicSparseTransitionParserTest.cpp similarity index 100% rename from src/test/parser/NondeterministicSparseTransitionParserTest.cpp rename to src/test/storm/parser/NondeterministicSparseTransitionParserTest.cpp diff --git a/src/test/parser/PrismParserTest.cpp b/src/test/storm/parser/PrismParserTest.cpp similarity index 100% rename from src/test/parser/PrismParserTest.cpp rename to src/test/storm/parser/PrismParserTest.cpp diff --git a/src/test/parser/SparseItemLabelingParserTest.cpp b/src/test/storm/parser/SparseItemLabelingParserTest.cpp similarity index 100% rename from src/test/parser/SparseItemLabelingParserTest.cpp rename to src/test/storm/parser/SparseItemLabelingParserTest.cpp diff --git a/src/test/parser/SparseStateRewardParserTest.cpp b/src/test/storm/parser/SparseStateRewardParserTest.cpp similarity index 100% rename from src/test/parser/SparseStateRewardParserTest.cpp rename to src/test/storm/parser/SparseStateRewardParserTest.cpp diff --git a/src/test/permissiveschedulers/MilpPermissiveSchedulerTest.cpp b/src/test/storm/permissiveschedulers/MilpPermissiveSchedulerTest.cpp similarity index 100% rename from src/test/permissiveschedulers/MilpPermissiveSchedulerTest.cpp rename to src/test/storm/permissiveschedulers/MilpPermissiveSchedulerTest.cpp diff --git a/src/test/permissiveschedulers/SmtPermissiveSchedulerTest.cpp b/src/test/storm/permissiveschedulers/SmtPermissiveSchedulerTest.cpp similarity index 100% rename from src/test/permissiveschedulers/SmtPermissiveSchedulerTest.cpp rename to src/test/storm/permissiveschedulers/SmtPermissiveSchedulerTest.cpp diff --git a/src/test/solver/CudaPluginTest.cpp b/src/test/storm/solver/CudaPluginTest.cpp similarity index 100% rename from src/test/solver/CudaPluginTest.cpp rename to src/test/storm/solver/CudaPluginTest.cpp diff --git a/src/test/solver/EigenLinearEquationSolverTest.cpp b/src/test/storm/solver/EigenLinearEquationSolverTest.cpp similarity index 100% rename from src/test/solver/EigenLinearEquationSolverTest.cpp rename to src/test/storm/solver/EigenLinearEquationSolverTest.cpp diff --git a/src/test/solver/EliminationLinearEquationSolverTest.cpp b/src/test/storm/solver/EliminationLinearEquationSolverTest.cpp similarity index 100% rename from src/test/solver/EliminationLinearEquationSolverTest.cpp rename to src/test/storm/solver/EliminationLinearEquationSolverTest.cpp diff --git a/src/test/solver/FullySymbolicGameSolverTest.cpp b/src/test/storm/solver/FullySymbolicGameSolverTest.cpp similarity index 100% rename from src/test/solver/FullySymbolicGameSolverTest.cpp rename to src/test/storm/solver/FullySymbolicGameSolverTest.cpp diff --git a/src/test/solver/GameSolverTest.cpp b/src/test/storm/solver/GameSolverTest.cpp similarity index 100% rename from src/test/solver/GameSolverTest.cpp rename to src/test/storm/solver/GameSolverTest.cpp diff --git a/src/test/solver/GlpkLpSolverTest.cpp b/src/test/storm/solver/GlpkLpSolverTest.cpp similarity index 100% rename from src/test/solver/GlpkLpSolverTest.cpp rename to src/test/storm/solver/GlpkLpSolverTest.cpp diff --git a/src/test/solver/GmmxxLinearEquationSolverTest.cpp b/src/test/storm/solver/GmmxxLinearEquationSolverTest.cpp similarity index 100% rename from src/test/solver/GmmxxLinearEquationSolverTest.cpp rename to src/test/storm/solver/GmmxxLinearEquationSolverTest.cpp diff --git a/src/test/solver/GmmxxMinMaxLinearEquationSolverTest.cpp b/src/test/storm/solver/GmmxxMinMaxLinearEquationSolverTest.cpp similarity index 100% rename from src/test/solver/GmmxxMinMaxLinearEquationSolverTest.cpp rename to src/test/storm/solver/GmmxxMinMaxLinearEquationSolverTest.cpp diff --git a/src/test/solver/GurobiLpSolverTest.cpp b/src/test/storm/solver/GurobiLpSolverTest.cpp similarity index 100% rename from src/test/solver/GurobiLpSolverTest.cpp rename to src/test/storm/solver/GurobiLpSolverTest.cpp diff --git a/src/test/solver/MathsatSmtSolverTest.cpp b/src/test/storm/solver/MathsatSmtSolverTest.cpp similarity index 100% rename from src/test/solver/MathsatSmtSolverTest.cpp rename to src/test/storm/solver/MathsatSmtSolverTest.cpp diff --git a/src/test/solver/MinMaxTechniqueSelectionTest.cpp b/src/test/storm/solver/MinMaxTechniqueSelectionTest.cpp similarity index 100% rename from src/test/solver/MinMaxTechniqueSelectionTest.cpp rename to src/test/storm/solver/MinMaxTechniqueSelectionTest.cpp diff --git a/src/test/solver/NativeLinearEquationSolverTest.cpp b/src/test/storm/solver/NativeLinearEquationSolverTest.cpp similarity index 100% rename from src/test/solver/NativeLinearEquationSolverTest.cpp rename to src/test/storm/solver/NativeLinearEquationSolverTest.cpp diff --git a/src/test/solver/NativeMinMaxLinearEquationSolverTest.cpp b/src/test/storm/solver/NativeMinMaxLinearEquationSolverTest.cpp similarity index 100% rename from src/test/solver/NativeMinMaxLinearEquationSolverTest.cpp rename to src/test/storm/solver/NativeMinMaxLinearEquationSolverTest.cpp diff --git a/src/test/solver/Z3LpSolverTest.cpp b/src/test/storm/solver/Z3LpSolverTest.cpp similarity index 100% rename from src/test/solver/Z3LpSolverTest.cpp rename to src/test/storm/solver/Z3LpSolverTest.cpp diff --git a/src/test/solver/Z3SmtSolverTest.cpp b/src/test/storm/solver/Z3SmtSolverTest.cpp similarity index 100% rename from src/test/solver/Z3SmtSolverTest.cpp rename to src/test/storm/solver/Z3SmtSolverTest.cpp diff --git a/src/test/storage/BitVectorHashMapTest.cpp b/src/test/storm/storage/BitVectorHashMapTest.cpp similarity index 100% rename from src/test/storage/BitVectorHashMapTest.cpp rename to src/test/storm/storage/BitVectorHashMapTest.cpp diff --git a/src/test/storage/BitVectorTest.cpp b/src/test/storm/storage/BitVectorTest.cpp similarity index 100% rename from src/test/storage/BitVectorTest.cpp rename to src/test/storm/storage/BitVectorTest.cpp diff --git a/src/test/storage/CuddDdTest.cpp b/src/test/storm/storage/CuddDdTest.cpp similarity index 100% rename from src/test/storage/CuddDdTest.cpp rename to src/test/storm/storage/CuddDdTest.cpp diff --git a/src/test/storage/DeterministicModelBisimulationDecompositionTest.cpp b/src/test/storm/storage/DeterministicModelBisimulationDecompositionTest.cpp similarity index 100% rename from src/test/storage/DeterministicModelBisimulationDecompositionTest.cpp rename to src/test/storm/storage/DeterministicModelBisimulationDecompositionTest.cpp diff --git a/src/test/storage/ExpressionEvalutionTest.cpp b/src/test/storm/storage/ExpressionEvalutionTest.cpp similarity index 100% rename from src/test/storage/ExpressionEvalutionTest.cpp rename to src/test/storm/storage/ExpressionEvalutionTest.cpp diff --git a/src/test/storage/ExpressionTest.cpp b/src/test/storm/storage/ExpressionTest.cpp similarity index 100% rename from src/test/storage/ExpressionTest.cpp rename to src/test/storm/storage/ExpressionTest.cpp diff --git a/src/test/storage/JaniModelTest.cpp b/src/test/storm/storage/JaniModelTest.cpp similarity index 100% rename from src/test/storage/JaniModelTest.cpp rename to src/test/storm/storage/JaniModelTest.cpp diff --git a/src/test/storage/MaximalEndComponentDecompositionTest.cpp b/src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp similarity index 100% rename from src/test/storage/MaximalEndComponentDecompositionTest.cpp rename to src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp diff --git a/src/test/storage/NondeterministicModelBisimulationDecompositionTest.cpp b/src/test/storm/storage/NondeterministicModelBisimulationDecompositionTest.cpp similarity index 100% rename from src/test/storage/NondeterministicModelBisimulationDecompositionTest.cpp rename to src/test/storm/storage/NondeterministicModelBisimulationDecompositionTest.cpp diff --git a/src/test/storage/PrismProgramTest.cpp b/src/test/storm/storage/PrismProgramTest.cpp similarity index 100% rename from src/test/storage/PrismProgramTest.cpp rename to src/test/storm/storage/PrismProgramTest.cpp diff --git a/src/test/storage/SchedulerTest.cpp b/src/test/storm/storage/SchedulerTest.cpp similarity index 100% rename from src/test/storage/SchedulerTest.cpp rename to src/test/storm/storage/SchedulerTest.cpp diff --git a/src/test/storage/SparseMatrixTest.cpp b/src/test/storm/storage/SparseMatrixTest.cpp similarity index 100% rename from src/test/storage/SparseMatrixTest.cpp rename to src/test/storm/storage/SparseMatrixTest.cpp diff --git a/src/test/storage/StronglyConnectedComponentDecompositionTest.cpp b/src/test/storm/storage/StronglyConnectedComponentDecompositionTest.cpp similarity index 100% rename from src/test/storage/StronglyConnectedComponentDecompositionTest.cpp rename to src/test/storm/storage/StronglyConnectedComponentDecompositionTest.cpp diff --git a/src/test/storage/SylvanDdTest.cpp b/src/test/storm/storage/SylvanDdTest.cpp similarity index 100% rename from src/test/storage/SylvanDdTest.cpp rename to src/test/storm/storage/SylvanDdTest.cpp diff --git a/src/test/storm-test.cpp b/src/test/storm/storm-test.cpp similarity index 100% rename from src/test/storm-test.cpp rename to src/test/storm/storm-test.cpp diff --git a/src/test/transformer/EndComponentEliminatorTest.cpp b/src/test/storm/transformer/EndComponentEliminatorTest.cpp similarity index 100% rename from src/test/transformer/EndComponentEliminatorTest.cpp rename to src/test/storm/transformer/EndComponentEliminatorTest.cpp diff --git a/src/test/utility/GraphTest.cpp b/src/test/storm/utility/GraphTest.cpp similarity index 100% rename from src/test/utility/GraphTest.cpp rename to src/test/storm/utility/GraphTest.cpp diff --git a/src/test/utility/KSPTest.cpp b/src/test/storm/utility/KSPTest.cpp similarity index 100% rename from src/test/utility/KSPTest.cpp rename to src/test/storm/utility/KSPTest.cpp diff --git a/src/test/utility/VectorTest.cpp b/src/test/storm/utility/VectorTest.cpp similarity index 100% rename from src/test/utility/VectorTest.cpp rename to src/test/storm/utility/VectorTest.cpp