Matthias Volk 8 years ago
parent
commit
28fc5b7c29
  1. 5
      src/CMakeLists.txt
  2. 7
      src/storm-pars-cli/CMakeLists.txt
  3. 346
      src/storm-pars-cli/storm-pars.cpp
  4. 40
      src/storm-pars/CMakeLists.txt
  5. 183
      src/storm-pars/api/region.h
  6. 3
      src/storm-pars/api/storm-pars.h
  7. 147
      src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp
  8. 35
      src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.h
  9. 42
      src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp
  10. 42
      src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h
  11. 171
      src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp
  12. 34
      src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.h
  13. 25
      src/storm-pars/modelchecker/region/RegionCheckEngine.cpp
  14. 19
      src/storm-pars/modelchecker/region/RegionCheckEngine.h
  15. 130
      src/storm-pars/modelchecker/region/RegionModelChecker.cpp
  16. 50
      src/storm-pars/modelchecker/region/RegionModelChecker.h
  17. 40
      src/storm-pars/modelchecker/region/RegionResult.cpp
  18. 24
      src/storm-pars/modelchecker/region/RegionResult.h
  19. 328
      src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp
  20. 64
      src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h
  21. 408
      src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp
  22. 70
      src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.h
  23. 176
      src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.cpp
  24. 83
      src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h
  25. 67
      src/storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.cpp
  26. 31
      src/storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.h
  27. 71
      src/storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.cpp
  28. 31
      src/storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.h
  29. 73
      src/storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.cpp
  30. 44
      src/storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.h
  31. 117
      src/storm-pars/modelchecker/results/RegionCheckResult.cpp
  32. 40
      src/storm-pars/modelchecker/results/RegionCheckResult.h
  33. 100
      src/storm-pars/modelchecker/results/RegionRefinementCheckResult.cpp
  34. 30
      src/storm-pars/modelchecker/results/RegionRefinementCheckResult.h
  35. 97
      src/storm-pars/parser/ParameterRegionParser.cpp
  36. 47
      src/storm-pars/parser/ParameterRegionParser.h
  37. 53
      src/storm-pars/settings/ParsSettings.cpp
  38. 11
      src/storm-pars/settings/ParsSettings.h
  39. 47
      src/storm-pars/settings/modules/ParametricSettings.cpp
  40. 58
      src/storm-pars/settings/modules/ParametricSettings.h
  41. 83
      src/storm-pars/settings/modules/RegionSettings.cpp
  42. 72
      src/storm-pars/settings/modules/RegionSettings.h
  43. 72
      src/storm-pars/storage/ParameterRegion.cpp
  44. 29
      src/storm-pars/storage/ParameterRegion.h
  45. 2
      src/storm-pars/transformer/ParameterLifter.cpp
  46. 4
      src/storm-pars/transformer/ParameterLifter.h
  47. 2
      src/storm-pars/transformer/SparseParametricDtmcSimplifier.cpp
  48. 2
      src/storm-pars/transformer/SparseParametricDtmcSimplifier.h
  49. 2
      src/storm-pars/transformer/SparseParametricMdpSimplifier.cpp
  50. 2
      src/storm-pars/transformer/SparseParametricMdpSimplifier.h
  51. 2
      src/storm-pars/transformer/SparseParametricModelSimplifier.cpp
  52. 0
      src/storm-pars/transformer/SparseParametricModelSimplifier.h
  53. 2
      src/storm-pars/utility/ModelInstantiator.cpp
  54. 2
      src/storm-pars/utility/ModelInstantiator.h
  55. 35
      src/storm-pars/utility/parameterlifting.h
  56. 2
      src/storm-pars/utility/parametric.cpp
  57. 0
      src/storm-pars/utility/parametric.h
  58. 1
      src/storm/api/storm.h
  59. 80
      src/storm/api/transformation.h
  60. 126
      src/storm/api/verification.h
  61. 8
      src/storm/cli/cli.cpp
  62. 119
      src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp
  63. 16
      src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h
  64. 42
      src/storm/modelchecker/parametric/RegionCheckResult.cpp
  65. 26
      src/storm/modelchecker/parametric/RegionCheckResult.h
  66. 326
      src/storm/modelchecker/parametric/RegionChecker.cpp
  67. 85
      src/storm/modelchecker/parametric/RegionChecker.h
  68. 149
      src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.cpp
  69. 37
      src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.h
  70. 281
      src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.cpp
  71. 56
      src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.h
  72. 65
      src/storm/modelchecker/parametric/SparseDtmcRegionChecker.cpp
  73. 27
      src/storm/modelchecker/parametric/SparseDtmcRegionChecker.h
  74. 44
      src/storm/modelchecker/parametric/SparseInstantiationModelChecker.cpp
  75. 44
      src/storm/modelchecker/parametric/SparseInstantiationModelChecker.h
  76. 173
      src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.cpp
  77. 36
      src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.h
  78. 348
      src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.cpp
  79. 63
      src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.h
  80. 70
      src/storm/modelchecker/parametric/SparseMdpRegionChecker.cpp
  81. 28
      src/storm/modelchecker/parametric/SparseMdpRegionChecker.h
  82. 94
      src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.cpp
  83. 60
      src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h
  84. 2
      src/storm/settings/SettingsManager.cpp
  85. 7
      src/storm/settings/modules/CoreSettings.cpp
  86. 7
      src/storm/settings/modules/CoreSettings.h
  87. 89
      src/storm/settings/modules/ParametricSettings.cpp
  88. 104
      src/storm/settings/modules/ParametricSettings.h
  89. 119
      src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.cpp
  90. 36
      src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.h
  91. 21
      src/storm/transformer/SymbolicToSparseTransformer.cpp
  92. 3
      src/storm/transformer/SymbolicToSparseTransformer.h
  93. 25
      src/test/CMakeLists.txt
  94. 385
      src/test/modelchecker/SparseDtmcParameterLiftingTest.cpp
  95. 313
      src/test/modelchecker/SparseMdpParameterLiftingTest.cpp
  96. 23
      src/test/storm-pars/CMakeLists.txt
  97. 362
      src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp
  98. 301
      src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp
  99. 8
      src/test/storm-pars/storm-test.cpp
  100. 2
      src/test/storm-pars/utility/ModelInstantiatorTest.cpp

5
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)
set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE)

7
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)

346
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;
}
}

40
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)

183
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;
}
}
}
}

3
src/storm-pars/api/storm-pars.h

@ -0,0 +1,3 @@
#pragma once
#include "storm-pars/api/region.h"

147
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>;
}
}

35
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;
};
}
}

42
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>;
}
}

42
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;
};
}
}

171
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>;
}
}

34
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;
};
}
}

25
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;
}
}
}

19
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);
}
}

130
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

50
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

40
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;
}
}
}

24
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);
}
}

328
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, &parameterLifter->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>;
}
}

64
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;
};
}
}

408
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, &parameterLifter->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>;
}
}

70
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;
};
}
}

176
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>;
}
}

83
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;
};
}
}

67
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>;
}
}

31
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;
};
}
}

71
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>;
}
}

31
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;
};
}
}

73
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>;
}
}

44
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;
};
}
}

117
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
}
}

40
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;
};
}
}

100
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
}
}

30
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;
};
}
}

97
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
}
}

47
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);
};
}
}

53
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>();
}
}
}

11
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);
}
}

47
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

58
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_ */

83
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

72
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

72
src/storm/storage/ParameterRegion.cpp → 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
}
}

29
src/storm/storage/ParameterRegion.h → 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);
}
}

2
src/storm/transformer/ParameterLifter.cpp → 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"

4
src/storm/transformer/ParameterLifter.h → 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 {

2
src/storm/transformer/SparseParametricDtmcSimplifier.cpp → 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"

2
src/storm/transformer/SparseParametricDtmcSimplifier.h → 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 {

2
src/storm/transformer/SparseParametricMdpSimplifier.cpp → 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"

2
src/storm/transformer/SparseParametricMdpSimplifier.h → 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 {

2
src/storm/transformer/SparseParametricModelSimplifier.cpp → 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"

0
src/storm/transformer/SparseParametricModelSimplifier.h → src/storm-pars/transformer/SparseParametricModelSimplifier.h

2
src/storm/utility/ModelInstantiator.cpp → 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 {

2
src/storm/utility/ModelInstantiator.h → 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 {

35
src/storm/utility/parameterlifting.h → 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()) {

2
src/storm/utility/parametric.cpp → 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"

0
src/storm/utility/parametric.h → src/storm-pars/utility/parametric.h

1
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"

80
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;
}
}
}

126
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;
// }
// }
// }
// }
}
}
}

8
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());
}
});
}

119
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);
}
}
}

16
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);
};
}

42
src/storm/modelchecker/parametric/RegionCheckResult.cpp

@ -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;
}
}
}
}

26
src/storm/modelchecker/parametric/RegionCheckResult.h

@ -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);
}
}
}

326
src/storm/modelchecker/parametric/RegionChecker.cpp

@ -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

85
src/storm/modelchecker/parametric/RegionChecker.h

@ -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

149
src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.cpp

@ -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>;
}
}
}

37
src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.h

@ -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;
};
}
}
}

281
src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.cpp

@ -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, &parameterLifter->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>;
}
}
}

56
src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.h

@ -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;
};
}
}
}

65
src/storm/modelchecker/parametric/SparseDtmcRegionChecker.cpp

@ -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

27
src/storm/modelchecker/parametric/SparseDtmcRegionChecker.h

@ -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

44
src/storm/modelchecker/parametric/SparseInstantiationModelChecker.cpp

@ -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>;
}
}
}

44
src/storm/modelchecker/parametric/SparseInstantiationModelChecker.h

@ -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;
};
}
}
}

173
src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.cpp

@ -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>;
}
}
}

36
src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.h

@ -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;
};
}
}
}

348
src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.cpp

@ -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, &parameterLifter->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>;
}
}
}

63
src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.h

@ -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;
};
}
}
}

70
src/storm/modelchecker/parametric/SparseMdpRegionChecker.cpp

@ -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

28
src/storm/modelchecker/parametric/SparseMdpRegionChecker.h

@ -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

94
src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.cpp

@ -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>;
}
}
}

60
src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h

@ -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;
};
}
}
}

2
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>();

7
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") {

7
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;

89
src/storm/settings/modules/ParametricSettings.cpp

@ -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

104
src/storm/settings/modules/ParametricSettings.h

@ -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_ */

119
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>;
}
}

36
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);
};
}
}

21
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>;

3
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:

25
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)

385
src/test/modelchecker/SparseDtmcParameterLiftingTest.cpp

@ -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

313
src/test/modelchecker/SparseMdpParameterLiftingTest.cpp

@ -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

23
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 ()

362
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

301
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

8
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();
}

2
src/test/utility/ModelInstantiatorTest.cpp → 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"

Some files were not shown because too many files changed in this diff

|||||||
100:0
Loading…
Cancel
Save