Browse Source

started on partial bisimulation model checker

main
dehnert 8 years ago
parent
commit
9c685f3bdb
  1. 222
      src/storm-cli-utilities/model-handling.h
  2. 56
      src/storm/api/verification.h
  3. 19
      src/storm/modelchecker/abstraction/PartialBisimulationMdpModelChecker.cpp
  4. 29
      src/storm/modelchecker/abstraction/PartialBisimulationMdpModelChecker.h
  5. 1
      src/storm/models/symbolic/StochasticTwoPlayerGame.cpp
  6. 17
      src/storm/settings/modules/AbstractionSettings.cpp
  7. 10
      src/storm/settings/modules/AbstractionSettings.h
  8. 2
      src/storm/storage/dd/BisimulationDecomposition.cpp
  9. 25
      src/storm/storage/dd/bisimulation/PartialQuotientExtractor.cpp
  10. 8
      src/storm/storage/dd/bisimulation/PartialQuotientExtractor.h

222
src/storm-cli-utilities/model-handling.h

@ -37,16 +37,16 @@
namespace storm { namespace storm {
namespace cli { namespace cli {
struct SymbolicInput { struct SymbolicInput {
// The symbolic model description. // The symbolic model description.
boost::optional<storm::storage::SymbolicModelDescription> model; boost::optional<storm::storage::SymbolicModelDescription> model;
// The properties to check. // The properties to check.
std::vector<storm::jani::Property> properties; std::vector<storm::jani::Property> properties;
}; };
void parseSymbolicModelDescription(storm::settings::modules::IOSettings const& ioSettings, SymbolicInput& input) { void parseSymbolicModelDescription(storm::settings::modules::IOSettings const& ioSettings, SymbolicInput& input) {
if (ioSettings.isPrismOrJaniInputSet()) { if (ioSettings.isPrismOrJaniInputSet()) {
if (ioSettings.isPrismInputSet()) { if (ioSettings.isPrismInputSet()) {
@ -55,7 +55,7 @@ namespace storm {
auto janiInput = storm::api::parseJaniModel(ioSettings.getJaniInputFilename()); auto janiInput = storm::api::parseJaniModel(ioSettings.getJaniInputFilename());
input.model = janiInput.first; input.model = janiInput.first;
auto const& janiPropertyInput = janiInput.second; auto const& janiPropertyInput = janiInput.second;
if (ioSettings.isJaniPropertiesSet()) { if (ioSettings.isJaniPropertiesSet()) {
for (auto const& propName : ioSettings.getJaniProperties()) { for (auto const& propName : ioSettings.getJaniProperties()) {
auto propertyIt = janiPropertyInput.find(propName); auto propertyIt = janiPropertyInput.find(propName);
@ -66,7 +66,7 @@ namespace storm {
} }
} }
} }
void parseProperties(storm::settings::modules::IOSettings const& ioSettings, SymbolicInput& input, boost::optional<std::set<std::string>> const& propertyFilter) { void parseProperties(storm::settings::modules::IOSettings const& ioSettings, SymbolicInput& input, boost::optional<std::set<std::string>> const& propertyFilter) {
if (ioSettings.isPropertySet()) { if (ioSettings.isPropertySet()) {
std::vector<storm::jani::Property> newProperties; std::vector<storm::jani::Property> newProperties;
@ -75,30 +75,30 @@ namespace storm {
} else { } else {
newProperties = storm::api::parseProperties(ioSettings.getProperty(), propertyFilter); newProperties = storm::api::parseProperties(ioSettings.getProperty(), propertyFilter);
} }
input.properties.insert(input.properties.end(), newProperties.begin(), newProperties.end()); input.properties.insert(input.properties.end(), newProperties.begin(), newProperties.end());
} }
} }
SymbolicInput parseSymbolicInput() { SymbolicInput parseSymbolicInput() {
auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
// Parse the property filter, if any is given. // Parse the property filter, if any is given.
boost::optional<std::set<std::string>> propertyFilter = storm::api::parsePropertyFilter(ioSettings.getPropertyFilter()); boost::optional<std::set<std::string>> propertyFilter = storm::api::parsePropertyFilter(ioSettings.getPropertyFilter());
SymbolicInput input; SymbolicInput input;
parseSymbolicModelDescription(ioSettings, input); parseSymbolicModelDescription(ioSettings, input);
parseProperties(ioSettings, input, propertyFilter); parseProperties(ioSettings, input, propertyFilter);
return input; return input;
} }
SymbolicInput preprocessSymbolicInput(SymbolicInput const& input) { SymbolicInput preprocessSymbolicInput(SymbolicInput const& input) {
auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>(); auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>();
SymbolicInput output = input; SymbolicInput output = input;
// Substitute constant definitions in symbolic input. // Substitute constant definitions in symbolic input.
std::string constantDefinitionString = ioSettings.getConstantDefinitionString(); std::string constantDefinitionString = ioSettings.getConstantDefinitionString();
std::map<storm::expressions::Variable, storm::expressions::Expression> constantDefinitions; std::map<storm::expressions::Variable, storm::expressions::Expression> constantDefinitions;
@ -109,19 +109,19 @@ namespace storm {
if (!output.properties.empty()) { if (!output.properties.empty()) {
output.properties = storm::api::substituteConstantsInProperties(output.properties, constantDefinitions); output.properties = storm::api::substituteConstantsInProperties(output.properties, constantDefinitions);
} }
// Check whether conversion for PRISM to JANI is requested or necessary. // Check whether conversion for PRISM to JANI is requested or necessary.
if (input.model && input.model.get().isPrismProgram()) { if (input.model && input.model.get().isPrismProgram()) {
bool transformToJani = ioSettings.isPrismToJaniSet(); bool transformToJani = ioSettings.isPrismToJaniSet();
bool transformToJaniForJit = coreSettings.getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse && ioSettings.isJitSet(); bool transformToJaniForJit = coreSettings.getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse && ioSettings.isJitSet();
STORM_LOG_WARN_COND(transformToJani || !transformToJaniForJit, "The JIT-based model builder is only available for JANI models, automatically converting the PRISM input model."); STORM_LOG_WARN_COND(transformToJani || !transformToJaniForJit, "The JIT-based model builder is only available for JANI models, automatically converting the PRISM input model.");
transformToJani |= transformToJaniForJit; transformToJani |= transformToJaniForJit;
if (transformToJani) { if (transformToJani) {
storm::prism::Program const& model = output.model.get().asPrismProgram(); storm::prism::Program const& model = output.model.get().asPrismProgram();
auto modelAndRenaming = model.toJaniWithLabelRenaming(true); auto modelAndRenaming = model.toJaniWithLabelRenaming(true);
output.model = modelAndRenaming.first; output.model = modelAndRenaming.first;
if (!modelAndRenaming.second.empty()) { if (!modelAndRenaming.second.empty()) {
std::map<std::string, std::string> const& labelRenaming = modelAndRenaming.second; std::map<std::string, std::string> const& labelRenaming = modelAndRenaming.second;
std::vector<storm::jani::Property> amendedProperties; std::vector<storm::jani::Property> amendedProperties;
@ -132,10 +132,10 @@ namespace storm {
} }
} }
} }
return output; return output;
} }
void exportSymbolicInput(SymbolicInput const& input) { void exportSymbolicInput(SymbolicInput const& input) {
auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
if (input.model && input.model.get().isJaniModel()) { if (input.model && input.model.get().isJaniModel()) {
@ -143,37 +143,37 @@ namespace storm {
if (ioSettings.isExportJaniDotSet()) { if (ioSettings.isExportJaniDotSet()) {
storm::api::exportJaniModelAsDot(model.asJaniModel(), ioSettings.getExportJaniDotFilename()); storm::api::exportJaniModelAsDot(model.asJaniModel(), ioSettings.getExportJaniDotFilename());
} }
if (model.isJaniModel() && storm::settings::getModule<storm::settings::modules::JaniExportSettings>().isJaniFileSet()) { if (model.isJaniModel() && storm::settings::getModule<storm::settings::modules::JaniExportSettings>().isJaniFileSet()) {
storm::api::exportJaniModel(model.asJaniModel(), input.properties, storm::settings::getModule<storm::settings::modules::JaniExportSettings>().getJaniFilename()); storm::api::exportJaniModel(model.asJaniModel(), input.properties, storm::settings::getModule<storm::settings::modules::JaniExportSettings>().getJaniFilename());
} }
} }
} }
SymbolicInput parseAndPreprocessSymbolicInput() { SymbolicInput parseAndPreprocessSymbolicInput() {
SymbolicInput input = parseSymbolicInput(); SymbolicInput input = parseSymbolicInput();
input = preprocessSymbolicInput(input); input = preprocessSymbolicInput(input);
exportSymbolicInput(input); exportSymbolicInput(input);
return input; return input;
} }
std::vector<std::shared_ptr<storm::logic::Formula const>> createFormulasToRespect(std::vector<storm::jani::Property> const& properties) { std::vector<std::shared_ptr<storm::logic::Formula const>> createFormulasToRespect(std::vector<storm::jani::Property> const& properties) {
std::vector<std::shared_ptr<storm::logic::Formula const>> result = storm::api::extractFormulasFromProperties(properties); std::vector<std::shared_ptr<storm::logic::Formula const>> result = storm::api::extractFormulasFromProperties(properties);
for (auto const& property : properties) { for (auto const& property : properties) {
if (!property.getFilter().getStatesFormula()->isInitialFormula()) { if (!property.getFilter().getStatesFormula()->isInitialFormula()) {
result.push_back(property.getFilter().getStatesFormula()); result.push_back(property.getFilter().getStatesFormula());
} }
} }
return result; return result;
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
std::shared_ptr<storm::models::ModelBase> buildModelDd(SymbolicInput const& input) { std::shared_ptr<storm::models::ModelBase> buildModelDd(SymbolicInput const& input) {
return storm::api::buildSymbolicModel<DdType, ValueType>(input.model.get(), createFormulasToRespect(input.properties), storm::settings::getModule<storm::settings::modules::IOSettings>().isBuildFullModelSet()); return storm::api::buildSymbolicModel<DdType, ValueType>(input.model.get(), createFormulasToRespect(input.properties), storm::settings::getModule<storm::settings::modules::IOSettings>().isBuildFullModelSet());
} }
template <typename ValueType> template <typename ValueType>
std::shared_ptr<storm::models::ModelBase> buildModelSparse(SymbolicInput const& input, storm::settings::modules::IOSettings const& ioSettings) { std::shared_ptr<storm::models::ModelBase> buildModelSparse(SymbolicInput const& input, storm::settings::modules::IOSettings const& ioSettings) {
auto counterexampleGeneratorSettings = storm::settings::getModule<storm::settings::modules::CounterexampleGeneratorSettings>(); auto counterexampleGeneratorSettings = storm::settings::getModule<storm::settings::modules::CounterexampleGeneratorSettings>();
@ -188,7 +188,7 @@ namespace storm {
} }
return storm::api::buildSparseModel<ValueType>(input.model.get(), options, ioSettings.isJitSet(), storm::settings::getModule<storm::settings::modules::JitBuilderSettings>().isDoctorSet()); return storm::api::buildSparseModel<ValueType>(input.model.get(), options, ioSettings.isJitSet(), storm::settings::getModule<storm::settings::modules::JitBuilderSettings>().isDoctorSet());
} }
template <typename ValueType> template <typename ValueType>
std::shared_ptr<storm::models::ModelBase> buildModelExplicit(storm::settings::modules::IOSettings const& ioSettings) { std::shared_ptr<storm::models::ModelBase> buildModelExplicit(storm::settings::modules::IOSettings const& ioSettings) {
std::shared_ptr<storm::models::ModelBase> result; std::shared_ptr<storm::models::ModelBase> result;
@ -202,11 +202,11 @@ namespace storm {
} }
return result; return result;
} }
template <storm::dd::DdType DdType, typename ValueType> 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) { 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); storm::utility::Stopwatch modelBuildingWatch(true);
std::shared_ptr<storm::models::ModelBase> result; std::shared_ptr<storm::models::ModelBase> result;
if (input.model) { if (input.model) {
if (engine == storm::settings::modules::CoreSettings::Engine::Dd || engine == storm::settings::modules::CoreSettings::Engine::Hybrid) { if (engine == storm::settings::modules::CoreSettings::Engine::Dd || engine == storm::settings::modules::CoreSettings::Engine::Hybrid) {
@ -218,15 +218,15 @@ namespace storm {
STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Can only use sparse engine with explicit input."); STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Can only use sparse engine with explicit input.");
result = buildModelExplicit<ValueType>(ioSettings); result = buildModelExplicit<ValueType>(ioSettings);
} }
modelBuildingWatch.stop(); modelBuildingWatch.stop();
if (result) { if (result) {
STORM_PRINT("Time for model construction: " << modelBuildingWatch << "." << std::endl << std::endl); STORM_PRINT("Time for model construction: " << modelBuildingWatch << "." << std::endl << std::endl);
} }
return result; return result;
} }
template <typename ValueType> template <typename ValueType>
std::shared_ptr<storm::models::sparse::Model<ValueType>> preprocessSparseMarkovAutomaton(std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> const& model) { std::shared_ptr<storm::models::sparse::Model<ValueType>> preprocessSparseMarkovAutomaton(std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> const& model) {
std::shared_ptr<storm::models::sparse::Model<ValueType>> result = model; std::shared_ptr<storm::models::sparse::Model<ValueType>> result = model;
@ -238,57 +238,57 @@ namespace storm {
} }
return result; return result;
} }
template <typename ValueType> template <typename ValueType>
std::shared_ptr<storm::models::sparse::Model<ValueType>> preprocessSparseModelBisimulation(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, storm::settings::modules::BisimulationSettings const& bisimulationSettings) { std::shared_ptr<storm::models::sparse::Model<ValueType>> preprocessSparseModelBisimulation(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, storm::settings::modules::BisimulationSettings const& bisimulationSettings) {
storm::storage::BisimulationType bisimType = storm::storage::BisimulationType::Strong; storm::storage::BisimulationType bisimType = storm::storage::BisimulationType::Strong;
if (bisimulationSettings.isWeakBisimulationSet()) { if (bisimulationSettings.isWeakBisimulationSet()) {
bisimType = storm::storage::BisimulationType::Weak; bisimType = storm::storage::BisimulationType::Weak;
} }
STORM_LOG_INFO("Performing bisimulation minimization..."); STORM_LOG_INFO("Performing bisimulation minimization...");
return storm::api::performBisimulationMinimization<ValueType>(model, createFormulasToRespect(input.properties), bisimType); return storm::api::performBisimulationMinimization<ValueType>(model, createFormulasToRespect(input.properties), bisimType);
} }
template <typename ValueType> template <typename ValueType>
std::pair<std::shared_ptr<storm::models::sparse::Model<ValueType>>, bool> preprocessSparseModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input) { std::pair<std::shared_ptr<storm::models::sparse::Model<ValueType>>, 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 ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
std::pair<std::shared_ptr<storm::models::sparse::Model<ValueType>>, bool> result = std::make_pair(model, false);
if (result.first->isOfType(storm::models::ModelType::MarkovAutomaton)) {
result.first = preprocessSparseMarkovAutomaton(result.first->template as<storm::models::sparse::MarkovAutomaton<ValueType>>());
result.second = true;
}
if (generalSettings.isBisimulationSet()) {
result.first = preprocessSparseModelBisimulation(result.first, input, bisimulationSettings);
result.second = true;
}
return result;
auto generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>();
auto bisimulationSettings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>();
auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
std::pair<std::shared_ptr<storm::models::sparse::Model<ValueType>>, bool> result = std::make_pair(model, false);
if (result.first->isOfType(storm::models::ModelType::MarkovAutomaton)) {
result.first = preprocessSparseMarkovAutomaton(result.first->template as<storm::models::sparse::MarkovAutomaton<ValueType>>());
result.second = true;
}
if (generalSettings.isBisimulationSet()) {
result.first = preprocessSparseModelBisimulation(result.first, input, bisimulationSettings);
result.second = true;
}
return result;
} }
template <typename ValueType> template <typename ValueType>
void exportSparseModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input) { void exportSparseModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input) {
auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
if (ioSettings.isExportExplicitSet()) { if (ioSettings.isExportExplicitSet()) {
storm::api::exportSparseModelAsDrn(model, ioSettings.getExportExplicitFilename(), input.model ? input.model.get().getParameterNames() : std::vector<std::string>()); storm::api::exportSparseModelAsDrn(model, ioSettings.getExportExplicitFilename(), input.model ? input.model.get().getParameterNames() : std::vector<std::string>());
} }
if (ioSettings.isExportDotSet()) { if (ioSettings.isExportDotSet()) {
storm::api::exportSparseModelAsDot(model, ioSettings.getExportDotFilename()); storm::api::exportSparseModelAsDot(model, ioSettings.getExportDotFilename());
} }
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
void exportDdModel(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input) { void exportDdModel(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input) {
// Intentionally left empty. // Intentionally left empty.
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
void exportModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) { void exportModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) {
if (model->isSparseModel()) { if (model->isSparseModel()) {
@ -297,7 +297,7 @@ namespace storm {
exportDdModel<DdType, ValueType>(model->as<storm::models::symbolic::Model<DdType, ValueType>>(), input); exportDdModel<DdType, ValueType>(model->as<storm::models::symbolic::Model<DdType, ValueType>>(), input);
} }
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
std::shared_ptr<storm::models::Model<ValueType>> preprocessDdModelBisimulation(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input, storm::settings::modules::BisimulationSettings const& bisimulationSettings) { std::shared_ptr<storm::models::Model<ValueType>> preprocessDdModelBisimulation(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input, storm::settings::modules::BisimulationSettings const& bisimulationSettings) {
STORM_LOG_WARN_COND(!bisimulationSettings.isWeakBisimulationSet(), "Weak bisimulation is currently not supported on DDs. Falling back to strong bisimulation."); STORM_LOG_WARN_COND(!bisimulationSettings.isWeakBisimulationSet(), "Weak bisimulation is currently not supported on DDs. Falling back to strong bisimulation.");
@ -319,11 +319,11 @@ namespace storm {
return result; return result;
} }
template <storm::dd::DdType DdType, typename ValueType> 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) { 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); storm::utility::Stopwatch preprocessingWatch(true);
std::pair<std::shared_ptr<storm::models::ModelBase>, bool> result = std::make_pair(model, false); std::pair<std::shared_ptr<storm::models::ModelBase>, bool> result = std::make_pair(model, false);
if (model->isSparseModel()) { if (model->isSparseModel()) {
result = preprocessSparseModel<ValueType>(result.first->as<storm::models::sparse::Model<ValueType>>(), input); result = preprocessSparseModel<ValueType>(result.first->as<storm::models::sparse::Model<ValueType>>(), input);
@ -333,17 +333,17 @@ namespace storm {
} }
preprocessingWatch.stop(); preprocessingWatch.stop();
if (result.second) { if (result.second) {
STORM_PRINT(std::endl << "Time for model preprocessing: " << preprocessingWatch << "." << std::endl << std::endl); STORM_PRINT(std::endl << "Time for model preprocessing: " << preprocessingWatch << "." << std::endl << std::endl);
} }
return result; return result;
} }
void printComputingCounterexample(storm::jani::Property const& property) { void printComputingCounterexample(storm::jani::Property const& property) {
STORM_PRINT("Computing counterexample for property " << *property.getRawFormula() << " ..." << std::endl); STORM_PRINT("Computing counterexample for property " << *property.getRawFormula() << " ..." << std::endl);
} }
void printCounterexample(std::shared_ptr<storm::counterexamples::Counterexample> const& counterexample, storm::utility::Stopwatch* watch = nullptr) { void printCounterexample(std::shared_ptr<storm::counterexamples::Counterexample> const& counterexample, storm::utility::Stopwatch* watch = nullptr) {
if (counterexample) { if (counterexample) {
STORM_PRINT(*counterexample << std::endl); STORM_PRINT(*counterexample << std::endl);
@ -354,27 +354,27 @@ namespace storm {
STORM_PRINT(" failed." << std::endl); STORM_PRINT(" failed." << std::endl);
} }
} }
template <typename ValueType> template <typename ValueType>
void generateCounterexamples(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) { void generateCounterexamples(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Counterexample generation is not supported for this data-type."); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Counterexample generation is not supported for this data-type.");
} }
template <> template <>
void generateCounterexamples<double>(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) { void generateCounterexamples<double>(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) {
typedef double ValueType; typedef double ValueType;
STORM_LOG_THROW(model->isSparseModel(), storm::exceptions::NotSupportedException, "Counterexample generation is currently only supported for sparse models."); STORM_LOG_THROW(model->isSparseModel(), storm::exceptions::NotSupportedException, "Counterexample generation is currently only supported for sparse models.");
auto sparseModel = model->as<storm::models::sparse::Model<ValueType>>(); auto sparseModel = model->as<storm::models::sparse::Model<ValueType>>();
STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException, "Counterexample is currently only supported for MDPs."); STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException, "Counterexample is currently only supported for MDPs.");
auto mdp = sparseModel->template as<storm::models::sparse::Mdp<ValueType>>(); auto mdp = sparseModel->template as<storm::models::sparse::Mdp<ValueType>>();
auto counterexampleSettings = storm::settings::getModule<storm::settings::modules::CounterexampleGeneratorSettings>(); auto counterexampleSettings = storm::settings::getModule<storm::settings::modules::CounterexampleGeneratorSettings>();
if (counterexampleSettings.isMinimalCommandSetGenerationSet()) { if (counterexampleSettings.isMinimalCommandSetGenerationSet()) {
STORM_LOG_THROW(input.model && input.model.get().isPrismProgram(), storm::exceptions::NotSupportedException, "Minimal command set counterexamples are only supported for PRISM model input."); STORM_LOG_THROW(input.model && input.model.get().isPrismProgram(), storm::exceptions::NotSupportedException, "Minimal command set counterexamples are only supported for PRISM model input.");
storm::prism::Program const& program = input.model.get().asPrismProgram(); storm::prism::Program const& program = input.model.get().asPrismProgram();
bool useMilp = counterexampleSettings.isUseMilpBasedMinimalCommandSetGenerationSet(); bool useMilp = counterexampleSettings.isUseMilpBasedMinimalCommandSetGenerationSet();
for (auto const& property : input.properties) { for (auto const& property : input.properties) {
std::shared_ptr<storm::counterexamples::Counterexample> counterexample; std::shared_ptr<storm::counterexamples::Counterexample> counterexample;
@ -392,7 +392,7 @@ namespace storm {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The selected counterexample formalism is unsupported."); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The selected counterexample formalism is unsupported.");
} }
} }
template<typename ValueType> template<typename ValueType>
void printFilteredResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::modelchecker::FilterType ft) { void printFilteredResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::modelchecker::FilterType ft) {
if (result->isQuantitative()) { if (result->isQuantitative()) {
@ -446,11 +446,11 @@ namespace storm {
} }
STORM_PRINT(std::endl); STORM_PRINT(std::endl);
} }
void printModelCheckingProperty(storm::jani::Property const& property) { void printModelCheckingProperty(storm::jani::Property const& property) {
STORM_PRINT(std::endl << "Model checking property " << *property.getRawFormula() << " ..." << std::endl); STORM_PRINT(std::endl << "Model checking property " << *property.getRawFormula() << " ..." << std::endl);
} }
template<typename ValueType> template<typename ValueType>
void printResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::jani::Property const& property, storm::utility::Stopwatch* watch = nullptr) { void printResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::jani::Property const& property, storm::utility::Stopwatch* watch = nullptr) {
if (result) { if (result) {
@ -465,25 +465,25 @@ namespace storm {
STORM_PRINT(" failed, property is unsupported by selected engine/settings." << std::endl); STORM_PRINT(" failed, property is unsupported by selected engine/settings." << std::endl);
} }
} }
struct PostprocessingIdentity { struct PostprocessingIdentity {
void operator()(std::unique_ptr<storm::modelchecker::CheckResult> const&) { void operator()(std::unique_ptr<storm::modelchecker::CheckResult> const&) {
// Intentionally left empty. // Intentionally left empty.
} }
}; };
template<typename ValueType> 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, std::shared_ptr<storm::logic::Formula const> const& states)> const& verificationCallback, std::function<void(std::unique_ptr<storm::modelchecker::CheckResult> const&)> const& postprocessingCallback = PostprocessingIdentity()) { 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, std::shared_ptr<storm::logic::Formula const> const& states)> const& verificationCallback, std::function<void(std::unique_ptr<storm::modelchecker::CheckResult> const&)> const& postprocessingCallback = PostprocessingIdentity()) {
for (auto const& property : properties) {
printModelCheckingProperty(property);
storm::utility::Stopwatch watch(true);
std::unique_ptr<storm::modelchecker::CheckResult> result = verificationCallback(property.getRawFormula(), property.getFilter().getStatesFormula());
watch.stop();
postprocessingCallback(result);
printResult<ValueType>(result, property, &watch);
}
for (auto const& property : properties) {
printModelCheckingProperty(property);
storm::utility::Stopwatch watch(true);
std::unique_ptr<storm::modelchecker::CheckResult> result = verificationCallback(property.getRawFormula(), property.getFilter().getStatesFormula());
watch.stop();
postprocessingCallback(result);
printResult<ValueType>(result, property, &watch);
}
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
void verifyWithAbstractionRefinementEngine(SymbolicInput const& input) { void verifyWithAbstractionRefinementEngine(SymbolicInput const& input) {
STORM_LOG_ASSERT(input.model, "Expected symbolic model description."); STORM_LOG_ASSERT(input.model, "Expected symbolic model description.");
@ -492,7 +492,7 @@ namespace storm {
return storm::api::verifyWithAbstractionRefinementEngine<DdType, ValueType>(input.model.get(), storm::api::createTask<ValueType>(formula, true)); return storm::api::verifyWithAbstractionRefinementEngine<DdType, ValueType>(input.model.get(), storm::api::createTask<ValueType>(formula, true));
}); });
} }
template <typename ValueType> template <typename ValueType>
void verifyWithExplorationEngine(SymbolicInput const& input) { void verifyWithExplorationEngine(SymbolicInput const& input) {
STORM_LOG_ASSERT(input.model, "Expected symbolic model description."); STORM_LOG_ASSERT(input.model, "Expected symbolic model description.");
@ -502,7 +502,7 @@ namespace storm {
return storm::api::verifyWithExplorationEngine<ValueType>(input.model.get(), storm::api::createTask<ValueType>(formula, true)); return storm::api::verifyWithExplorationEngine<ValueType>(input.model.get(), storm::api::createTask<ValueType>(formula, true));
}); });
} }
template <typename ValueType> template <typename ValueType>
void verifyWithSparseEngine(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) { void verifyWithSparseEngine(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) {
auto sparseModel = model->as<storm::models::sparse::Model<ValueType>>(); auto sparseModel = model->as<storm::models::sparse::Model<ValueType>>();
@ -511,7 +511,7 @@ namespace storm {
bool filterForInitialStates = states->isInitialFormula(); bool filterForInitialStates = states->isInitialFormula();
auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates); auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates);
std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithSparseEngine<ValueType>(sparseModel, task); std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithSparseEngine<ValueType>(sparseModel, task);
std::unique_ptr<storm::modelchecker::CheckResult> filter; std::unique_ptr<storm::modelchecker::CheckResult> filter;
if (filterForInitialStates) { if (filterForInitialStates) {
filter = std::make_unique<storm::modelchecker::ExplicitQualitativeCheckResult>(sparseModel->getInitialStates()); filter = std::make_unique<storm::modelchecker::ExplicitQualitativeCheckResult>(sparseModel->getInitialStates());
@ -524,16 +524,16 @@ namespace storm {
return result; return result;
}); });
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
void verifyWithHybridEngine(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) { void verifyWithHybridEngine(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) {
verifyProperties<ValueType>(input.properties, [&model] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) { verifyProperties<ValueType>(input.properties, [&model] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) {
bool filterForInitialStates = states->isInitialFormula(); bool filterForInitialStates = states->isInitialFormula();
auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates); auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates);
auto symbolicModel = model->as<storm::models::symbolic::Model<DdType, ValueType>>(); auto symbolicModel = model->as<storm::models::symbolic::Model<DdType, ValueType>>();
std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithHybridEngine<DdType, ValueType>(symbolicModel, task); std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithHybridEngine<DdType, ValueType>(symbolicModel, task);
std::unique_ptr<storm::modelchecker::CheckResult> filter; std::unique_ptr<storm::modelchecker::CheckResult> filter;
if (filterForInitialStates) { if (filterForInitialStates) {
filter = std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<DdType>>(symbolicModel->getReachableStates(), symbolicModel->getInitialStates()); filter = std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<DdType>>(symbolicModel->getReachableStates(), symbolicModel->getInitialStates());
@ -546,16 +546,16 @@ namespace storm {
return result; return result;
}); });
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
void verifyWithDdEngine(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) { void verifyWithDdEngine(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) {
verifyProperties<ValueType>(input.properties, [&model] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) { verifyProperties<ValueType>(input.properties, [&model] (std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) {
bool filterForInitialStates = states->isInitialFormula(); bool filterForInitialStates = states->isInitialFormula();
auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates); auto task = storm::api::createTask<ValueType>(formula, filterForInitialStates);
auto symbolicModel = model->as<storm::models::symbolic::Model<DdType, ValueType>>(); auto symbolicModel = model->as<storm::models::symbolic::Model<DdType, ValueType>>();
std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithDdEngine<DdType, ValueType>(model->as<storm::models::symbolic::Model<DdType, ValueType>>(), storm::api::createTask<ValueType>(formula, true)); std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithDdEngine<DdType, ValueType>(model->as<storm::models::symbolic::Model<DdType, ValueType>>(), storm::api::createTask<ValueType>(formula, true));
std::unique_ptr<storm::modelchecker::CheckResult> filter; std::unique_ptr<storm::modelchecker::CheckResult> filter;
if (filterForInitialStates) { if (filterForInitialStates) {
filter = std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<DdType>>(symbolicModel->getReachableStates(), symbolicModel->getInitialStates()); filter = std::make_unique<storm::modelchecker::SymbolicQualitativeCheckResult<DdType>>(symbolicModel->getReachableStates(), symbolicModel->getInitialStates());
@ -568,22 +568,24 @@ namespace storm {
return result; return result;
}); });
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
typename std::enable_if<DdType != storm::dd::DdType::CUDD || std::is_same<ValueType, double>::value, void>::type verifySymbolicModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, storm::settings::modules::CoreSettings const& coreSettings) { typename std::enable_if<DdType != storm::dd::DdType::CUDD || std::is_same<ValueType, double>::value, void>::type verifySymbolicModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, storm::settings::modules::CoreSettings const& coreSettings) {
bool hybrid = coreSettings.getEngine() == storm::settings::modules::CoreSettings::Engine::Hybrid;
if (hybrid) {
storm::settings::modules::CoreSettings::Engine engine = coreSettings.getEngine();;
if (engine == storm::settings::modules::CoreSettings::Engine::Hybrid) {
verifyWithHybridEngine<DdType, ValueType>(model, input); verifyWithHybridEngine<DdType, ValueType>(model, input);
} else {
} else if (engine == storm::settings::modules::CoreSettings::Engine::Dd) {
verifyWithDdEngine<DdType, ValueType>(model, input); verifyWithDdEngine<DdType, ValueType>(model, input);
} else {
verifyWithAbstractionRefinementEngine<DdType, ValueType>(model, input);
} }
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
typename std::enable_if<DdType == storm::dd::DdType::CUDD && !std::is_same<ValueType, double>::value, void>::type verifySymbolicModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, storm::settings::modules::CoreSettings const& coreSettings) { typename std::enable_if<DdType == storm::dd::DdType::CUDD && !std::is_same<ValueType, double>::value, void>::type verifySymbolicModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, storm::settings::modules::CoreSettings const& coreSettings) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "CUDD does not support the selected data-type."); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "CUDD does not support the selected data-type.");
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
void verifyModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, storm::settings::modules::CoreSettings const& coreSettings) { void verifyModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, storm::settings::modules::CoreSettings const& coreSettings) {
if (model->isSparseModel()) { if (model->isSparseModel()) {
@ -593,7 +595,7 @@ namespace storm {
verifySymbolicModel<DdType, ValueType>(model, input, coreSettings); verifySymbolicModel<DdType, ValueType>(model, input, coreSettings);
} }
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
std::shared_ptr<storm::models::ModelBase> buildPreprocessExportModelWithValueTypeAndDdlib(SymbolicInput const& input, storm::settings::modules::CoreSettings::Engine engine) { std::shared_ptr<storm::models::ModelBase> buildPreprocessExportModelWithValueTypeAndDdlib(SymbolicInput const& input, storm::settings::modules::CoreSettings::Engine engine) {
auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
@ -601,13 +603,13 @@ namespace storm {
if (!ioSettings.isNoBuildModelSet()) { if (!ioSettings.isNoBuildModelSet()) {
model = buildModel<DdType, ValueType>(engine, input, ioSettings); model = buildModel<DdType, ValueType>(engine, input, ioSettings);
} }
if (model) { if (model) {
model->printModelInformationToStream(std::cout); model->printModelInformationToStream(std::cout);
} }
STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model."); STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model.");
if (model) { if (model) {
auto preprocessingResult = preprocessModel<DdType, ValueType>(model, input); auto preprocessingResult = preprocessModel<DdType, ValueType>(model, input);
if (preprocessingResult.second) { if (preprocessingResult.second) {
@ -618,20 +620,22 @@ namespace storm {
} }
return model; return model;
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
void processInputWithValueTypeAndDdlib(SymbolicInput const& input) { void processInputWithValueTypeAndDdlib(SymbolicInput const& input) {
auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>(); auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>();
auto abstractionSettings = storm::settings::getModule<storm::settings::modules::AbstractionSettings>();
// For several engines, no model building step is performed, but the verification is started right away. // For several engines, no model building step is performed, but the verification is started right away.
storm::settings::modules::CoreSettings::Engine engine = coreSettings.getEngine(); storm::settings::modules::CoreSettings::Engine engine = coreSettings.getEngine();
if (engine == storm::settings::modules::CoreSettings::Engine::AbstractionRefinement) {
if (engine == storm::settings::modules::CoreSettings::Engine::AbstractionRefinement && abstractionSettings.getMethod() == storm::settings::modules::AbstractionSettings::Method::Games) {
verifyWithAbstractionRefinementEngine<DdType, ValueType>(input); verifyWithAbstractionRefinementEngine<DdType, ValueType>(input);
} else if (engine == storm::settings::modules::CoreSettings::Engine::Exploration) { } else if (engine == storm::settings::modules::CoreSettings::Engine::Exploration) {
verifyWithExplorationEngine<ValueType>(input); verifyWithExplorationEngine<ValueType>(input);
} else { } else {
std::shared_ptr<storm::models::ModelBase> model = buildPreprocessExportModelWithValueTypeAndDdlib<DdType, ValueType>(input, engine); std::shared_ptr<storm::models::ModelBase> model = buildPreprocessExportModelWithValueTypeAndDdlib<DdType, ValueType>(input, engine);
if (model) { if (model) {
if (coreSettings.isCounterexampleSet()) { if (coreSettings.isCounterexampleSet()) {
auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
@ -643,12 +647,12 @@ namespace storm {
} }
} }
} }
template <typename ValueType> template <typename ValueType>
void processInputWithValueType(SymbolicInput const& input) { void processInputWithValueType(SymbolicInput const& input) {
auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>(); auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>();
auto generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>(); auto generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>();
if (coreSettings.getDdLibraryType() == storm::dd::DdType::CUDD && coreSettings.isDdLibraryTypeSetFromDefaultValue() && generalSettings.isExactSet()) { if (coreSettings.getDdLibraryType() == storm::dd::DdType::CUDD && coreSettings.isDdLibraryTypeSetFromDefaultValue() && generalSettings.isExactSet()) {
STORM_LOG_INFO("Switching to DD library sylvan to allow for rational arithmetic."); STORM_LOG_INFO("Switching to DD library sylvan to allow for rational arithmetic.");
processInputWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, ValueType>(input); processInputWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, ValueType>(input);
@ -659,6 +663,6 @@ namespace storm {
processInputWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, ValueType>(input); processInputWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, ValueType>(input);
} }
} }
}
}
} }

56
src/storm/api/verification.h

@ -12,6 +12,7 @@
#include "storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h" #include "storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h"
#include "storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h" #include "storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h"
#include "storm/modelchecker/abstraction/GameBasedMdpModelChecker.h" #include "storm/modelchecker/abstraction/GameBasedMdpModelChecker.h"
#include "storm/modelchecker/abstraction/PartialBisimulationMdpModelChecker.h"
#include "storm/modelchecker/exploration/SparseExplorationModelChecker.h" #include "storm/modelchecker/exploration/SparseExplorationModelChecker.h"
#include "storm/modelchecker/reachability/SparseDtmcEliminationModelChecker.h" #include "storm/modelchecker/reachability/SparseDtmcEliminationModelChecker.h"
@ -30,7 +31,7 @@
namespace storm { namespace storm {
namespace api { namespace api {
template<typename ValueType> template<typename ValueType>
storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> createTask(std::shared_ptr<const storm::logic::Formula> const& formula, bool onlyInitialStatesRelevant = false) { storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> createTask(std::shared_ptr<const storm::logic::Formula> const& formula, bool onlyInitialStatesRelevant = false) {
return storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>(*formula, onlyInitialStatesRelevant); return storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>(*formula, onlyInitialStatesRelevant);
@ -41,6 +42,7 @@ namespace storm {
STORM_LOG_THROW(model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::DTMC || model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::MDP, storm::exceptions::NotSupportedException, "Can only treat DTMCs/MDPs using the abstraction refinement engine."); STORM_LOG_THROW(model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::DTMC || model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::MDP, storm::exceptions::NotSupportedException, "Can only treat DTMCs/MDPs using the abstraction refinement engine.");
std::unique_ptr<storm::modelchecker::CheckResult> result; std::unique_ptr<storm::modelchecker::CheckResult> result;
if (model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::DTMC) { if (model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::DTMC) {
storm::modelchecker::GameBasedMdpModelChecker<DdType, storm::models::symbolic::Dtmc<DdType, ValueType>> modelchecker(model); storm::modelchecker::GameBasedMdpModelChecker<DdType, storm::models::symbolic::Dtmc<DdType, ValueType>> modelchecker(model);
if (modelchecker.canHandle(task)) { if (modelchecker.canHandle(task)) {
@ -51,21 +53,47 @@ namespace storm {
if (modelchecker.canHandle(task)) { if (modelchecker.canHandle(task)) {
result = modelchecker.check(task); result = modelchecker.check(task);
} }
} else {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException);
} }
return result; return result;
} }
template<storm::dd::DdType DdType, typename ValueType> template<storm::dd::DdType DdType, typename ValueType>
typename std::enable_if<!std::is_same<ValueType, double>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const&, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const&) { typename std::enable_if<!std::is_same<ValueType, double>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const&, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const&) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Abstraction-refinement engine does not support data type."); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Abstraction-refinement engine does not support data type.");
} }
template<storm::dd::DdType DdType, typename ValueType>
typename std::enable_if<std::is_same<ValueType, double>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithAbstractionRefinementEngine(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) {
std::unique_ptr<storm::modelchecker::CheckResult> result;
if (model->getType() == storm::models::ModelType::Dtmc) {
storm::modelchecker::PartialBisimulationMdpModelChecker<storm::models::symbolic::Dtmc<DdType, ValueType>> modelchecker(model->as<storm::models::symbolic::Dtmc<DdType, double>>());
if (modelchecker.canHandle(task)) {
result = modelchecker.check(task);
}
} else if (model->getType() == storm::models::ModelType::Mdp) {
storm::modelchecker::PartialBisimulationMdpModelChecker<storm::models::symbolic::Mdp<DdType, ValueType>> modelchecker(model->as<storm::models::symbolic::Mdp<DdType, double>>());
if (modelchecker.canHandle(task)) {
result = modelchecker.check(task);
}
} else {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The model type is not supported by the dd engine.");
}
return result;
}
template<storm::dd::DdType DdType, typename ValueType>
typename std::enable_if<!std::is_same<ValueType, double>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithAbstractionRefinementEngine(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Abstraction-refinement engine does not support data type.");
}
template<typename ValueType> template<typename ValueType>
typename std::enable_if<std::is_same<ValueType, double>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithExplorationEngine(storm::storage::SymbolicModelDescription const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) { typename std::enable_if<std::is_same<ValueType, double>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithExplorationEngine(storm::storage::SymbolicModelDescription const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) {
STORM_LOG_THROW(model.isPrismProgram(), storm::exceptions::NotSupportedException, "Exploration engine is currently only applicable to PRISM models."); STORM_LOG_THROW(model.isPrismProgram(), storm::exceptions::NotSupportedException, "Exploration engine is currently only applicable to PRISM models.");
storm::prism::Program const& program = model.asPrismProgram(); storm::prism::Program const& program = model.asPrismProgram();
STORM_LOG_THROW(program.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::MDP, storm::exceptions::NotSupportedException, "Currently exploration-based verification is only available for DTMCs and MDPs."); STORM_LOG_THROW(program.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::MDP, storm::exceptions::NotSupportedException, "Currently exploration-based verification is only available for DTMCs and MDPs.");
std::unique_ptr<storm::modelchecker::CheckResult> result; std::unique_ptr<storm::modelchecker::CheckResult> result;
if (program.getModelType() == storm::prism::Program::ModelType::DTMC) { if (program.getModelType() == storm::prism::Program::ModelType::DTMC) {
storm::modelchecker::SparseExplorationModelChecker<storm::models::sparse::Dtmc<ValueType>> checker(program); storm::modelchecker::SparseExplorationModelChecker<storm::models::sparse::Dtmc<ValueType>> checker(program);
@ -80,7 +108,7 @@ namespace storm {
} }
return result; return result;
} }
template<typename ValueType> template<typename ValueType>
typename std::enable_if<!std::is_same<ValueType, double>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithExplorationEngine(storm::storage::SymbolicModelDescription const&, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const&) { typename std::enable_if<!std::is_same<ValueType, double>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithExplorationEngine(storm::storage::SymbolicModelDescription const&, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const&) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Exploration engine does not support data type."); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Exploration engine does not support data type.");
@ -122,16 +150,16 @@ namespace storm {
} }
return result; return result;
} }
template<typename ValueType> template<typename ValueType>
typename std::enable_if<std::is_same<ValueType, storm::RationalFunction>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithSparseEngine(std::shared_ptr<storm::models::sparse::Mdp<ValueType>> const&, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const&) { typename std::enable_if<std::is_same<ValueType, storm::RationalFunction>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithSparseEngine(std::shared_ptr<storm::models::sparse::Mdp<ValueType>> const&, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const&) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sparse engine cannot verify MDPs with this data type."); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sparse engine cannot verify MDPs with this data type.");
} }
template<typename ValueType> template<typename ValueType>
typename std::enable_if<!std::is_same<ValueType, storm::RationalFunction>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithSparseEngine(std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> const& ma, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) { typename std::enable_if<!std::is_same<ValueType, storm::RationalFunction>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithSparseEngine(std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> const& ma, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) {
std::unique_ptr<storm::modelchecker::CheckResult> result; std::unique_ptr<storm::modelchecker::CheckResult> result;
// Close the MA, if it is not already closed. // Close the MA, if it is not already closed.
if (!ma->isClosed()) { if (!ma->isClosed()) {
STORM_LOG_WARN("Closing Markov automaton. Consider closing the MA before verification."); STORM_LOG_WARN("Closing Markov automaton. Consider closing the MA before verification.");
@ -144,12 +172,12 @@ namespace storm {
} }
return result; return result;
} }
template<typename ValueType> template<typename ValueType>
typename std::enable_if<std::is_same<ValueType, storm::RationalFunction>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithSparseEngine(std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> const& ma, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) { typename std::enable_if<std::is_same<ValueType, storm::RationalFunction>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithSparseEngine(std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> const& ma, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sparse engine cannot verify MAs with this data type."); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sparse engine cannot verify MAs with this data type.");
} }
template<typename ValueType> template<typename ValueType>
std::unique_ptr<storm::modelchecker::CheckResult> verifyWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) { std::unique_ptr<storm::modelchecker::CheckResult> verifyWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) {
std::unique_ptr<storm::modelchecker::CheckResult> result; std::unique_ptr<storm::modelchecker::CheckResult> result;
@ -176,7 +204,7 @@ namespace storm {
} }
return result; return result;
} }
template<storm::dd::DdType DdType, typename ValueType> template<storm::dd::DdType DdType, typename ValueType>
std::unique_ptr<storm::modelchecker::CheckResult> verifyWithHybridEngine(std::shared_ptr<storm::models::symbolic::Ctmc<DdType, ValueType>> const& ctmc, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) { std::unique_ptr<storm::modelchecker::CheckResult> verifyWithHybridEngine(std::shared_ptr<storm::models::symbolic::Ctmc<DdType, ValueType>> const& ctmc, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) {
std::unique_ptr<storm::modelchecker::CheckResult> result; std::unique_ptr<storm::modelchecker::CheckResult> result;
@ -196,12 +224,12 @@ namespace storm {
} }
return result; return result;
} }
template<storm::dd::DdType DdType, typename ValueType> template<storm::dd::DdType DdType, typename ValueType>
typename std::enable_if<std::is_same<ValueType, storm::RationalFunction>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithHybridEngine(std::shared_ptr<storm::models::symbolic::Mdp<DdType, ValueType>> const&, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const&) { typename std::enable_if<std::is_same<ValueType, storm::RationalFunction>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithHybridEngine(std::shared_ptr<storm::models::symbolic::Mdp<DdType, ValueType>> const&, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const&) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Hybrid engine cannot verify MDPs with this data type."); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Hybrid engine cannot verify MDPs with this data type.");
} }
template<storm::dd::DdType DdType, typename ValueType> template<storm::dd::DdType DdType, typename ValueType>
std::unique_ptr<storm::modelchecker::CheckResult> verifyWithHybridEngine(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) { std::unique_ptr<storm::modelchecker::CheckResult> verifyWithHybridEngine(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) {
std::unique_ptr<storm::modelchecker::CheckResult> result; std::unique_ptr<storm::modelchecker::CheckResult> result;
@ -216,7 +244,7 @@ namespace storm {
} }
return result; return result;
} }
template<storm::dd::DdType DdType, typename ValueType> template<storm::dd::DdType DdType, typename ValueType>
std::unique_ptr<storm::modelchecker::CheckResult> verifyWithDdEngine(std::shared_ptr<storm::models::symbolic::Dtmc<DdType, ValueType>> const& dtmc, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) { std::unique_ptr<storm::modelchecker::CheckResult> verifyWithDdEngine(std::shared_ptr<storm::models::symbolic::Dtmc<DdType, ValueType>> const& dtmc, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) {
std::unique_ptr<storm::modelchecker::CheckResult> result; std::unique_ptr<storm::modelchecker::CheckResult> result;
@ -236,7 +264,7 @@ namespace storm {
} }
return result; return result;
} }
template<storm::dd::DdType DdType, typename ValueType> template<storm::dd::DdType DdType, typename ValueType>
typename std::enable_if<std::is_same<ValueType, storm::RationalFunction>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithDdEngine(std::shared_ptr<storm::models::symbolic::Mdp<DdType, ValueType>> const&, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const&) { typename std::enable_if<std::is_same<ValueType, storm::RationalFunction>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithDdEngine(std::shared_ptr<storm::models::symbolic::Mdp<DdType, ValueType>> const&, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const&) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Dd engine cannot verify MDPs with this data type."); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Dd engine cannot verify MDPs with this data type.");

19
src/storm/modelchecker/abstraction/PartialBisimulationMdpModelChecker.cpp

@ -0,0 +1,19 @@
#include "storm/modelchecker/abstraction/PartialBisimulationMdpModelChecker.h"
#include "storm/models/symbolic/Dtmc.h"
#include "storm/models/symbolic/Mdp.h"
namespace storm {
namespace modelchecker {
template<storm::dd::DdType Type, typename ModelType>
PartialBisimulationMdpModelChecker<Type, ModelType>::PartialBisimulationMdpModelChecker(ModelType const& model) : model(model) {
}
template class PartialBisimulationMdpModelChecker<storm::dd::DdType::CUDD, storm::models::symbolic::Dtmc<storm::dd::DdType::CUDD, double>>;
template class PartialBisimulationMdpModelChecker<storm::dd::DdType::CUDD, storm::models::symbolic::Mdp<storm::dd::DdType::CUDD, double>>;
template class PartialBisimulationMdpModelChecker<storm::dd::DdType::Sylvan, storm::models::symbolic::Dtmc<storm::dd::DdType::Sylvan, double>>;
template class PartialBisimulationMdpModelChecker<storm::dd::DdType::Sylvan, storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan, double>>;
}
}

29
src/storm/modelchecker/abstraction/PartialBisimulationMdpModelChecker.h

@ -0,0 +1,29 @@
#pragma once
#include "storm/modelchecker/AbstractModelChecker.h"
#include "storm/storage/dd/DdType.h"
namespace storm {
namespace modelchecker {
template<storm::dd::DdType Type, typename ModelType>
class PartialBisimulationMdpModelChecker : public AbstractModelChecker<ModelType> {
public:
typedef typename ModelType::ValueType ValueType;
/*!
* Constructs a model checker for the given model.
*/
explicit PartialBisimulationMdpModelChecker(ModelType const& model);
// /// Overridden methods from super class.
// virtual bool canHandle(CheckTask<storm::logic::Formula> const& checkTask) const override;
// virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override;
// virtual std::unique_ptr<CheckResult> computeReachabilityProbabilities(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
private:
ModelType const& model;
};
}
}

1
src/storm/models/symbolic/StochasticTwoPlayerGame.cpp

@ -86,6 +86,7 @@ namespace storm {
template class StochasticTwoPlayerGame<storm::dd::DdType::CUDD, double>; template class StochasticTwoPlayerGame<storm::dd::DdType::CUDD, double>;
template class StochasticTwoPlayerGame<storm::dd::DdType::Sylvan, double>; template class StochasticTwoPlayerGame<storm::dd::DdType::Sylvan, double>;
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
template class StochasticTwoPlayerGame<storm::dd::DdType::Sylvan, storm::RationalNumber>;
template class StochasticTwoPlayerGame<storm::dd::DdType::Sylvan, storm::RationalFunction>; template class StochasticTwoPlayerGame<storm::dd::DdType::Sylvan, storm::RationalFunction>;
#endif #endif

17
src/storm/settings/modules/AbstractionSettings.cpp

@ -12,6 +12,7 @@ namespace storm {
namespace settings { namespace settings {
namespace modules { namespace modules {
const std::string AbstractionSettings::methodOptionName = "method";
const std::string AbstractionSettings::moduleName = "abstraction"; const std::string AbstractionSettings::moduleName = "abstraction";
const std::string AbstractionSettings::useDecompositionOptionName = "decomposition"; const std::string AbstractionSettings::useDecompositionOptionName = "decomposition";
const std::string AbstractionSettings::splitModeOptionName = "split"; const std::string AbstractionSettings::splitModeOptionName = "split";
@ -22,6 +23,12 @@ namespace storm {
const std::string AbstractionSettings::reuseResultsOptionName = "reuse"; const std::string AbstractionSettings::reuseResultsOptionName = "reuse";
AbstractionSettings::AbstractionSettings() : ModuleSettings(moduleName) { AbstractionSettings::AbstractionSettings() : ModuleSettings(moduleName) {
std::vector<std::string> methods = {"games", "bisimulation", "bisim"};
this->addOption(storm::settings::OptionBuilder(moduleName, methodOptionName, true, "Sets which abstraction-refinement method to use.")
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of themethod to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(methods))
.setDefaultValueString("bisim").build())
.build());
std::vector<std::string> onOff = {"on", "off"}; std::vector<std::string> onOff = {"on", "off"};
this->addOption(storm::settings::OptionBuilder(moduleName, useDecompositionOptionName, true, "Sets whether to apply decomposition during the abstraction.") this->addOption(storm::settings::OptionBuilder(moduleName, useDecompositionOptionName, true, "Sets whether to apply decomposition during the abstraction.")
@ -59,6 +66,16 @@ namespace storm {
.build()); .build());
} }
AbstractionSettings::Method AbstractionSettings::getAbstractionRefinementMethod() const {
std::string methodAsString = this->getOption(methodOptionName).getArgumentByName("method").getValueAsString();
if (methodAsString == "games") {
return Method::Games;
} else if (methodAsString == "bisimulation" || methodAsString == "bism") {
return Method::Bisimulation;
}
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown abstraction-refinement method '" << methodAsString << "'.");
}
bool AbstractionSettings::isUseDecompositionSet() const { bool AbstractionSettings::isUseDecompositionSet() const {
return this->getOption(useDecompositionOptionName).getHasOptionBeenSet(); return this->getOption(useDecompositionOptionName).getHasOptionBeenSet();
} }

10
src/storm/settings/modules/AbstractionSettings.h

@ -11,6 +11,10 @@ namespace storm {
*/ */
class AbstractionSettings : public ModuleSettings { class AbstractionSettings : public ModuleSettings {
public: public:
enum class Method {
Games, Bisimulation
};
enum class PivotSelectionHeuristic { enum class PivotSelectionHeuristic {
NearestMaximalDeviation, MostProbablePath, MaxWeightedDeviation NearestMaximalDeviation, MostProbablePath, MaxWeightedDeviation
}; };
@ -28,6 +32,11 @@ namespace storm {
*/ */
AbstractionSettings(); AbstractionSettings();
/*!
* Retrieves the selected abstraction refinement method.
*/
Method getAbstractionRefinementMethod() const;
/*! /*!
* Retrieves whether the option to use the decomposition was set. * Retrieves whether the option to use the decomposition was set.
* *
@ -87,6 +96,7 @@ namespace storm {
const static std::string moduleName; const static std::string moduleName;
private: private:
const static std::string methodOptionName;
const static std::string useDecompositionOptionName; const static std::string useDecompositionOptionName;
const static std::string splitModeOptionName; const static std::string splitModeOptionName;
const static std::string addAllGuardsOptionName; const static std::string addAllGuardsOptionName;

2
src/storm/storage/dd/BisimulationDecomposition.cpp

@ -140,6 +140,8 @@ namespace storm {
QuotientExtractor<DdType, ValueType> extractor; QuotientExtractor<DdType, ValueType> extractor;
quotient = extractor.extract(model, refiner->getStatePartition(), preservationInformation); quotient = extractor.extract(model, refiner->getStatePartition(), preservationInformation);
} else { } else {
STORM_LOG_THROW(model.getType() == storm::models::ModelType::Dtmc || model.getType() == storm::models::ModelType::Mdp, storm::exceptions::InvalidOperationException, "Can only extract partial quotient for discrete-time models.");
STORM_LOG_TRACE("Starting partial quotient extraction."); STORM_LOG_TRACE("Starting partial quotient extraction.");
if (!partialQuotientExtractor) { if (!partialQuotientExtractor) {
partialQuotientExtractor = std::make_unique<bisimulation::PartialQuotientExtractor<DdType, ValueType>>(model); partialQuotientExtractor = std::make_unique<bisimulation::PartialQuotientExtractor<DdType, ValueType>>(model);

25
src/storm/storage/dd/bisimulation/PartialQuotientExtractor.cpp

@ -3,6 +3,7 @@
#include "storm/storage/dd/DdManager.h" #include "storm/storage/dd/DdManager.h"
#include "storm/models/symbolic/Mdp.h" #include "storm/models/symbolic/Mdp.h"
#include "storm/models/symbolic/StochasticTwoPlayerGame.h"
#include "storm/models/symbolic/StandardRewardModel.h" #include "storm/models/symbolic/StandardRewardModel.h"
#include "storm/settings/SettingsManager.h" #include "storm/settings/SettingsManager.h"
@ -13,7 +14,7 @@
namespace storm { namespace storm {
namespace dd { namespace dd {
namespace bisimulation { namespace bisimulation {
template<storm::dd::DdType DdType, typename ValueType> template<storm::dd::DdType DdType, typename ValueType>
PartialQuotientExtractor<DdType, ValueType>::PartialQuotientExtractor(storm::models::symbolic::Model<DdType, ValueType> const& model) : model(model) { PartialQuotientExtractor<DdType, ValueType>::PartialQuotientExtractor(storm::models::symbolic::Model<DdType, ValueType> const& model) : model(model) {
auto const& settings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>(); auto const& settings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>();
@ -26,7 +27,7 @@ namespace storm {
std::shared_ptr<storm::models::Model<ValueType>> PartialQuotientExtractor<DdType, ValueType>::extract(Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation) { std::shared_ptr<storm::models::Model<ValueType>> PartialQuotientExtractor<DdType, ValueType>::extract(Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation) {
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
std::shared_ptr<storm::models::Model<ValueType>> result; std::shared_ptr<storm::models::Model<ValueType>> result;
STORM_LOG_THROW(this->quotientFormat == storm::settings::modules::BisimulationSettings::QuotientFormat::Dd, storm::exceptions::NotSupportedException, "Only DD-based partial quotient extraction is currently supported."); STORM_LOG_THROW(this->quotientFormat == storm::settings::modules::BisimulationSettings::QuotientFormat::Dd, storm::exceptions::NotSupportedException, "Only DD-based partial quotient extraction is currently supported.");
result = extractDdQuotient(partition, preservationInformation); result = extractDdQuotient(partition, preservationInformation);
auto end = std::chrono::high_resolution_clock::now(); auto end = std::chrono::high_resolution_clock::now();
@ -41,7 +42,7 @@ namespace storm {
std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> PartialQuotientExtractor<DdType, ValueType>::extractDdQuotient(Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation) { std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> PartialQuotientExtractor<DdType, ValueType>::extractDdQuotient(Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation) {
auto modelType = model.getType(); auto modelType = model.getType();
if (modelType == storm::models::ModelType::Dtmc) {
if (modelType == storm::models::ModelType::Dtmc || modelType == storm::models::ModelType::Mdp) {
// Sanity checks. // Sanity checks.
STORM_LOG_ASSERT(partition.getNumberOfStates() == model.getNumberOfStates(), "Mismatching partition size."); STORM_LOG_ASSERT(partition.getNumberOfStates() == model.getNumberOfStates(), "Mismatching partition size.");
STORM_LOG_ASSERT(partition.getStates().renameVariables(model.getColumnVariables(), model.getRowVariables()) == model.getReachableStates(), "Mismatching partition."); STORM_LOG_ASSERT(partition.getStates().renameVariables(model.getColumnVariables(), model.getRowVariables()) == model.getReachableStates(), "Mismatching partition.");
@ -84,12 +85,6 @@ namespace storm {
storm::dd::Add<DdType, ValueType> partitionAsAdd = partitionAsBdd.template toAdd<ValueType>(); storm::dd::Add<DdType, ValueType> partitionAsAdd = partitionAsBdd.template toAdd<ValueType>();
storm::dd::Add<DdType, ValueType> quotientTransitionMatrix = model.getTransitionMatrix().multiplyMatrix(partitionAsAdd.renameVariables(blockAndRowVariables, blockPrimeAndColumnVariables), model.getColumnVariables()); storm::dd::Add<DdType, ValueType> quotientTransitionMatrix = model.getTransitionMatrix().multiplyMatrix(partitionAsAdd.renameVariables(blockAndRowVariables, blockPrimeAndColumnVariables), model.getColumnVariables());
// // Pick a representative from each block.
// auto representatives = InternalRepresentativeComputer<DdType>(partitionAsBdd, model.getRowVariables()).getRepresentatives();
// partitionAsBdd &= representatives;
// partitionAsAdd *= partitionAsBdd.template toAdd<ValueType>();
// quotientTransitionMatrix = quotientTransitionMatrix.multiplyMatrix(partitionAsAdd, model.getRowVariables());
quotientTransitionMatrix = quotientTransitionMatrix * partitionAsAdd; quotientTransitionMatrix = quotientTransitionMatrix * partitionAsAdd;
end = std::chrono::high_resolution_clock::now(); end = std::chrono::high_resolution_clock::now();
@ -125,11 +120,13 @@ namespace storm {
end = std::chrono::high_resolution_clock::now(); end = std::chrono::high_resolution_clock::now();
STORM_LOG_TRACE("Reward models extracted in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms."); STORM_LOG_TRACE("Reward models extracted in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
std::set<storm::expressions::Variable> newNondeterminismVariables = model.getNondeterminismVariables();
newNondeterminismVariables.insert(model.getRowVariables().begin(), model.getRowVariables().end());
if (modelType == storm::models::ModelType::Dtmc) { if (modelType == storm::models::ModelType::Dtmc) {
return std::shared_ptr<storm::models::symbolic::Mdp<DdType, ValueType>>(new storm::models::symbolic::Mdp<DdType, ValueType>(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, newNondeterminismVariables, preservedLabelBdds, quotientRewardModels));
return std::make_shared<storm::models::symbolic::Mdp<DdType, ValueType>>(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getRowVariables(), preservedLabelBdds, quotientRewardModels);
} else if (modelType == storm::models::ModelType::Mdp) {
std::set<storm::expressions::Variable> allNondeterminismVariables;
std::set_union(model.getRowVariables().begin(), model.getRowVariables().end(), model.getNondeterminismVariables().begin(), model.getNondeterminismVariables().end(), std::inserter(allNondeterminismVariables, allNondeterminismVariables.begin()));
return std::make_shared<storm::models::symbolic::StochasticTwoPlayerGame<DdType, ValueType>>(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getRowVariables(), model.getNondeterminismVariables(), allNondeterminismVariables, preservedLabelBdds, quotientRewardModels);
} else { } else {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unsupported quotient type."); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unsupported quotient type.");
} }
@ -140,7 +137,7 @@ namespace storm {
template class PartialQuotientExtractor<storm::dd::DdType::CUDD, double>; template class PartialQuotientExtractor<storm::dd::DdType::CUDD, double>;
template class PartialQuotientExtractor<storm::dd::DdType::Sylvan, double>; template class PartialQuotientExtractor<storm::dd::DdType::Sylvan, double>;
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
template class PartialQuotientExtractor<storm::dd::DdType::Sylvan, storm::RationalNumber>; template class PartialQuotientExtractor<storm::dd::DdType::Sylvan, storm::RationalNumber>;
template class PartialQuotientExtractor<storm::dd::DdType::Sylvan, storm::RationalFunction>; template class PartialQuotientExtractor<storm::dd::DdType::Sylvan, storm::RationalFunction>;

8
src/storm/storage/dd/bisimulation/PartialQuotientExtractor.h

@ -15,20 +15,20 @@
namespace storm { namespace storm {
namespace dd { namespace dd {
namespace bisimulation { namespace bisimulation {
template<storm::dd::DdType DdType, typename ValueType> template<storm::dd::DdType DdType, typename ValueType>
class PartialQuotientExtractor { class PartialQuotientExtractor {
public:
public:
PartialQuotientExtractor(storm::models::symbolic::Model<DdType, ValueType> const& model); PartialQuotientExtractor(storm::models::symbolic::Model<DdType, ValueType> const& model);
std::shared_ptr<storm::models::Model<ValueType>> extract(Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation); std::shared_ptr<storm::models::Model<ValueType>> extract(Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation);
private:
private:
std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> extractDdQuotient(Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation); std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> extractDdQuotient(Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation);
// The model for which to compute the partial quotient. // The model for which to compute the partial quotient.
storm::models::symbolic::Model<DdType, ValueType> const& model; storm::models::symbolic::Model<DdType, ValueType> const& model;
storm::settings::modules::BisimulationSettings::QuotientFormat quotientFormat; storm::settings::modules::BisimulationSettings::QuotientFormat quotientFormat;
}; };

Loading…
Cancel
Save