Browse Source

Merge branch 'jani_support' into export_explicit

Former-commit-id: 4a5dc499e8 [formerly 7dca599712]
Former-commit-id: 65c17bb14e
tempestpy_adaptions
sjunges 8 years ago
parent
commit
3daa725bb5
  1. 2
      resources/3rdparty/CMakeLists.txt
  2. 206
      resources/cmake/find_modules/FindHwloc.cmake
  3. 8
      src/builder/DdJaniModelBuilder.cpp
  4. 59
      src/cli/cli.cpp
  5. 144
      src/cli/entrypoints.h
  6. 2
      src/generator/JaniNextStateGenerator.cpp
  7. 36
      src/generator/VariableInformation.cpp
  8. 41
      src/modelchecker/results/ExplicitQualitativeCheckResult.cpp
  9. 6
      src/modelchecker/results/ExplicitQualitativeCheckResult.h
  10. 59
      src/modelchecker/results/ExplicitQuantitativeCheckResult.cpp
  11. 6
      src/modelchecker/results/ExplicitQuantitativeCheckResult.h
  12. 32
      src/modelchecker/results/FilterType.cpp
  13. 14
      src/modelchecker/results/FilterType.h
  14. 14
      src/modelchecker/results/HybridQuantitativeCheckResult.cpp
  15. 9
      src/modelchecker/results/HybridQuantitativeCheckResult.h
  16. 4
      src/modelchecker/results/QualitativeCheckResult.h
  17. 12
      src/modelchecker/results/QuantitativeCheckResult.h
  18. 17
      src/modelchecker/results/SymbolicQualitativeCheckResult.cpp
  19. 6
      src/modelchecker/results/SymbolicQualitativeCheckResult.h
  20. 12
      src/modelchecker/results/SymbolicQuantitativeCheckResult.cpp
  21. 7
      src/modelchecker/results/SymbolicQuantitativeCheckResult.h
  22. 23
      src/parser/CSVParser.cpp
  23. 12
      src/parser/CSVParser.h
  24. 288
      src/parser/JaniParser.cpp
  25. 25
      src/parser/JaniParser.h
  26. 32
      src/parser/KeyValueParser.cpp
  27. 11
      src/parser/KeyValueParser.h
  28. 16
      src/settings/modules/IOSettings.cpp
  29. 6
      src/settings/modules/IOSettings.h
  30. 5
      src/storage/jani/BooleanVariable.cpp
  31. 2
      src/storage/jani/BooleanVariable.h
  32. 9
      src/storage/jani/BoundedIntegerVariable.cpp
  33. 4
      src/storage/jani/BoundedIntegerVariable.h
  34. 348
      src/storage/jani/JSONExporter.cpp
  35. 39
      src/storage/jani/JSONExporter.h
  36. 28
      src/storage/jani/Property.cpp
  37. 66
      src/storage/jani/Property.h
  38. 2
      src/storage/jani/RealVariable.cpp
  39. 2
      src/storage/jani/RealVariable.h
  40. 2
      src/storage/jani/UnboundedIntegerVariable.cpp
  41. 2
      src/storage/jani/Variable.cpp
  42. 2
      src/storage/jani/Variable.h
  43. 2
      src/storage/ppg/defines.h
  44. 4
      src/storage/prism/Module.cpp
  45. 6
      src/storage/prism/ToJaniConverter.cpp
  46. 95
      src/utility/constants.cpp
  47. 16
      src/utility/constants.h
  48. 15
      src/utility/storm.cpp
  49. 3
      src/utility/storm.h

2
resources/3rdparty/CMakeLists.txt

@ -330,7 +330,7 @@ add_dependencies(resources sylvan)
if(${OPERATING_SYSTEM} MATCHES "Linux")
find_package(Hwloc QUIET REQUIRED)
if(Hwloc_FOUND)
if(HWLOC_FOUND)
message(STATUS "StoRM - Linking with hwloc ${Hwloc_VERSION}")
list(APPEND STORM_LINK_LIBRARIES ${Hwloc_LIBRARIES})
else()

206
resources/cmake/find_modules/FindHwloc.cmake

@ -1,179 +1,55 @@
# FindHwloc
# ----------
# Try to find hwloc libraries and headers.
#
# Try to find Portable Hardware Locality (hwloc) libraries.
# http://www.open-mpi.org/software/hwloc
# Usage of this module:
#
# You may declare HWLOC_ROOT environment variable to tell where
# your hwloc library is installed.
# find_package(hwloc)
#
# Once done this will define::
# Variables defined by this module:
#
# Hwloc_FOUND - True if hwloc was found
# Hwloc_INCLUDE_DIRS - include directories for hwloc
# Hwloc_LIBRARIES - link against these libraries to use hwloc
# Hwloc_VERSION - version
# Hwloc_CFLAGS - include directories as compiler flags
# Hwloc_LDLFAGS - link paths and libs as compiler flags
#
#=============================================================================
# Copyright 2014 Mikael Lepistö
#
# Distributed under the OSI-approved BSD License (the "License");
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
if(WIN32)
find_path(Hwloc_INCLUDE_DIR
NAMES
hwloc.h
PATHS
ENV "PROGRAMFILES(X86)"
ENV HWLOC_ROOT
PATH_SUFFIXES
include
)
find_library(Hwloc_LIBRARY
NAMES
libhwloc.lib
PATHS
ENV "PROGRAMFILES(X86)"
ENV HWLOC_ROOT
PATH_SUFFIXES
lib
)
#
# Check if the found library can be used to linking
#
SET (_TEST_SOURCE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/linktest.c")
FILE (WRITE "${_TEST_SOURCE}"
"
#include <hwloc.h>
int main()
{
hwloc_topology_t topology;
int nbcores;
hwloc_topology_init(&topology);
hwloc_topology_load(topology);
nbcores = hwloc_get_nbobjs_by_type(topology, HWLOC_OBJ_CORE);
hwloc_topology_destroy(topology);
return 0;
}
"
)
TRY_COMPILE(_LINK_SUCCESS ${CMAKE_BINARY_DIR} "${_TEST_SOURCE}"
CMAKE_FLAGS
"-DINCLUDE_DIRECTORIES:STRING=${Hwloc_INCLUDE_DIR}"
CMAKE_FLAGS
"-DLINK_LIBRARIES:STRING=${Hwloc_LIBRARY}"
)
IF(NOT _LINK_SUCCESS)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
message(STATUS "You are building 64bit target.")
ELSE()
message(STATUS "You are building 32bit code. If you like to build x64 use e.g. -G 'Visual Studio 12 Win64' generator." )
ENDIF()
message(FATAL_ERROR "Library found, but linking test program failed.")
ENDIF()
#
# Resolve version if some compiled binary found...
#
find_program(HWLOC_INFO_EXECUTABLE
NAMES
hwloc-info
PATHS
ENV HWLOC_ROOT
PATH_SUFFIXES
bin
)
if(HWLOC_INFO_EXECUTABLE)
execute_process(
COMMAND ${HWLOC_INFO_EXECUTABLE} "--version"
OUTPUT_VARIABLE HWLOC_VERSION_LINE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(REGEX MATCH "([0-9]+.[0-9]+)$"
Hwloc_VERSION "${HWLOC_VERSION_LINE}")
unset(HWLOC_VERSION_LINE)
endif()
#
# All good
#
set(Hwloc_LIBRARIES ${Hwloc_LIBRARY})
set(Hwloc_INCLUDE_DIRS ${Hwloc_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
Hwloc
FOUND_VAR Hwloc_FOUND
REQUIRED_VARS Hwloc_LIBRARY Hwloc_INCLUDE_DIR
VERSION_VAR Hwloc_VERSION)
mark_as_advanced(
Hwloc_INCLUDE_DIR
Hwloc_LIBRARY)
foreach(arg ${Hwloc_INCLUDE_DIRS})
set(Hwloc_CFLAGS "${Hwloc_CFLAGS} /I${arg}")
endforeach()
# HWLOC_FOUND System has hwloc libraries and headers
# HWLOC_LIBRARIES The hwloc library
# HWLOC_INCLUDE_DIRS The location of HWLOC headers
set(Hwloc_LDFLAGS "${Hwloc_LIBRARY}")
find_path(
HWLOC_PREFIX
NAMES include/hwloc.h
)
else()
if (NOT HWLOC_PREFIX AND NOT $ENV{HWLOC_BASE} STREQUAL "")
set(HWLOC_PREFIX $ENV{HWLOC_BASE})
endif()
# Find with pkgconfig
find_package(PkgConfig)
message(STATUS "Searching for hwloc library in path " ${HWLOC_PREFIX})
if(HWLOC_ROOT)
set(ENV{PKG_CONFIG_PATH} "${HWLOC_ROOT}/lib/pkgconfig")
else()
foreach(PREFIX ${CMAKE_PREFIX_PATH})
set(PKG_CONFIG_PATH "${PKG_CONFIG_PATH}:${PREFIX}/lib/pkgconfig")
endforeach()
set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}:$ENV{PKG_CONFIG_PATH}")
endif()
find_library(
HWLOC_LIBRARIES
NAMES hwloc
HINTS ${HWLOC_PREFIX}/lib
)
if(hwloc_FIND_REQUIRED)
set(_hwloc_OPTS "REQUIRED")
elseif(hwloc_FIND_QUIETLY)
set(_hwloc_OPTS "QUIET")
else()
set(_hwloc_output 1)
endif()
find_path(
HWLOC_INCLUDE_DIRS
NAMES hwloc.h
HINTS ${HWLOC_PREFIX}/include
)
if(hwloc_FIND_VERSION)
if(hwloc_FIND_VERSION_EXACT)
pkg_check_modules(Hwloc ${_hwloc_OPTS} hwloc=${hwloc_FIND_VERSION})
else()
pkg_check_modules(Hwloc ${_hwloc_OPTS} hwloc>=${hwloc_FIND_VERSION})
endif()
else()
pkg_check_modules(Hwloc ${_hwloc_OPTS} hwloc)
endif()
include(FindPackageHandleStandardArgs)
if(Hwloc_FOUND)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Hwloc DEFAULT_MSG Hwloc_LIBRARIES)
find_package_handle_standard_args(
HWLOC DEFAULT_MSG
HWLOC_LIBRARIES
HWLOC_INCLUDE_DIRS
)
if(NOT ${Hwloc_VERSION} VERSION_LESS 1.7.0)
set(Hwloc_GL_FOUND 1)
endif()
mark_as_advanced(
HWLOC_LIBRARIES
HWLOC_INCLUDE_DIRS
)
if(_hwloc_output)
message(STATUS
"Found hwloc ${Hwloc_VERSION} in ${Hwloc_INCLUDE_DIRS}:${Hwloc_LIBRARIES}")
endif()
if (HWLOC_FOUND)
if (NOT $ENV{HWLOC_LIB} STREQUAL "")
# set(HWLOC_LIBRARIES "$ENV{HWLOC_LIB}")
endif()
endif()
message(STATUS "hwloc includes: " ${HWLOC_INCLUDE_DIRS})
message(STATUS "hwloc libraries: " ${HWLOC_LIBRARIES})
endif()

8
src/builder/DdJaniModelBuilder.cpp

@ -895,7 +895,6 @@ namespace storm {
if (action.isInputEnabled()) {
// If the action is input-enabled, we add self-loops to all states.
transitions *= actionGuard.ite(action.transitions, encodeIndex(0, action.getLowestLocalNondeterminismVariable(), action.getHighestLocalNondeterminismVariable() - action.getLowestLocalNondeterminismVariable(), this->variables) * actionIdentityPair.second);
actionGuard.ite(action.transitions, encodeIndex(0, action.getLowestLocalNondeterminismVariable(), action.getHighestLocalNondeterminismVariable() - action.getLowestLocalNondeterminismVariable(), this->variables) * actionIdentityPair.second).exportToDot("this.dot");
} else {
transitions *= action.transitions;
}
@ -1107,7 +1106,8 @@ namespace storm {
}
// Add the source location and the guard.
transitions *= this->variables.manager->getEncoding(this->variables.automatonToLocationDdVariableMap.at(automaton.getName()).first, edge.getSourceLocationIndex()).template toAdd<ValueType>() * guard;
storm::dd::Add<Type, ValueType> sourceLocationAndGuard = this->variables.manager->getEncoding(this->variables.automatonToLocationDdVariableMap.at(automaton.getName()).first, edge.getSourceLocationIndex()).template toAdd<ValueType>() * guard;
transitions *= sourceLocationAndGuard;
// If we multiply the ranges of global variables, make sure everything stays within its bounds.
if (!globalVariablesInSomeDestination.empty()) {
@ -1124,7 +1124,9 @@ namespace storm {
// Finally treat the transient assignments.
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
if (!this->transientVariables.empty()) {
performTransientAssignments(edge.getAssignments().getTransientAssignments(), [this, &transientEdgeAssignments, &guard] (storm::jani::Assignment const& assignment) { transientEdgeAssignments[assignment.getExpressionVariable()] = guard * this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression()); } );
performTransientAssignments(edge.getAssignments().getTransientAssignments(), [this, &transientEdgeAssignments, &guard, &sourceLocationAndGuard] (storm::jani::Assignment const& assignment) {
transientEdgeAssignments[assignment.getExpressionVariable()] = sourceLocationAndGuard * this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression());
} );
}
return EdgeDd(isMarkovian, guard, guard * transitions, transientEdgeAssignments, globalVariablesInSomeDestination);

59
src/cli/cli.cpp

@ -213,22 +213,48 @@ namespace storm {
auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
if (ioSettings.isPrismOrJaniInputSet()) {
storm::storage::SymbolicModelDescription model;
std::vector<storm::jani::Property> properties;
if (ioSettings.isPrismInputSet()) {
model = storm::parseProgram(ioSettings.getPrismInputFilename());
if (ioSettings.isPrismToJaniSet()) {
model = model.toJani(true);
}
} else if (ioSettings.isJaniInputSet()) {
model = storm::parseJaniModel(ioSettings.getJaniInputFilename()).first;
auto input = storm::parseJaniModel(ioSettings.getJaniInputFilename());
model = input.first;
if (ioSettings.isJaniPropertiesSet()) {
for (auto const& propName : ioSettings.getJaniProperties()) {
STORM_LOG_THROW( input.second.count(propName) == 1, storm::exceptions::InvalidArgumentException, "No property with name " << propName << " known.");
properties.push_back(input.second.at(propName));
}
}
}
// Then proceed to parsing the properties (if given), since the model we are building may depend on the property.
uint64_t i = 0;
if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isPropertySet()) {
if (model.isJaniModel()) {
for(auto const& formula : storm::parseFormulasForJaniModel(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), model.asJaniModel())) {
properties.emplace_back(std::to_string(i), formula);
++i;
}
} else {
for(auto const& formula :storm::parseFormulasForPrismProgram(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), model.asPrismProgram())) {
properties.emplace_back(std::to_string(i), formula);
++i;
}
}
}
if(model.isJaniModel() && storm::settings::getModule<storm::settings::modules::JaniExportSettings>().isJaniFileSet()) {
if (storm::settings::getModule<storm::settings::modules::JaniExportSettings>().isExportAsStandardJaniSet()) {
storm::jani::Model normalisedModel = storm::jani::Model(model.asJaniModel());
normalisedModel.makeStandardJaniCompliant();
storm::jani::JsonExporter::toFile(normalisedModel, storm::settings::getModule<storm::settings::modules::JaniExportSettings>().getJaniFilename());
storm::jani::JsonExporter::toFile(normalisedModel, formulasInProperties(properties), storm::settings::getModule<storm::settings::modules::JaniExportSettings>().getJaniFilename());
} else {
storm::jani::JsonExporter::toFile(model.asJaniModel(), storm::settings::getModule<storm::settings::modules::JaniExportSettings>().getJaniFilename());
storm::jani::JsonExporter::toFile(model.asJaniModel(), formulasInProperties(properties), storm::settings::getModule<storm::settings::modules::JaniExportSettings>().getJaniFilename());
}
}
@ -236,42 +262,39 @@ namespace storm {
std::string constantDefinitionString = ioSettings.getConstantDefinitionString();
model = model.preprocess(constantDefinitionString);
// Then proceed to parsing the properties (if given), since the model we are building may depend on the property.
std::vector<std::shared_ptr<storm::logic::Formula const>> formulas;
if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isPropertySet()) {
if (model.isJaniModel()) {
formulas = storm::parseFormulasForJaniModel(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), model.asJaniModel());
} else {
formulas = storm::parseFormulasForPrismProgram(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), model.asPrismProgram());
}
}
if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isParametricSet()) {
#ifdef STORM_HAVE_CARL
buildAndCheckSymbolicModel<storm::RationalFunction>(model, formulas, true);
buildAndCheckSymbolicModel<storm::RationalFunction>(model, properties, true);
#else
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No parameters are supported in this build.");
#endif
} else if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isExactSet()) {
#ifdef STORM_HAVE_CARL
buildAndCheckSymbolicModel<storm::RationalNumber>(model, formulas, true);
buildAndCheckSymbolicModel<storm::RationalNumber>(model, properties, true);
#else
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No exact numbers are supported in this build.");
#endif
} else {
buildAndCheckSymbolicModel<double>(model, formulas, true);
buildAndCheckSymbolicModel<double>(model, properties, true);
}
} else if (storm::settings::getModule<storm::settings::modules::IOSettings>().isExplicitSet()) {
STORM_LOG_THROW(storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Only the sparse engine supports explicit model input.");
// If the model is given in an explicit format, we parse the properties without allowing expressions
// in formulas.
std::vector<std::shared_ptr<storm::logic::Formula const>> formulas;
std::vector<storm::jani::Property> properties;
if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isPropertySet()) {
formulas = storm::parseFormulasForExplicit(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty());
uint64_t i = 0;
for(auto const& formula : storm::parseFormulasForExplicit(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty())) {
properties.emplace_back(std::to_string(i), formula);
++i;
}
}
buildAndCheckExplicitModel<double>(formulas, true);
buildAndCheckExplicitModel<double>(properties, true);
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "No input model.");
}

144
src/cli/entrypoints.h

@ -13,15 +13,72 @@ namespace storm {
namespace cli {
template<typename ValueType>
void verifySparseModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
for (auto const& formula : formulas) {
std::cout << std::endl << "Model checking property: " << *formula << " ...";
std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySparseModel(model, formula, onlyInitialStatesRelevant));
void applyFilterFunctionAndOutput(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::modelchecker::FilterType ft) {
if(result->isQuantitative()) {
switch(ft) {
case storm::modelchecker::FilterType::VALUES:
std::cout << *result << std::endl;
return;
case storm::modelchecker::FilterType::SUM:
std::cout << result->asQuantitativeCheckResult<ValueType>().sum();
return;
case storm::modelchecker::FilterType::AVG:
std::cout << result->asQuantitativeCheckResult<ValueType>().average();
return;
case storm::modelchecker::FilterType::MIN:
std::cout << result->asQuantitativeCheckResult<ValueType>().getMin();
return;
case storm::modelchecker::FilterType::MAX:
std::cout << result->asQuantitativeCheckResult<ValueType>().getMax();
return;
case storm::modelchecker::FilterType::ARGMIN:
case storm::modelchecker::FilterType::ARGMAX:
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Outputting states is not supported");
case storm::modelchecker::FilterType::EXISTS:
case storm::modelchecker::FilterType::FORALL:
case storm::modelchecker::FilterType::COUNT:
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "FilterType only defined for qualitative results");
}
} else {
switch(ft) {
case storm::modelchecker::FilterType::VALUES:
std::cout << *result << std::endl;
return;
case storm::modelchecker::FilterType::EXISTS:
std::cout << result->asQualitativeCheckResult().existsTrue();
return;
case storm::modelchecker::FilterType::FORALL:
std::cout << result->asQualitativeCheckResult().forallTrue();
return;
case storm::modelchecker::FilterType::COUNT:
std::cout << result->asQualitativeCheckResult().count();
return;
case storm::modelchecker::FilterType::ARGMIN:
case storm::modelchecker::FilterType::ARGMAX:
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Outputting states is not supported");
case storm::modelchecker::FilterType::SUM:
case storm::modelchecker::FilterType::AVG:
case storm::modelchecker::FilterType::MIN:
case storm::modelchecker::FilterType::MAX:
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "FilterType only defined for quantitative results");
}
}
}
template<typename ValueType>
void verifySparseModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> model, std::vector<storm::jani::Property> const& properties, bool onlyInitialStatesRelevant = false) {
for (auto const& property : properties) {
std::cout << std::endl << "Model checking property: " << property << " ...";
std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySparseModel(model, property.getFilter().getFormula(), onlyInitialStatesRelevant));
if (result) {
std::cout << " done." << std::endl;
std::cout << "Result (initial states): ";
result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
std::cout << *result << std::endl;
applyFilterFunctionAndOutput<ValueType>(result, property.getFilter().getFilterType());
std::cout << std::endl;
} else {
std::cout << " skipped, because the modelling formalism is currently unsupported." << std::endl;
}
@ -30,17 +87,18 @@ namespace storm {
#ifdef STORM_HAVE_CARL
template<>
inline void verifySparseModel(std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) {
inline void verifySparseModel(std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> model, std::vector<storm::jani::Property> const& properties, bool onlyInitialStatesRelevant) {
for (auto const& formula : formulas) {
for (auto const& property : properties) {
STORM_LOG_THROW(model->getType() == storm::models::ModelType::Dtmc || model->getType() == storm::models::ModelType::Ctmc, storm::exceptions::InvalidSettingsException, "Currently parametric verification is only available for DTMCs and CTMCs.");
std::cout << std::endl << "Model checking property: " << *formula << " ...";
std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySparseModel(model, formula, onlyInitialStatesRelevant));
std::cout << std::endl << "Model checking property: " << property << " ...";
std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySparseModel(model, property.getFilter().getFormula(), onlyInitialStatesRelevant));
if (result) {
std::cout << " done." << std::endl;
std::cout << "Result (initial states): ";
result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
std::cout << *result << std::endl;
applyFilterFunctionAndOutput<storm::RationalFunction>(result, property.getFilter().getFilterType());
std::cout << std::endl;
} else {
std::cout << " skipped, because the modelling formalism is currently unsupported." << std::endl;
}
@ -53,24 +111,24 @@ namespace storm {
#endif
template<storm::dd::DdType DdType>
void verifySymbolicModelWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
void verifySymbolicModelWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const& model, std::vector<storm::jani::Property> const& formulas, bool onlyInitialStatesRelevant = false) {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Abstraction Refinement is not yet implemented.");
}
template<typename ValueType>
void verifySymbolicModelWithExplorationEngine(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
void verifySymbolicModelWithExplorationEngine(storm::storage::SymbolicModelDescription const& model, std::vector<storm::jani::Property> const& formulas, bool onlyInitialStatesRelevant = false) {
STORM_LOG_THROW(model.isPrismProgram(), storm::exceptions::InvalidSettingsException, "Exploration engine is currently only applicable to PRISM models.");
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::InvalidSettingsException, "Currently exploration-based verification is only available for DTMCs and MDPs.");
for (auto const& formula : formulas) {
std::cout << std::endl << "Model checking property: " << *formula << " ...";
for (auto const& property : formulas) {
std::cout << std::endl << "Model checking property: " << property << " ...";
bool supportFormula;
std::unique_ptr<storm::modelchecker::CheckResult> result;
if(program.getModelType() == storm::prism::Program::ModelType::DTMC) {
storm::modelchecker::SparseExplorationModelChecker<storm::models::sparse::Dtmc<ValueType>> checker(program);
storm::modelchecker::CheckTask<storm::logic::Formula> task(*formula, onlyInitialStatesRelevant);
storm::modelchecker::CheckTask<storm::logic::Formula> task(*property.getFilter().getFormula(), onlyInitialStatesRelevant);
supportFormula = checker.canHandle(task);
if (supportFormula) {
@ -78,7 +136,7 @@ namespace storm {
}
} else if(program.getModelType() == storm::prism::Program::ModelType::MDP) {
storm::modelchecker::SparseExplorationModelChecker<storm::models::sparse::Mdp<ValueType>> checker(program);
storm::modelchecker::CheckTask<storm::logic::Formula> task(*formula, onlyInitialStatesRelevant);
storm::modelchecker::CheckTask<storm::logic::Formula> task(*property.getFilter().getFormula(), onlyInitialStatesRelevant);
supportFormula = checker.canHandle(task);
if (supportFormula) {
@ -95,7 +153,8 @@ namespace storm {
if (result) {
std::cout << " done." << std::endl;
std::cout << "Result (initial states): ";
std::cout << *result << std::endl;
applyFilterFunctionAndOutput<ValueType>(result, property.getFilter().getFilterType());
std::cout << std::endl;
} else {
std::cout << " skipped, because the modelling formalism is currently unsupported." << std::endl;
}
@ -104,22 +163,23 @@ namespace storm {
#ifdef STORM_HAVE_CARL
template<>
void verifySymbolicModelWithExplorationEngine<storm::RationalFunction>(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) {
void verifySymbolicModelWithExplorationEngine<storm::RationalFunction>(storm::storage::SymbolicModelDescription const& model, std::vector<storm::jani::Property> const& formulas, bool onlyInitialStatesRelevant) {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Exploration-based verification does currently not support parametric models.");
}
#endif
template<storm::dd::DdType DdType>
void verifySymbolicModelWithHybridEngine(std::shared_ptr<storm::models::symbolic::Model<DdType>> model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
for (auto const& formula : formulas) {
std::cout << std::endl << "Model checking property: " << *formula << " ...";
std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySymbolicModelWithHybridEngine(model, formula, onlyInitialStatesRelevant));
void verifySymbolicModelWithHybridEngine(std::shared_ptr<storm::models::symbolic::Model<DdType>> model, std::vector<storm::jani::Property> const& formulas, bool onlyInitialStatesRelevant = false) {
for (auto const& property : formulas) {
std::cout << std::endl << "Model checking property: " << property << " ...";
std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySymbolicModelWithHybridEngine(model, property.getFilter().getFormula(), onlyInitialStatesRelevant));
if (result) {
std::cout << " done." << std::endl;
std::cout << "Result (initial states): ";
result->filter(storm::modelchecker::SymbolicQualitativeCheckResult<DdType>(model->getReachableStates(), model->getInitialStates()));
std::cout << *result << std::endl;
applyFilterFunctionAndOutput<double>(result, property.getFilter().getFilterType());
std::cout << std::endl;
} else {
std::cout << " skipped, because the modelling formalism is currently unsupported." << std::endl;
}
@ -127,15 +187,16 @@ namespace storm {
}
template<storm::dd::DdType DdType>
void verifySymbolicModelWithDdEngine(std::shared_ptr<storm::models::symbolic::Model<DdType>> model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
for (auto const& formula : formulas) {
std::cout << std::endl << "Model checking property: " << *formula << " ...";
std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySymbolicModelWithDdEngine(model, formula, onlyInitialStatesRelevant));
void verifySymbolicModelWithDdEngine(std::shared_ptr<storm::models::symbolic::Model<DdType>> model, std::vector<storm::jani::Property> const& formulas, bool onlyInitialStatesRelevant = false) {
for (auto const& property : formulas) {
std::cout << std::endl << "Model checking property: " << property << " ...";
std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySymbolicModelWithDdEngine(model, property.getFilter().getFormula(), onlyInitialStatesRelevant));
if (result) {
std::cout << " done." << std::endl;
std::cout << "Result (initial states): ";
result->filter(storm::modelchecker::SymbolicQualitativeCheckResult<DdType>(model->getReachableStates(), model->getInitialStates()));
std::cout << *result << std::endl;
applyFilterFunctionAndOutput<double>(result, property.getFilter().getFilterType());
std::cout << std::endl;
} else {
std::cout << " skipped, because the modelling formalism is currently unsupported." << std::endl;
}
@ -183,23 +244,24 @@ namespace storm {
}
template<storm::dd::DdType LibraryType>
void buildAndCheckSymbolicModelWithSymbolicEngine(bool hybrid, storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
void buildAndCheckSymbolicModelWithSymbolicEngine(bool hybrid, storm::storage::SymbolicModelDescription const& model, std::vector<storm::jani::Property> const& properties, bool onlyInitialStatesRelevant = false) {
// Start by building the model.
auto markovModel = buildSymbolicModel<double, LibraryType>(model, formulas);
auto markovModel = buildSymbolicModel<double, LibraryType>(model, formulasInProperties(properties));
// Print some information about the model.
markovModel->printModelInformationToStream(std::cout);
// Then select the correct engine.
if (hybrid) {
verifySymbolicModelWithHybridEngine(markovModel, formulas, onlyInitialStatesRelevant);
verifySymbolicModelWithHybridEngine(markovModel, properties, onlyInitialStatesRelevant);
} else {
verifySymbolicModelWithDdEngine(markovModel, formulas, onlyInitialStatesRelevant);
verifySymbolicModelWithDdEngine(markovModel, properties, onlyInitialStatesRelevant);
}
}
template<typename ValueType>
void buildAndCheckSymbolicModelWithSparseEngine(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
void buildAndCheckSymbolicModelWithSparseEngine(storm::storage::SymbolicModelDescription const& model, std::vector<storm::jani::Property> const& properties, bool onlyInitialStatesRelevant = false) {
auto formulas = formulasInProperties(properties);
// Start by building the model.
std::shared_ptr<storm::models::ModelBase> markovModel = buildSparseModel<ValueType>(model, formulas);
@ -215,7 +277,7 @@ namespace storm {
if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isCounterexampleSet()) {
generateCounterexamples<ValueType>(model, sparseModel, formulas);
} else {
verifySparseModel<ValueType>(sparseModel, formulas, onlyInitialStatesRelevant);
verifySparseModel<ValueType>(sparseModel, properties, onlyInitialStatesRelevant);
}
// And export if required.
@ -228,7 +290,7 @@ namespace storm {
}
template<typename ValueType>
void buildAndCheckSymbolicModel(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
void buildAndCheckSymbolicModel(storm::storage::SymbolicModelDescription const& model, std::vector<storm::jani::Property> const& formulas, bool onlyInitialStatesRelevant = false) {
if (storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::AbstractionRefinement) {
auto ddlib = storm::settings::getModule<storm::settings::modules::CoreSettings>().getDdLibraryType();
if (ddlib == storm::dd::DdType::CUDD) {
@ -256,35 +318,35 @@ namespace storm {
#ifdef STORM_HAVE_CARL
template<>
void buildAndCheckSymbolicModel<storm::RationalNumber>(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) {
void buildAndCheckSymbolicModel<storm::RationalNumber>(storm::storage::SymbolicModelDescription const& model, std::vector<storm::jani::Property> const& formulas, bool onlyInitialStatesRelevant) {
STORM_LOG_THROW(storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Cannot use this data type with an engine different than the sparse one.");
buildAndCheckSymbolicModelWithSparseEngine<storm::RationalNumber>(model, formulas, onlyInitialStatesRelevant);
}
template<>
void buildAndCheckSymbolicModel<storm::RationalFunction>(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) {
void buildAndCheckSymbolicModel<storm::RationalFunction>(storm::storage::SymbolicModelDescription const& model, std::vector<storm::jani::Property> const& formulas, bool onlyInitialStatesRelevant) {
STORM_LOG_THROW(storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Cannot use this data type with an engine different than the sparse one.");
buildAndCheckSymbolicModelWithSparseEngine<storm::RationalFunction>(model, formulas, onlyInitialStatesRelevant);
}
#endif
template<typename ValueType>
void buildAndCheckExplicitModel(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
void buildAndCheckExplicitModel(std::vector<storm::jani::Property> const& properties, bool onlyInitialStatesRelevant = false) {
storm::settings::modules::IOSettings const& settings = storm::settings::getModule<storm::settings::modules::IOSettings>();
STORM_LOG_THROW(settings.isExplicitSet(), storm::exceptions::InvalidStateException, "Unable to build explicit model without model files.");
std::shared_ptr<storm::models::ModelBase> model = buildExplicitModel<ValueType>(settings.getTransitionFilename(), settings.getLabelingFilename(), settings.isStateRewardsSet() ? boost::optional<std::string>(settings.getStateRewardsFilename()) : boost::none, settings.isTransitionRewardsSet() ? boost::optional<std::string>(settings.getTransitionRewardsFilename()) : boost::none, settings.isChoiceLabelingSet() ? boost::optional<std::string>(settings.getChoiceLabelingFilename()) : boost::none);
// Preprocess the model if needed.
BRANCH_ON_MODELTYPE(model, model, ValueType, storm::dd::DdType::CUDD, preprocessModel, formulas);
BRANCH_ON_MODELTYPE(model, model, ValueType, storm::dd::DdType::CUDD, preprocessModel, formulasInProperties(properties));
// Print some information about the model.
model->printModelInformationToStream(std::cout);
// Verify the model, if a formula was given.
if (!formulas.empty()) {
if (!properties.empty()) {
STORM_LOG_THROW(model->isSparseModel(), storm::exceptions::InvalidStateException, "Expected sparse model.");
verifySparseModel<ValueType>(model->as<storm::models::sparse::Model<ValueType>>(), formulas, onlyInitialStatesRelevant);
verifySparseModel<ValueType>(model->as<storm::models::sparse::Model<ValueType>>(), properties, onlyInitialStatesRelevant);
}
}
}

2
src/generator/JaniNextStateGenerator.cpp

@ -188,7 +188,7 @@ namespace storm {
blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression;
initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast<uint_fast64_t>(variableValue - integerVariable.lowerBound));
}
// Gather iterators to the initial locations of all the automata.
std::vector<std::set<uint64_t>::const_iterator> initialLocationsIterators;
uint64_t currentLocationVariable = 0;

36
src/generator/VariableInformation.cpp

@ -63,15 +63,19 @@ namespace storm {
}
for (auto const& variable : model.getGlobalVariables().getBooleanVariables()) {
booleanVariables.emplace_back(variable.getExpressionVariable(), totalBitOffset, true);
++totalBitOffset;
if (!variable.isTransient()) {
booleanVariables.emplace_back(variable.getExpressionVariable(), totalBitOffset, true);
++totalBitOffset;
}
}
for (auto const& variable : model.getGlobalVariables().getBoundedIntegerVariables()) {
int_fast64_t lowerBound = variable.getLowerBound().evaluateAsInt();
int_fast64_t upperBound = variable.getUpperBound().evaluateAsInt();
uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1)));
integerVariables.emplace_back(variable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth, true);
totalBitOffset += bitwidth;
if (!variable.isTransient()) {
int_fast64_t lowerBound = variable.getLowerBound().evaluateAsInt();
int_fast64_t upperBound = variable.getUpperBound().evaluateAsInt();
uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1)));
integerVariables.emplace_back(variable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth, true);
totalBitOffset += bitwidth;
}
}
for (auto const& automaton : model.getAutomata()) {
uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(automaton.getNumberOfLocations())));
@ -79,15 +83,19 @@ namespace storm {
totalBitOffset += bitwidth;
for (auto const& variable : automaton.getVariables().getBooleanVariables()) {
booleanVariables.emplace_back(variable.getExpressionVariable(), totalBitOffset);
++totalBitOffset;
if (!variable.isTransient()) {
booleanVariables.emplace_back(variable.getExpressionVariable(), totalBitOffset);
++totalBitOffset;
}
}
for (auto const& variable : automaton.getVariables().getBoundedIntegerVariables()) {
int_fast64_t lowerBound = variable.getLowerBound().evaluateAsInt();
int_fast64_t upperBound = variable.getUpperBound().evaluateAsInt();
uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1)));
integerVariables.emplace_back(variable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth);
totalBitOffset += bitwidth;
if (!variable.isTransient()) {
int_fast64_t lowerBound = variable.getLowerBound().evaluateAsInt();
int_fast64_t upperBound = variable.getUpperBound().evaluateAsInt();
uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1)));
integerVariables.emplace_back(variable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth);
totalBitOffset += bitwidth;
}
}
}

41
src/modelchecker/results/ExplicitQualitativeCheckResult.cpp

@ -70,6 +70,47 @@ namespace storm {
return *this;
}
bool ExplicitQualitativeCheckResult::existsTrue() const {
if (this->isResultForAllStates()) {
return !boost::get<vector_type>(truthValues).empty();
} else {
for (auto& element : boost::get<map_type>(truthValues)) {
if(element.second) {
return true;
}
}
return false;
}
}
bool ExplicitQualitativeCheckResult::forallTrue() const {
if (this->isResultForAllStates()) {
return boost::get<vector_type>(truthValues).full();
} else {
for (auto& element : boost::get<map_type>(truthValues)) {
if(!element.second) {
return false;
}
}
return true;
}
}
uint64_t ExplicitQualitativeCheckResult::count() const {
if (this->isResultForAllStates()) {
return boost::get<vector_type>(truthValues).getNumberOfSetBits();
} else {
uint64_t result = 0;
for (auto& element : boost::get<map_type>(truthValues)) {
if(element.second) {
++result;
}
}
return result;
}
}
bool ExplicitQualitativeCheckResult::operator[](storm::storage::sparse::state_type state) const {
if (this->isResultForAllStates()) {
return boost::get<vector_type>(truthValues).get(state);

6
src/modelchecker/results/ExplicitQualitativeCheckResult.h

@ -47,6 +47,12 @@ namespace storm {
vector_type const& getTruthValuesVector() const;
map_type const& getTruthValuesVectorMap() const;
virtual bool existsTrue() const override;
virtual bool forallTrue() const override;
virtual uint64_t count() const override;
virtual std::ostream& writeToStream(std::ostream& out) const override;
virtual void filter(QualitativeCheckResult const& filter) override;

59
src/modelchecker/results/ExplicitQuantitativeCheckResult.cpp

@ -3,6 +3,7 @@
#include "src/modelchecker/results/ExplicitQualitativeCheckResult.h"
#include "src/storage/BitVector.h"
#include "src/utility/macros.h"
#include "src/utility/constants.h"
#include "src/utility/vector.h"
#include "src/exceptions/InvalidOperationException.h"
#include "src/exceptions/InvalidAccessException.h"
@ -81,6 +82,64 @@ namespace storm {
}
}
template<typename ValueType>
ValueType ExplicitQuantitativeCheckResult<ValueType>::getMin() const {
STORM_LOG_THROW(!values.empty(),storm::exceptions::InvalidOperationException, "Minimum of empty set is not defined");
if (this->isResultForAllStates()) {
return storm::utility::minimum(boost::get<vector_type>(values));
} else {
return storm::utility::minimum(boost::get<map_type>(values));
}
}
template<typename ValueType>
ValueType ExplicitQuantitativeCheckResult<ValueType>::getMax() const {
STORM_LOG_THROW(!values.empty(),storm::exceptions::InvalidOperationException, "Minimum of empty set is not defined");
if (this->isResultForAllStates()) {
return storm::utility::maximum(boost::get<vector_type>(values));
} else {
return storm::utility::maximum(boost::get<map_type>(values));
}
}
template<typename ValueType>
ValueType ExplicitQuantitativeCheckResult<ValueType>::sum() const {
STORM_LOG_THROW(!values.empty(),storm::exceptions::InvalidOperationException, "Minimum of empty set is not defined");
ValueType sum = storm::utility::zero<ValueType>();
if (this->isResultForAllStates()) {
for (auto& element : boost::get<vector_type>(values)) {
sum += element;
}
} else {
for (auto& element : boost::get<map_type>(values)) {
sum += element.second;
}
}
return sum;
}
template<typename ValueType>
ValueType ExplicitQuantitativeCheckResult<ValueType>::average() const {
STORM_LOG_THROW(!values.empty(),storm::exceptions::InvalidOperationException, "Minimum of empty set is not defined");
ValueType sum = storm::utility::zero<ValueType>();
if (this->isResultForAllStates()) {
for (auto& element : boost::get<vector_type>(values)) {
sum += element;
}
return sum / boost::get<vector_type>(values).size();
} else {
for (auto& element : boost::get<map_type>(values)) {
sum += element.second;
}
return sum / boost::get<map_type>(values).size();
}
}
template<typename ValueType>
bool ExplicitQuantitativeCheckResult<ValueType>::hasScheduler() const {
return static_cast<bool>(scheduler);

6
src/modelchecker/results/ExplicitQuantitativeCheckResult.h

@ -53,6 +53,12 @@ namespace storm {
virtual void oneMinus() override;
virtual ValueType getMin() const override;
virtual ValueType getMax() const override;
virtual ValueType average() const override;
virtual ValueType sum() const override;
bool hasScheduler() const;
void setScheduler(std::unique_ptr<storm::storage::Scheduler>&& scheduler);
storm::storage::Scheduler const& getScheduler() const;

32
src/modelchecker/results/FilterType.cpp

@ -0,0 +1,32 @@
#include "FilterType.h"
namespace storm {
namespace modelchecker {
std::string toString(FilterType ft) {
switch(ft) {
case FilterType::ARGMAX:
return "the argmax";
case FilterType::ARGMIN:
return "the argmin";
case FilterType::AVG:
return "the average";
case FilterType::COUNT:
return "the number of";
case FilterType::EXISTS:
return "whether there exists a state in";
case FilterType::FORALL:
return "whether for all states in";
case FilterType::MAX:
return "the maximum";
case FilterType::MIN:
return "the minumum";
case FilterType::SUM:
return "the sum";
case FilterType::VALUES:
return "the values";
}
}
}
}

14
src/modelchecker/results/FilterType.h

@ -0,0 +1,14 @@
#pragma once
#include <string>
namespace storm {
namespace modelchecker {
enum class StateFilter { ARGMIN, ARGMAX };
enum class FilterType { MIN, MAX, SUM, AVG, COUNT, FORALL, EXISTS, ARGMIN, ARGMAX, VALUES };
std::string toString(FilterType);
bool isStateFilter(FilterType);
}
}

14
src/modelchecker/results/HybridQuantitativeCheckResult.cpp

@ -5,9 +5,12 @@
#include "src/storage/dd/cudd/CuddAddIterator.h"
#include "src/exceptions/InvalidOperationException.h"
#include "src/exceptions/NotImplementedException.h"
#include "src/utility/macros.h"
#include "src/utility/constants.h"
namespace storm {
namespace modelchecker {
template<storm::dd::DdType Type, typename ValueType>
@ -164,6 +167,16 @@ namespace storm {
return max;
}
template<storm::dd::DdType Type, typename ValueType>
ValueType HybridQuantitativeCheckResult<Type, ValueType>::sum() const {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Sum not implemented for hybrid results");
}
template<storm::dd::DdType Type, typename ValueType>
ValueType HybridQuantitativeCheckResult<Type, ValueType>::average() const {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Average not implemented for hybrid results");
}
template<storm::dd::DdType Type, typename ValueType>
void HybridQuantitativeCheckResult<Type, ValueType>::oneMinus() {
storm::dd::Add<Type> one = symbolicValues.getDdManager().template getAddOne<ValueType>();
@ -175,6 +188,7 @@ namespace storm {
}
}
// Explicitly instantiate the class.
template class HybridQuantitativeCheckResult<storm::dd::DdType::CUDD>;
template class HybridQuantitativeCheckResult<storm::dd::DdType::Sylvan>;

9
src/modelchecker/results/HybridQuantitativeCheckResult.h

@ -46,9 +46,14 @@ namespace storm {
virtual void filter(QualitativeCheckResult const& filter) override;
virtual ValueType getMin() const;
virtual ValueType getMin() const override;
virtual ValueType getMax() const;
virtual ValueType getMax() const override;
virtual ValueType sum() const override;
virtual ValueType average() const override;
virtual void oneMinus() override;

4
src/modelchecker/results/QualitativeCheckResult.h

@ -12,6 +12,10 @@ namespace storm {
virtual QualitativeCheckResult& operator|=(QualitativeCheckResult const& other);
virtual void complement();
virtual bool existsTrue() const = 0;
virtual bool forallTrue() const = 0;
virtual uint64_t count() const = 0;
virtual bool isQualitative() const override;
};
}

12
src/modelchecker/results/QuantitativeCheckResult.h

@ -1,5 +1,4 @@
#ifndef STORM_MODELCHECKER_QUANTITATIVECHECKRESULT_H_
#define STORM_MODELCHECKER_QUANTITATIVECHECKRESULT_H_
#pragma once
#include "src/modelchecker/results/CheckResult.h"
@ -14,9 +13,16 @@ namespace storm {
virtual void oneMinus() = 0;
virtual ValueType getMin() const = 0;
virtual ValueType getMax() const = 0;
virtual ValueType average() const = 0;
virtual ValueType sum() const = 0;
virtual bool isQuantitative() const override;
};
}
}
#endif /* STORM_MODELCHECKER_QUANTITATIVECHECKRESULT_H_ */

17
src/modelchecker/results/SymbolicQualitativeCheckResult.cpp

@ -3,6 +3,8 @@
#include "src/utility/macros.h"
#include "src/exceptions/InvalidOperationException.h"
#include "src/exceptions/NotImplementedException.h"
namespace storm {
namespace modelchecker {
template <storm::dd::DdType Type>
@ -49,6 +51,21 @@ namespace storm {
return truthValues;
}
template <storm::dd::DdType Type>
bool SymbolicQualitativeCheckResult<Type>::existsTrue() const {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Exists not implemented for symbolic results");
}
template <storm::dd::DdType Type>
bool SymbolicQualitativeCheckResult<Type>::forallTrue() const {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Forall not implemented for symbolic results");
}
template <storm::dd::DdType Type>
uint64_t SymbolicQualitativeCheckResult<Type>::count() const {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Count not implemented for symbolic results");
}
template <storm::dd::DdType Type>
std::ostream& SymbolicQualitativeCheckResult<Type>::writeToStream(std::ostream& out) const {
if (this->truthValues.isZero()) {

6
src/modelchecker/results/SymbolicQualitativeCheckResult.h

@ -30,6 +30,12 @@ namespace storm {
virtual QualitativeCheckResult& operator|=(QualitativeCheckResult const& other) override;
virtual void complement() override;
virtual bool existsTrue() const override;
virtual bool forallTrue() const override;
virtual uint64_t count() const override;
storm::dd::Bdd<Type> const& getTruthValuesVector() const;
virtual std::ostream& writeToStream(std::ostream& out) const override;

12
src/modelchecker/results/SymbolicQuantitativeCheckResult.cpp

@ -5,6 +5,8 @@
#include "src/storage/dd/cudd/CuddAddIterator.h"
#include "src/exceptions/InvalidOperationException.h"
#include "src/exceptions/NotImplementedException.h"
#include "src/utility/macros.h"
#include "src/utility/constants.h"
@ -89,6 +91,16 @@ namespace storm {
return this->values.getMax();
}
template<storm::dd::DdType Type, typename ValueType>
ValueType SymbolicQuantitativeCheckResult<Type, ValueType>::average() const {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Average not implemented for symbolic results");
}
template<storm::dd::DdType Type, typename ValueType>
ValueType SymbolicQuantitativeCheckResult<Type, ValueType>::sum() const {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Sum not implemented for symbolic results");
}
template<storm::dd::DdType Type, typename ValueType>
void SymbolicQuantitativeCheckResult<Type, ValueType>::oneMinus() {
storm::dd::Add<Type> one = values.getDdManager().template getAddOne<ValueType>();

7
src/modelchecker/results/SymbolicQuantitativeCheckResult.h

@ -35,9 +35,12 @@ namespace storm {
virtual void filter(QualitativeCheckResult const& filter) override;
virtual ValueType getMin() const;
virtual ValueType getMin() const override;
virtual ValueType getMax() const;
virtual ValueType getMax() const override;
virtual ValueType average() const override;
virtual ValueType sum() const override;
virtual void oneMinus() override;

23
src/parser/CSVParser.cpp

@ -0,0 +1,23 @@
#include "src/parser/CSVParser.h"
#include <boost/any.hpp>
#include <boost/algorithm/string.hpp>
#include "src/utility/macros.h"
#include "src/exceptions/InvalidArgumentException.h"
namespace storm {
namespace parser {
std::vector<std::string> parseCommaSeperatedValues(std::string const& input) {
std::vector<std::string> values;
std::vector<std::string> definitions;
boost::split(definitions, input, boost::is_any_of(","));
for (auto& definition : definitions) {
boost::trim(definition);
values.push_back(definition);
}
return values;
}
}
}

12
src/parser/CSVParser.h

@ -0,0 +1,12 @@
#include <vector>
#include <string>
namespace storm {
namespace parser {
/**
* Given a string seperated by commas, returns the values.
*/
std::vector<std::string> parseCommaSeperatedValues(std::string const& input);
}
}

288
src/parser/JaniParser.cpp

@ -5,9 +5,12 @@
#include "src/storage/jani/ParallelComposition.h"
#include "src/exceptions/FileIoException.h"
#include "src/exceptions/InvalidJaniException.h"
#include "src/exceptions/NotSupportedException.h"
#include "src/exceptions/NotImplementedException.h"
#include "src/storage/jani/ModelType.h"
#include "src/modelchecker/results/FilterType.h"
#include <iostream>
#include <sstream>
@ -49,7 +52,7 @@ namespace storm {
}
std::pair<storm::jani::Model, std::vector<storm::jani::Property>> JaniParser::parse(std::string const& path) {
std::pair<storm::jani::Model, std::map<std::string, storm::jani::Property>> JaniParser::parse(std::string const& path) {
JaniParser parser;
parser.readFile(path);
return parser.parseModel();
@ -75,7 +78,7 @@ namespace storm {
file.close();
}
std::pair<storm::jani::Model, std::vector<storm::jani::Property>> JaniParser::parseModel(bool parseProperties) {
std::pair<storm::jani::Model, std::map<std::string, storm::jani::Property>> JaniParser::parseModel(bool parseProperties) {
//jani-version
STORM_LOG_THROW(parsedStructure.count("jani-version") == 1, storm::exceptions::InvalidJaniException, "Jani-version must be given exactly once.");
uint64_t version = getUnsignedInt(parsedStructure.at("jani-version"), "jani version");
@ -110,21 +113,185 @@ namespace storm {
for (auto const& automataEntry : parsedStructure.at("automata")) {
model.addAutomaton(parseAutomaton(automataEntry, model));
}
STORM_LOG_THROW(parsedStructure.count("restrict-initial") < 2, storm::exceptions::InvalidJaniException, "Model has multiple initial value restrictions");
storm::expressions::Expression initialValueRestriction = expressionManager->boolean(true);
if(parsedStructure.count("restrict-initial") > 0) {
STORM_LOG_THROW(parsedStructure.at("restrict-initial").count("exp") == 1, storm::exceptions::InvalidJaniException, "Model needs an expression inside the initial restricion");
initialValueRestriction = parseExpression(parsedStructure.at("restrict-initial").at("exp"), "Initial value restriction for automaton " + name);
}
model.setInitialStatesRestriction(initialValueRestriction);
STORM_LOG_THROW(parsedStructure.count("system") == 1, storm::exceptions::InvalidJaniException, "Exactly one system description must be given");
std::shared_ptr<storm::jani::Composition> composition = parseComposition(parsedStructure.at("system"));
model.setSystemComposition(composition);
STORM_LOG_THROW(parsedStructure.count("properties") <= 1, storm::exceptions::InvalidJaniException, "At most one list of properties can be given");
PropertyVector properties;
std::map<std::string, storm::jani::Property> properties;
if (parseProperties && parsedStructure.count("properties") == 1) {
STORM_LOG_THROW(parsedStructure.at("properties").is_array(), storm::exceptions::InvalidJaniException, "Properties should be an array");
for(auto const& propertyEntry : parsedStructure.at("properties")) {
properties.push_back(this->parseProperty(propertyEntry));
try {
auto prop = this->parseProperty(propertyEntry);
properties.emplace(prop.getName(), prop);
} catch (storm::exceptions::NotSupportedException const& ex) {
STORM_LOG_WARN("Cannot handle property " << ex.what());
} catch (storm::exceptions::NotImplementedException const& ex) {
STORM_LOG_WARN("Cannot handle property " << ex.what());
}
}
}
return {model, properties};
}
std::vector<std::shared_ptr<storm::logic::Formula const>> JaniParser::parseUnaryFormulaArgument(json const& propertyStructure, std::string const& opstring, std::string const& context) {
STORM_LOG_THROW(propertyStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting operand for operator " << opstring << " in " << context);
return { parseFormula(propertyStructure.at("exp"), "Operand of operator " + opstring) };
}
std::vector<std::shared_ptr<storm::logic::Formula const>> JaniParser::parseBinaryFormulaArguments(json const& propertyStructure, std::string const& opstring, std::string const& context) {
STORM_LOG_THROW(propertyStructure.count("left") == 1, storm::exceptions::InvalidJaniException, "Expecting left operand for operator " << opstring << " in " << context);
STORM_LOG_THROW(propertyStructure.count("right") == 1, storm::exceptions::InvalidJaniException, "Expecting right operand for operator " << opstring << " in " << context);
return { parseFormula(propertyStructure.at("left"), "Operand of operator " + opstring), parseFormula(propertyStructure.at("right"), "Operand of operator " + opstring) };
}
storm::jani::PropertyInterval JaniParser::parsePropertyInterval(json const& piStructure) {
storm::jani::PropertyInterval pi;
if (piStructure.count("lower") > 0) {
pi.lowerBound = parseExpression(piStructure.at("lower"), "Lower bound for property interval");
// TODO substitute constants.
STORM_LOG_THROW(!pi.lowerBound.containsVariables(), storm::exceptions::NotSupportedException, "Only constant expressions are supported as lower bounds");
}
if (piStructure.count("lower-exclusive") > 0) {
STORM_LOG_THROW(pi.lowerBound.isInitialized(), storm::exceptions::InvalidJaniException, "Lower-exclusive can only be set if a lower bound is present");
pi.lowerBoundStrict = piStructure.at("lower-exclusive");
}
if (piStructure.count("upper") > 0) {
pi.upperBound = parseExpression(piStructure.at("upper"), "Upper bound for property interval");
// TODO substitute constants.
STORM_LOG_THROW(!pi.upperBound.containsVariables(), storm::exceptions::NotSupportedException, "Only constant expressions are supported as upper bounds");
}
if (piStructure.count("upper-exclusive") > 0) {
STORM_LOG_THROW(pi.lowerBound.isInitialized(), storm::exceptions::InvalidJaniException, "Lower-exclusive can only be set if a lower bound is present");
pi.lowerBoundStrict = piStructure.at("upper-exclusive");
}
STORM_LOG_THROW(pi.lowerBound.isInitialized() || pi.upperBound.isInitialized(), storm::exceptions::InvalidJaniException, "Bounded operators must be bounded");
return pi;
}
std::shared_ptr<storm::logic::Formula const> JaniParser::parseFormula(json const& propertyStructure, std::string const& context, boost::optional<storm::logic::Bound<storm::RationalNumber>> bound) {
storm::expressions::Expression expr = parseExpression(propertyStructure, "expression in property", {}, true);
if(expr.isInitialized()) {
assert(bound == boost::none);
return std::make_shared<storm::logic::AtomicExpressionFormula>(expr);
} else if(propertyStructure.count("op") == 1) {
std::string opString = getString(propertyStructure.at("op"), "Operation description");
if(opString == "Pmin" || opString == "Pmax") {
std::vector<std::shared_ptr<storm::logic::Formula const>> args = parseUnaryFormulaArgument(propertyStructure, opString, "");
assert(args.size() == 1);
storm::logic::OperatorInformation opInfo;
opInfo.optimalityType = opString == "Pmin" ? storm::solver::OptimizationDirection::Minimize : storm::solver::OptimizationDirection::Maximize;
opInfo.bound = bound;
return std::make_shared<storm::logic::ProbabilityOperatorFormula>(args[0], opInfo);
} else if (opString == "" || opString == "") {
assert(bound == boost::none);
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Forall and Exists are currently not supported");
} else if (opString == "Emin" || opString == "Emax") {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Emin and Emax are currently not supported");
} else if (opString == "Smin" || opString == "Smax") {
std::vector<std::shared_ptr<storm::logic::Formula const>> args = parseUnaryFormulaArgument(propertyStructure, opString, "");
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Smin and Smax are currently not supported");
} else if (opString == "U") {
assert(bound == boost::none);
std::vector<std::shared_ptr<storm::logic::Formula const>> args = parseBinaryFormulaArguments(propertyStructure, opString, "");
if (propertyStructure.count("step-bounds") > 0) {
storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("step-bounds"));
STORM_LOG_THROW(pi.hasUpperBound(), storm::exceptions::NotSupportedException, "Storm only supports step-bounded until with an upper bound");
if(pi.hasLowerBound()) {
STORM_LOG_THROW(pi.lowerBound.evaluateAsInt() == 0, storm::exceptions::NotSupportedException, "Storm only supports step-bounded until without a (non-trivial) lower-bound");
}
int64_t upperBound = pi.upperBound.evaluateAsInt();
if(pi.upperBoundStrict) {
upperBound--;
}
STORM_LOG_THROW(upperBound >= 0, storm::exceptions::InvalidJaniException, "Step-bounds cannot be negative");
return std::make_shared<storm::logic::BoundedUntilFormula const>(args[0], args[1], upperBound);
} else if (propertyStructure.count("time-bounds") > 0) {
storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("time-bounds"));
STORM_LOG_THROW(pi.hasUpperBound(), storm::exceptions::NotSupportedException, "Storm only supports time-bounded until with an upper bound.");
double lowerBound = 0.0;
if(pi.hasLowerBound()) {
lowerBound = pi.lowerBound.evaluateAsDouble();
}
double upperBound = pi.upperBound.evaluateAsDouble();
STORM_LOG_THROW(lowerBound >= 0, storm::exceptions::InvalidJaniException, "(Lower) time-bounds cannot be negative");
STORM_LOG_THROW(upperBound >= 0, storm::exceptions::InvalidJaniException, "(Upper) time-bounds cannot be negative");
return std::make_shared<storm::logic::BoundedUntilFormula const>(args[0], args[1], upperBound);
} else if (propertyStructure.count("reward-bounds") > 0 ) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Reward bounded properties are not supported by Storm");
}
if (args[0]->isTrueFormula()) {
return std::make_shared<storm::logic::EventuallyFormula const>(args[1]);
} else {
return std::make_shared<storm::logic::UntilFormula const>(args[0], args[1]);
}
} else if (opString == "W") {
assert(bound == boost::none);
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Weak until is not supported");
} else if (opString == "" || opString == "") {
assert(bound == boost::none);
std::vector<std::shared_ptr<storm::logic::Formula const>> args = parseBinaryFormulaArguments(propertyStructure, opString, "");
assert(args.size() == 2);
storm::logic::BinaryBooleanStateFormula::OperatorType oper = opString == "" ? storm::logic::BinaryBooleanStateFormula::OperatorType::And : storm::logic::BinaryBooleanStateFormula::OperatorType::Or;
return std::make_shared<storm::logic::BinaryBooleanStateFormula const>(oper, args[0], args[1]);
} else if (opString == "¬") {
assert(bound == boost::none);
std::vector<std::shared_ptr<storm::logic::Formula const>> args = parseUnaryFormulaArgument(propertyStructure, opString, "");
assert(args.size() == 1);
return std::make_shared<storm::logic::UnaryBooleanStateFormula const>(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, args[0]);
} else if (opString == "" || opString == "" || opString == "<" || opString == ">") {
assert(bound == boost::none);
storm::logic::ComparisonType ct;
if(opString == "") {
ct = storm::logic::ComparisonType::GreaterEqual;
} else if (opString == "") {
ct = storm::logic::ComparisonType::LessEqual;
} else if (opString == "<") {
ct = storm::logic::ComparisonType::Less;
} else if (opString == ">") {
ct = storm::logic::ComparisonType::Greater;
}
if (propertyStructure.at("left").count("op") > 0 && (propertyStructure.at("left").at("op") == "Pmin" || propertyStructure.at("left").at("op") == "Pmax" || propertyStructure.at("left").at("op") == "Emin" || propertyStructure.at("left").at("op") == "Emax" || propertyStructure.at("left").at("op") == "Smin" || propertyStructure.at("left").at("op") == "Smax")) {
auto expr = parseExpression(propertyStructure.at("right"), "Threshold for operator " + propertyStructure.at("left").at("op").get<std::string>());
STORM_LOG_THROW(expr.getVariables().empty(), storm::exceptions::NotSupportedException, "Only constant thresholds supported");
// TODO evaluate this expression directly as rational number
return parseFormula(propertyStructure.at("left"), "", storm::logic::Bound<storm::RationalNumber>(ct, storm::utility::convertNumber<storm::RationalNumber>(expr.evaluateAsDouble())));
} else if(propertyStructure.at("right").count("op") > 0 && (propertyStructure.at("right").at("op") == "Pmin" || propertyStructure.at("right").at("op") == "Pmax" || propertyStructure.at("right").at("op") == "Emin" || propertyStructure.at("right").at("op") == "Emax" || propertyStructure.at("right").at("op") == "Smin" || propertyStructure.at("right").at("op") == "Smax")) {
auto expr = parseExpression(propertyStructure.at("left"), "Threshold for operator " + propertyStructure.at("right").at("op").get<std::string>());
STORM_LOG_THROW(expr.getVariables().empty(), storm::exceptions::NotSupportedException, "Only constant thresholds supported");
// TODO evaluate this expression directly as rational number
return parseFormula(propertyStructure.at("right"), "", storm::logic::Bound<storm::RationalNumber>(ct, storm::utility::convertNumber<storm::RationalNumber>(expr.evaluateAsDouble())));
} else {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No complex comparisons are allowed.");
}
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown operator " << opString);
}
}
}
storm::jani::Property JaniParser::parseProperty(json const& propertyStructure) {
STORM_LOG_THROW(propertyStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Property must have a name");
// TODO check unique name
@ -133,8 +300,46 @@ namespace storm {
if (propertyStructure.count("comment") > 0) {
comment = getString(propertyStructure.at("comment"), "comment for property named '" + name + "'.");
}
STORM_LOG_THROW(propertyStructure.count("expression") == 1, storm::exceptions::InvalidJaniException, "Property must have an expression");
// Parse filter expression.
json const& expressionStructure = propertyStructure.at("expression");
STORM_LOG_THROW(expressionStructure.count("op") == 1, storm::exceptions::InvalidJaniException, "Expression in property must have an operation description");
STORM_LOG_THROW(expressionStructure.at("op") == "filter", storm::exceptions::InvalidJaniException, "Top level operation of a property must be a filter");
STORM_LOG_THROW(expressionStructure.count("fun") == 1, storm::exceptions::InvalidJaniException, "Filter must have a function descritpion");
std::string funDescr = getString(expressionStructure.at("fun"), "Filter function in property named " + name);
storm::modelchecker::FilterType ft;
if (funDescr == "min") {
ft = storm::modelchecker::FilterType::MIN;
} else if (funDescr == "max") {
ft = storm::modelchecker::FilterType::MAX;
} else if (funDescr == "sum") {
ft = storm::modelchecker::FilterType::SUM;
} else if (funDescr == "avg") {
ft = storm::modelchecker::FilterType::AVG;
} else if (funDescr == "count") {
ft = storm::modelchecker::FilterType::COUNT;
} else if (funDescr == "") {
ft = storm::modelchecker::FilterType::FORALL;
} else if (funDescr == "") {
ft = storm::modelchecker::FilterType::EXISTS;
} else if (funDescr == "argmin") {
ft = storm::modelchecker::FilterType::ARGMIN;
} else if (funDescr == "argmax") {
ft = storm::modelchecker::FilterType::ARGMAX;
} else if (funDescr == "values") {
ft = storm::modelchecker::FilterType::VALUES;
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown filter description " << funDescr << " in property named " << name);
}
STORM_LOG_THROW(expressionStructure.count("states") == 1, storm::exceptions::InvalidJaniException, "Filter must have a states description");
STORM_LOG_THROW(expressionStructure.at("states").count("op") > 0, storm::exceptions::NotImplementedException, "We only support properties where the filter has initial states");
std::string statesDescr = getString(expressionStructure.at("states").at("op"), "Filtered states in property named " + name);
STORM_LOG_THROW(statesDescr == "initial", storm::exceptions::NotImplementedException, "Only initial states are allowed as set of states we are interested in.");
STORM_LOG_THROW(expressionStructure.count("values") == 1, storm::exceptions::InvalidJaniException, "Values as input for a filter must be given");
auto formula = parseFormula(expressionStructure.at("values"), "Values of property " + name);
return storm::jani::Property(name, storm::jani::FilterExpression(formula, ft), comment);
}
std::shared_ptr<storm::jani::Constant> JaniParser::parseConstant(json const& constantStructure, std::string const& scopeDescription) {
@ -229,7 +434,6 @@ namespace storm {
boost::optional<storm::expressions::Expression> initVal;
if(variableStructure.at("type").is_string()) {
if(variableStructure.at("type") == "real") {
expressionManager->declareRationalVariable(name);
if(initvalcount == 1) {
if(variableStructure.at("initial-value").is_null()) {
initVal = expressionManager->rational(defaultRationalInitialValue);
@ -240,7 +444,8 @@ namespace storm {
return std::make_shared<storm::jani::RealVariable>(name, expressionManager->declareRationalVariable(exprManagerName), initVal.get(), transientVar);
}
return std::make_shared<storm::jani::RealVariable>(name, expressionManager->declareRationalVariable(exprManagerName), transientVar);
assert(!transientVar);
return std::make_shared<storm::jani::RealVariable>(name, expressionManager->declareRationalVariable(exprManagerName));
} else if(variableStructure.at("type") == "bool") {
if(initvalcount == 1) {
if(variableStructure.at("initial-value").is_null()) {
@ -251,7 +456,8 @@ namespace storm {
}
return std::make_shared<storm::jani::BooleanVariable>(name, expressionManager->declareBooleanVariable(exprManagerName), initVal.get(), transientVar);
}
return std::make_shared<storm::jani::BooleanVariable>(name, expressionManager->declareBooleanVariable(exprManagerName), transientVar);
assert(!transientVar);
return std::make_shared<storm::jani::BooleanVariable>(name, expressionManager->declareBooleanVariable(exprManagerName));
} else if(variableStructure.at("type") == "int") {
if(initvalcount == 1) {
if(variableStructure.at("initial-value").is_null()) {
@ -316,14 +522,14 @@ namespace storm {
STORM_LOG_THROW(expected == actual, storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects " << expected << " arguments, but got " << actual << " in " << errorInfo << ".");
}
std::vector<storm::expressions::Expression> JaniParser::parseUnaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars) {
storm::expressions::Expression left = parseExpression(expressionDecl.at("exp"), "Left argument of operator " + opstring + " in " + scopeDescription, localVars);
std::vector<storm::expressions::Expression> JaniParser::parseUnaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars, bool returnNoneInitializedOnUnknownOperator) {
storm::expressions::Expression left = parseExpression(expressionDecl.at("exp"), "Argument of operator " + opstring + " in " + scopeDescription, localVars,returnNoneInitializedOnUnknownOperator);
return {left};
}
std::vector<storm::expressions::Expression> JaniParser::parseBinaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars) {
storm::expressions::Expression left = parseExpression(expressionDecl.at("left"), "Left argument of operator " + opstring + " in " + scopeDescription, localVars);
storm::expressions::Expression right = parseExpression(expressionDecl.at("right"), "Right argument of operator " + opstring + " in " + scopeDescription, localVars);
std::vector<storm::expressions::Expression> JaniParser::parseBinaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars, bool returnNoneInitializedOnUnknownOperator) {
storm::expressions::Expression left = parseExpression(expressionDecl.at("left"), "Left argument of operator " + opstring + " in " + scopeDescription, localVars, returnNoneInitializedOnUnknownOperator);
storm::expressions::Expression right = parseExpression(expressionDecl.at("right"), "Right argument of operator " + opstring + " in " + scopeDescription, localVars, returnNoneInitializedOnUnknownOperator);
return {left, right};
}
/**
@ -359,7 +565,7 @@ namespace storm {
}
}
storm::expressions::Expression JaniParser::parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars) {
storm::expressions::Expression JaniParser::parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars, bool returnNoneInitializedOnUnknownOperator) {
if(expressionStructure.is_boolean()) {
if(expressionStructure.get<bool>()) {
return expressionManager->boolean(true);
@ -382,31 +588,50 @@ namespace storm {
if(expressionStructure.count("op") == 1) {
std::string opstring = getString(expressionStructure.at("op"), scopeDescription);
std::vector<storm::expressions::Expression> arguments = {};
if(opstring == "?:") {
if(opstring == "ite") {
STORM_LOG_THROW(expressionStructure.count("if") == 1, storm::exceptions::InvalidJaniException, "If operator required");
STORM_LOG_THROW(expressionStructure.count("else") == 1, storm::exceptions::InvalidJaniException, "Else operator required");
STORM_LOG_THROW(expressionStructure.count("then") == 1, storm::exceptions::InvalidJaniException, "If operator required");
arguments.push_back(parseExpression(expressionStructure.at("if"), "if-formula in " + scopeDescription));
arguments.push_back(parseExpression(expressionStructure.at("then"), "then-formula in " + scopeDescription));
arguments.push_back(parseExpression(expressionStructure.at("else"), "else-formula in " + scopeDescription));
ensureNumberOfArguments(3, arguments.size(), opstring, scopeDescription);
assert(arguments.size() == 3);
ensureBooleanType(arguments[0], opstring, 0, scopeDescription);
return storm::expressions::ite(arguments[0], arguments[1], arguments[2]);
} else if (opstring == "") {
arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars);
arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars, returnNoneInitializedOnUnknownOperator);
assert(arguments.size() == 2);
if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) {
return storm::expressions::Expression();
}
ensureBooleanType(arguments[0], opstring, 0, scopeDescription);
ensureBooleanType(arguments[1], opstring, 1, scopeDescription);
return arguments[0] || arguments[1];
} else if (opstring == "") {
arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars);
arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars, returnNoneInitializedOnUnknownOperator);
assert(arguments.size() == 2);
if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) {
return storm::expressions::Expression();
}
ensureBooleanType(arguments[0], opstring, 0, scopeDescription);
ensureBooleanType(arguments[1], opstring, 1, scopeDescription);
return arguments[0] && arguments[1];
} else if (opstring == "") {
arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars);
arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars, returnNoneInitializedOnUnknownOperator);
assert(arguments.size() == 2);
if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) {
return storm::expressions::Expression();
}
ensureBooleanType(arguments[0], opstring, 0, scopeDescription);
ensureBooleanType(arguments[0], opstring, 1, scopeDescription);
ensureBooleanType(arguments[1], opstring, 1, scopeDescription);
return (!arguments[0]) || arguments[1];
} else if (opstring == "¬") {
arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars);
arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars, returnNoneInitializedOnUnknownOperator);
assert(arguments.size() == 1);
if(!arguments[0].isInitialized()) {
return storm::expressions::Expression();
}
ensureBooleanType(arguments[0], opstring, 0, scopeDescription);
return !arguments[0];
} else if (opstring == "=") {
@ -430,26 +655,38 @@ namespace storm {
return arguments[0] != arguments[1];
}
} else if (opstring == "<") {
arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars);
arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars, returnNoneInitializedOnUnknownOperator);
assert(arguments.size() == 2);
if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) {
return storm::expressions::Expression();
}
ensureNumericalType(arguments[0], opstring, 0, scopeDescription);
ensureNumericalType(arguments[1], opstring, 1, scopeDescription);
return arguments[0] < arguments[1];
} else if (opstring == "") {
arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars);
arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars, returnNoneInitializedOnUnknownOperator);
assert(arguments.size() == 2);
if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) {
return storm::expressions::Expression();
}
ensureNumericalType(arguments[0], opstring, 0, scopeDescription);
ensureNumericalType(arguments[1], opstring, 1, scopeDescription);
return arguments[0] <= arguments[1];
} else if (opstring == ">") {
arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars);
arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars, returnNoneInitializedOnUnknownOperator);
assert(arguments.size() == 2);
if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) {
return storm::expressions::Expression();
}
ensureNumericalType(arguments[0], opstring, 0, scopeDescription);
ensureNumericalType(arguments[1], opstring, 1, scopeDescription);
return arguments[0] > arguments[1];
} else if (opstring == "") {
arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars);
arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, localVars, returnNoneInitializedOnUnknownOperator);
assert(arguments.size() == 2);
if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) {
return storm::expressions::Expression();
}
ensureNumericalType(arguments[0], opstring, 0, scopeDescription);
ensureNumericalType(arguments[1], opstring, 1, scopeDescription);
return arguments[0] >= arguments[1];
@ -551,6 +788,9 @@ namespace storm {
STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Opstring " + opstring + " is not supported by storm");
} else {
if(returnNoneInitializedOnUnknownOperator) {
return storm::expressions::Expression();
}
STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown operator " << opstring << " in " << scopeDescription << ".");
}
}

25
src/parser/JaniParser.h

@ -1,9 +1,11 @@
#pragma once
#include <src/storage/jani/Constant.h>
#include <src/logic/Formula.h>
#include "src/logic/Formula.h"
#include "src/logic/Bound.h"
#include "src/exceptions/FileIoException.h"
#include "src/storage/expressions/ExpressionManager.h"
// JSON parser
#include "json.hpp"
@ -16,6 +18,7 @@ namespace storm {
class Variable;
class Composition;
class Property;
class PropertyInterval;
}
@ -33,16 +36,16 @@ namespace storm {
JaniParser() : expressionManager(new storm::expressions::ExpressionManager()) {}
JaniParser(std::string const& jsonstring);
static std::pair<storm::jani::Model, PropertyVector> parse(std::string const& path);
static std::pair<storm::jani::Model, std::map<std::string, storm::jani::Property>> parse(std::string const& path);
protected:
void readFile(std::string const& path);
std::pair<storm::jani::Model, PropertyVector> parseModel(bool parseProperties = true);
std::pair<storm::jani::Model, std::map<std::string, storm::jani::Property>> parseModel(bool parseProperties = true);
storm::jani::Property parseProperty(json const& propertyStructure);
storm::jani::Automaton parseAutomaton(json const& automatonStructure, storm::jani::Model const& parentModel);
std::shared_ptr<storm::jani::Variable> parseVariable(json const& variableStructure, std::string const& scopeDescription, bool prefWithScope = false);
storm::expressions::Expression parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars = std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>>());
storm::expressions::Expression parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars = std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>>(), bool returnNoneOnUnknownOpString = false);
private:
std::shared_ptr<storm::jani::Constant> parseConstant(json const& constantStructure, std::string const& scopeDescription = "global");
@ -51,13 +54,19 @@ namespace storm {
* Helper for parsing the actions of a model.
*/
void parseActions(json const& actionStructure, storm::jani::Model& parentModel);
std::vector<storm::expressions::Expression> parseUnaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars = {});
std::vector<storm::expressions::Expression> parseBinaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars = {});
std::shared_ptr<storm::logic::Formula const> parseFormula(json const& propertyStructure, std::string const& context, boost::optional<storm::logic::Bound<storm::RationalNumber>> bound = boost::none);
std::vector<storm::expressions::Expression> parseUnaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars = {}, bool returnNoneOnUnknownOpString = false);
std::vector<storm::expressions::Expression> parseBinaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars = {}, bool returnNoneOnUnknownOpString = false);
std::vector<std::shared_ptr<storm::logic::Formula const>> parseUnaryFormulaArgument(json const& propertyStructure, std::string const& opstring, std::string const& context);
std::vector<std::shared_ptr<storm::logic::Formula const>> parseBinaryFormulaArguments(json const& propertyStructure, std::string const& opstring, std::string const& context);
storm::jani::PropertyInterval parsePropertyInterval(json const& piStructure);
std::shared_ptr<storm::jani::Composition> parseComposition(json const& compositionStructure);
storm::expressions::Variable getVariableOrConstantExpression(std::string const& ident, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars = {});
/**
* The overall structure currently under inspection.
*/

32
src/parser/KeyValueParser.cpp

@ -0,0 +1,32 @@
#include "KeyValueParser.h"
#include <boost/algorithm/string.hpp>
#include <vector>
#include "src/utility/macros.h"
#include "src/exceptions/InvalidArgumentException.h"
namespace storm {
namespace parser {
std::unordered_map<std::string, std::string> parseKeyValueString(std::string const& keyValueString) {
std::unordered_map<std::string, std::string> keyValueMap;
std::vector<std::string> definitions;
boost::split(definitions, keyValueString, boost::is_any_of(","));
for (auto& definition : definitions) {
boost::trim(definition);
// Check whether the token could be a legal constant definition.
std::size_t positionOfAssignmentOperator = definition.find('=');
STORM_LOG_THROW(positionOfAssignmentOperator != std::string::npos, storm::exceptions::InvalidArgumentException, "Illegal key value string: syntax error.");
// Now extract the variable name and the value from the string.
std::string key = definition.substr(0, positionOfAssignmentOperator);
boost::trim(key);
std::string value = definition.substr(positionOfAssignmentOperator + 1);
boost::trim(value);
keyValueMap.emplace(key, value);
}
return keyValueMap;
}
}
}

11
src/parser/KeyValueParser.h

@ -0,0 +1,11 @@
#pragma once
#include <string>
#include <unordered_map>
namespace storm {
namespace parser {
std::unordered_map<std::string, std::string> parseKeyValueString(std::string const& keyValueString);
}
}

16
src/settings/modules/IOSettings.cpp

@ -7,6 +7,7 @@
#include "src/settings/ArgumentBuilder.h"
#include "src/settings/Argument.h"
#include "src/exceptions/InvalidSettingsException.h"
#include "src/parser/CSVParser.h"
namespace storm {
namespace settings {
@ -30,6 +31,9 @@ namespace storm {
const std::string IOSettings::prismCompatibilityOptionName = "prismcompat";
const std::string IOSettings::prismCompatibilityOptionShortName = "pc";
const std::string IOSettings::fullModelBuildOptionName = "buildfull";
const std::string IOSettings::janiPropertyOptionName = "janiproperty";
const std::string IOSettings::janiPropertyOptionShortName = "jprop";
IOSettings::IOSettings() : ModuleSettings(moduleName) {
this->addOption(storm::settings::OptionBuilder(moduleName, prismCompatibilityOptionName, false, "Enables PRISM compatibility. This may be necessary to process some PRISM models.").setShortName(prismCompatibilityOptionShortName).build());
@ -60,7 +64,8 @@ namespace storm {
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The file from which to read the choice labels.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, constantsOptionName, false, "Specifies the constant replacements to use in symbolic models. Note that this requires the model to be given as an symbolic model (i.e., via --" + prismInputOptionName + " or --" + janiInputOptionName + ").").setShortName(constantsOptionShortName)
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of constants and their value, e.g. a=1,b=2,c=3.").setDefaultValueString("").build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, janiPropertyOptionName, false, "Specifies the properties from the jani model (given by --" + janiInputOptionName + ") to be checked.").setShortName(janiPropertyOptionShortName)
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of properties to be checked").setDefaultValueString("").build()).build());
}
bool IOSettings::isExportDotSet() const {
@ -165,6 +170,15 @@ namespace storm {
return this->getOption(constantsOptionName).getArgumentByName("values").getValueAsString();
}
bool IOSettings::isJaniPropertiesSet() const {
return this->getOption(janiPropertyOptionName).getHasOptionBeenSet();
}
std::vector<std::string> IOSettings::getJaniProperties() const {
return storm::parser::parseCommaSeperatedValues(this->getOption(janiPropertyOptionName).getArgumentByName("values").getValueAsString());
}
bool IOSettings::isPrismCompatibilityEnabled() const {
return this->getOption(prismCompatibilityOptionName).getHasOptionBeenSet();
}

6
src/settings/modules/IOSettings.h

@ -199,6 +199,10 @@ namespace storm {
* @return The string that defines the constants of a symbolic model.
*/
std::string getConstantDefinitionString() const;
bool isJaniPropertiesSet() const;
std::vector<std::string> getJaniProperties() const;
/*!
* Retrieves whether the PRISM compatibility mode was enabled.
@ -239,6 +243,8 @@ namespace storm {
static const std::string prismCompatibilityOptionName;
static const std::string prismCompatibilityOptionShortName;
static const std::string fullModelBuildOptionName;
static const std::string janiPropertyOptionName;
static const std::string janiPropertyOptionShortName;
};
} // namespace modules

5
src/storage/jani/BooleanVariable.cpp

@ -3,7 +3,7 @@
namespace storm {
namespace jani {
BooleanVariable::BooleanVariable(std::string const& name, storm::expressions::Variable const& variable, bool transient) : Variable(name, variable, transient) {
BooleanVariable::BooleanVariable(std::string const& name, storm::expressions::Variable const& variable) : Variable(name, variable) {
// Intentionally left empty.
}
@ -19,7 +19,8 @@ namespace storm {
if (initValue) {
return std::make_shared<BooleanVariable>(name, variable, initValue.get(), transient);
} else {
return std::make_shared<BooleanVariable>(name, variable, transient);
assert(!transient);
return std::make_shared<BooleanVariable>(name, variable);
}
}

2
src/storage/jani/BooleanVariable.h

@ -11,7 +11,7 @@ namespace storm {
/*!
* Creates a Boolean variable with initial value
*/
BooleanVariable(std::string const& name, storm::expressions::Variable const& variable, bool transient=false);
BooleanVariable(std::string const& name, storm::expressions::Variable const& variable);
/*!
* Creates a Boolean variable with initial value

9
src/storage/jani/BoundedIntegerVariable.cpp

@ -13,11 +13,7 @@ namespace storm {
// Intentionally left empty.
}
BoundedIntegerVariable::BoundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, bool transient, storm::expressions::Expression const& lowerBound, storm::expressions::Expression const& upperBound) : Variable(name, variable, transient), lowerBound(lowerBound), upperBound(upperBound) {
// Intentionally left empty.
}
BoundedIntegerVariable::BoundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, storm::expressions::Expression const& lowerBound, storm::expressions::Expression const& upperBound) : Variable(name, variable), lowerBound(lowerBound), upperBound(upperBound) {
BoundedIntegerVariable::BoundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, storm::expressions::Expression const& lowerBound, storm::expressions::Expression const& upperBound) : Variable(name, variable), lowerBound(lowerBound), upperBound(upperBound) {
// Intentionally left empty.
}
@ -56,7 +52,8 @@ namespace storm {
if (initValue) {
return std::make_shared<BoundedIntegerVariable>(name, variable, initValue.get(), transient, lowerBound.get(), upperBound.get());
} else {
return std::make_shared<BoundedIntegerVariable>(name, variable, transient, lowerBound.get(), upperBound.get());
assert(!transient);
return std::make_shared<BoundedIntegerVariable>(name, variable, lowerBound.get(), upperBound.get());
}
}
}

4
src/storage/jani/BoundedIntegerVariable.h

@ -16,10 +16,6 @@ namespace storm {
* Creates a bounded integer variable with transient set to false and an initial value.
*/
BoundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, storm::expressions::Expression const& initValue, storm::expressions::Expression const& lowerBound, storm::expressions::Expression const& upperBound);
/*!
* Creates a bounded integer variable without initial value.
*/
BoundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, bool transient, storm::expressions::Expression const& lowerBound, storm::expressions::Expression const& upperBound);
/*!
* Creates a bounded integer variable with transient set to false and no initial value.
*/

348
src/storage/jani/JSONExporter.cpp

@ -6,8 +6,10 @@
#include "src/utility/macros.h"
#include "src/exceptions/FileIoException.h"
#include "src/exceptions/NotSupportedException.h"
#include "src/exceptions/InvalidJaniException.h"
#include "src/exceptions/NotImplementedException.h"
#include "src/storage/expressions/RationalLiteralExpression.h"
#include "src/storage/expressions/IntegerLiteralExpression.h"
@ -20,8 +22,11 @@
#include "src/storage/expressions/BinaryRelationExpression.h"
#include "src/storage/expressions/VariableExpression.h"
#include "src/logic/Formulas.h"
#include "src/storage/jani/AutomatonComposition.h"
#include "src/storage/jani/ParallelComposition.h"
#include "src/storage/jani/Property.h"
namespace storm {
namespace jani {
@ -85,6 +90,293 @@ namespace storm {
bool allowRecursion;
};
std::string comparisonTypeToJani(storm::logic::ComparisonType ct) {
switch(ct) {
case storm::logic::ComparisonType::Less:
return "<";
case storm::logic::ComparisonType::LessEqual:
return "";
case storm::logic::ComparisonType::Greater:
return ">";
case storm::logic::ComparisonType::GreaterEqual:
return "";
}
}
modernjson::json numberToJson(storm::RationalNumber rn) {
modernjson::json numDecl;
numDecl = storm::utility::convertNumber<double>(rn);
// if(carl::isOne(carl::getDenom(rn))) {
// numDecl = modernjson::json(carl::toString(carl::getNum(rn)));
// } else {
// numDecl["op"] = "/";
// // TODO set json lib to work with arbitrary precision ints.
// assert(carl::toInt<int64_t>(carl::getNum(rn)) == carl::getNum(rn));
// assert(carl::toInt<int64_t>(carl::getDenom(rn)) == carl::getDenom(rn));
// numDecl["left"] = carl::toInt<int64_t>(carl::getNum(rn));
// numDecl["right"] = carl::toInt<int64_t>(carl::getDenom(rn));
// }
return numDecl;
}
modernjson::json constructPropertyInterval(uint64_t lower, uint64_t upper) {
modernjson::json iDecl;
iDecl["lower"] = lower;
iDecl["upper"] = upper;
return iDecl;
}
modernjson::json constructPropertyInterval(double lower, double upper) {
modernjson::json iDecl;
iDecl["lower"] = lower;
iDecl["upper"] = upper;
return iDecl;
}
modernjson::json FormulaToJaniJson::translate(storm::logic::Formula const& formula, bool continuousTime) {
FormulaToJaniJson translator(continuousTime);
return boost::any_cast<modernjson::json>(formula.accept(translator));
}
boost::any FormulaToJaniJson::visit(storm::logic::AtomicExpressionFormula const& f, boost::any const& data) const {
return ExpressionToJson::translate(f.getExpression());
}
boost::any FormulaToJaniJson::visit(storm::logic::AtomicLabelFormula const& f, boost::any const& data) const {
modernjson::json opDecl(f.getLabel());
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::BinaryBooleanStateFormula const& f, boost::any const& data) const{
modernjson::json opDecl;
storm::logic::BinaryBooleanStateFormula::OperatorType op = f.getOperator();
opDecl["op"] = op == storm::logic::BinaryBooleanStateFormula::OperatorType::And ? "" : "";
opDecl["left"] = boost::any_cast<modernjson::json>(f.getLeftSubformula().accept(*this, boost::none));
opDecl["right"] = boost::any_cast<modernjson::json>(f.getRightSubformula().accept(*this, boost::none));
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::BooleanLiteralFormula const& f, boost::any const& data) const {
modernjson::json opDecl(f.isTrueFormula() ? true : false);
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::BoundedUntilFormula const& f, boost::any const& data) const {
modernjson::json opDecl;
opDecl["op"] = "U";
opDecl["left"] = boost::any_cast<modernjson::json>(f.getLeftSubformula().accept(*this, boost::none));
opDecl["right"] = boost::any_cast<modernjson::json>(f.getRightSubformula().accept(*this, boost::none));
if(f.hasDiscreteTimeBound()) {
opDecl["step-bounds"] = constructPropertyInterval(0, f.getDiscreteTimeBound());
} else {
opDecl["time-bounds"] = constructPropertyInterval(f.getIntervalBounds().first, f.getIntervalBounds().second);
}
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::ConditionalFormula const& f, boost::any const& data) const {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Jani currently does not support conditional formulae");
}
boost::any FormulaToJaniJson::visit(storm::logic::CumulativeRewardFormula const& f, boost::any const& data) const {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm currently does not support translating cummulative reward formulae");
}
boost::any FormulaToJaniJson::visit(storm::logic::EventuallyFormula const& f, boost::any const& data) const {
modernjson::json opDecl;
opDecl["op"] = "U";
opDecl["left"] = boost::any_cast<modernjson::json>(f.getTrueFormula()->accept(*this, boost::none));
opDecl["right"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::TimeOperatorFormula const& f, boost::any const& data) const {
modernjson::json opDecl;
std::vector<std::string> tvec;
tvec.push_back("time");
if(f.hasBound()) {
auto bound = f.getBound();
opDecl["op"] = comparisonTypeToJani(bound.comparisonType);
if(f.hasOptimalityType()) {
opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax";
opDecl["left"]["reach"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
} else {
opDecl["left"]["op"] = (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Emax" : "Emin";
opDecl["left"]["reach"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
}
opDecl["left"]["exp"] = modernjson::json(1);
opDecl["left"]["accumulate"] = modernjson::json(tvec);
opDecl["right"] = numberToJson(bound.threshold);
} else {
if(f.hasOptimalityType()) {
opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax";
opDecl["reach"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
} else {
// TODO add checks
opDecl["op"] = "Pmin";
opDecl["reach"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
}
opDecl["exp"] = modernjson::json(1);
opDecl["accumulate"] = modernjson::json(tvec);
}
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::GloballyFormula const& f, boost::any const& data) const {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support conversion of a globally formulae");
}
boost::any FormulaToJaniJson::visit(storm::logic::InstantaneousRewardFormula const& f, boost::any const& data) const {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support conversion of an instanteneous reward formula");
}
boost::any FormulaToJaniJson::visit(storm::logic::LongRunAverageOperatorFormula const& f, boost::any const& data) const {
modernjson::json opDecl;
if(f.hasBound()) {
auto bound = f.getBound();
opDecl["op"] = comparisonTypeToJani(bound.comparisonType);
if(f.hasOptimalityType()) {
opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Smin" : "Smax";
opDecl["left"]["exp"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
} else {
opDecl["left"]["op"] = (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Smax" : "Smin";
opDecl["left"]["exp"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
}
opDecl["right"] = numberToJson(bound.threshold);
} else {
if(f.hasOptimalityType()) {
opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Smin" : "Smax";
opDecl["exp"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
} else {
// TODO add checks
opDecl["op"] = "Pmin";
opDecl["exp"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
}
}
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::LongRunAverageRewardFormula const& f, boost::any const& data) const {
// modernjson::json opDecl;
// if(f.()) {
// auto bound = f.getBound();
// opDecl["op"] = comparisonTypeToJani(bound.comparisonType);
// if(f.hasOptimalityType()) {
// opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Smin" : "Smax";
// opDecl["left"]["exp"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
// } else {
// opDecl["left"]["op"] = (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Smax" : "Smin";
// opDecl["left"]["exp"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
// }
// opDecl["right"] = numberToJson(bound.threshold);
// } else {
// if(f.hasOptimalityType()) {
// opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Smin" : "Smax";
// opDecl["exp"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
//
// } else {
// // TODO add checks
// opDecl["op"] = "Pmin";
// opDecl["exp"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
// }
// }
// return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::NextFormula const& f, boost::any const& data) const {
modernjson::json opDecl;
opDecl["op"] = "U";
opDecl["left"] = boost::any_cast<modernjson::json>(f.getTrueFormula()->accept(*this, boost::none));
opDecl["right"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
opDecl["step-bounds"] = constructPropertyInterval((uint64_t)1, (uint64_t)1);
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::ProbabilityOperatorFormula const& f, boost::any const& data) const {
modernjson::json opDecl;
if(f.hasBound()) {
auto bound = f.getBound();
opDecl["op"] = comparisonTypeToJani(bound.comparisonType);
if(f.hasOptimalityType()) {
opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Pmin" : "Pmax";
opDecl["left"]["exp"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
} else {
opDecl["left"]["op"] = (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Pmax" : "Pmin";
opDecl["left"]["exp"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
}
opDecl["right"] = numberToJson(bound.threshold);
} else {
if(f.hasOptimalityType()) {
opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Pmin" : "Pmax";
opDecl["exp"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
} else {
// TODO add checks
opDecl["op"] = "Pmin";
opDecl["exp"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
}
}
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::RewardOperatorFormula const& f, boost::any const& data) const {
modernjson::json opDecl;
std::vector<std::string> accvec;
if(continuous) {
accvec.push_back("time");
} else {
accvec.push_back("steps");
}
if(f.hasBound()) {
auto bound = f.getBound();
opDecl["op"] = comparisonTypeToJani(bound.comparisonType);
if(f.hasOptimalityType()) {
opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax";
opDecl["left"]["reach"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
} else {
opDecl["left"]["op"] = (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Emax" : "Emin";
opDecl["left"]["reach"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
}
opDecl["left"]["exp"] = f.hasRewardModelName() ? f.getRewardModelName() : "DEFAULT";
opDecl["left"]["accumulate"] = modernjson::json(accvec);
opDecl["right"] = numberToJson(bound.threshold);
} else {
if(f.hasOptimalityType()) {
opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax";
opDecl["reach"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
} else {
// TODO add checks
opDecl["op"] = "Pmin";
opDecl["reach"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
}
opDecl["exp"] = f.hasRewardModelName() ? f.getRewardModelName() : "DEFAULT";
opDecl["accumulate"] = modernjson::json(accvec);
}
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::UnaryBooleanStateFormula const& f, boost::any const& data) const {
modernjson::json opDecl;
storm::logic::UnaryBooleanStateFormula::OperatorType op = f.getOperator();
assert(op == storm::logic::UnaryBooleanStateFormula::OperatorType::Not);
opDecl["op"] = "¬";
opDecl["exp"] = boost::any_cast<modernjson::json>(f.getSubformula().accept(*this, boost::none));
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::UntilFormula const& f, boost::any const& data) const {
modernjson::json opDecl;
opDecl["op"] = "U";
opDecl["left"] = boost::any_cast<modernjson::json>(f.getLeftSubformula().accept(*this, boost::none));
opDecl["right"] = boost::any_cast<modernjson::json>(f.getRightSubformula().accept(*this, boost::none));
return opDecl;
}
std::string operatorTypeToJaniString(storm::expressions::OperatorType optype) {
@ -205,22 +497,23 @@ namespace storm {
void JsonExporter::toFile(storm::jani::Model const& janiModel, std::string const& filepath, bool checkValid) {
void JsonExporter::toFile(storm::jani::Model const& janiModel, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, std::string const& filepath, bool checkValid) {
std::ofstream ofs;
ofs.open (filepath, std::ofstream::out );
if(ofs.is_open()) {
toStream(janiModel, ofs, checkValid);
toStream(janiModel, formulas, ofs, checkValid);
} else {
STORM_LOG_THROW(false, storm::exceptions::FileIoException, "Cannot open " << filepath);
}
}
void JsonExporter::toStream(storm::jani::Model const& janiModel, std::ostream& os, bool checkValid) {
void JsonExporter::toStream(storm::jani::Model const& janiModel, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, std::ostream& os, bool checkValid) {
if(checkValid) {
janiModel.checkValid();
}
JsonExporter exporter;
exporter.convertModel(janiModel);
exporter.convertProperties(formulas, !janiModel.isDiscreteTimeModel());
os << exporter.finalize().dump(4) << std::endl;
}
@ -400,6 +693,55 @@ namespace storm {
}
std::string janiFilterTypeString(storm::modelchecker::FilterType const& ft) {
switch(ft) {
case storm::modelchecker::FilterType::MIN:
return "min";
case storm::modelchecker::FilterType::MAX:
return "max";
case storm::modelchecker::FilterType::SUM:
return "sum";
case storm::modelchecker::FilterType::AVG:
return "avg";
case storm::modelchecker::FilterType::COUNT:
return "count";
case storm::modelchecker::FilterType::EXISTS:
return "";
case storm::modelchecker::FilterType::FORALL:
return "";
case storm::modelchecker::FilterType::ARGMIN:
return "argmin";
case storm::modelchecker::FilterType::ARGMAX:
return "argmax";
case storm::modelchecker::FilterType::VALUES:
return "values";
}
}
modernjson::json convertFilterExpression(storm::jani::FilterExpression const& fe, bool continuousModel) {
modernjson::json propDecl;
propDecl["states"]["op"] = "initial";
propDecl["op"] = "filter";
propDecl["fun"] = janiFilterTypeString(fe.getFilterType());
propDecl["values"] = FormulaToJaniJson::translate(*fe.getFormula(), continuousModel);
return propDecl;
}
void JsonExporter::convertProperties( std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool continuousModel) {
std::vector<modernjson::json> properties;
uint64_t index = 0;
for(auto const& f : formulas) {
modernjson::json propDecl;
propDecl["name"] = "prop" + std::to_string(index);
propDecl["expression"] = convertFilterExpression(storm::jani::FilterExpression(f), continuousModel);
++index;
properties.push_back(propDecl);
}
jsonStruct["properties"] = properties;
}
}
}

39
src/storage/jani/JSONExporter.h

@ -2,10 +2,14 @@
#include "src/storage/expressions/ExpressionVisitor.h"
#include "src/logic/FormulaVisitor.h"
#include "Model.h"
#include "src/adapters/NumberAdapter.h"
// JSON parser
#include "json.hpp"
namespace modernjson = nlohmann;
namespace modernjson {
using json = nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, double, std::allocator>;
};
namespace storm {
namespace jani {
@ -28,15 +32,44 @@ namespace storm {
};
class FormulaToJaniJson : public storm::logic::FormulaVisitor {
public:
static modernjson::json translate(storm::logic::Formula const& formula, bool continuousTime);
virtual boost::any visit(storm::logic::AtomicExpressionFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::AtomicLabelFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::BinaryBooleanStateFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::BooleanLiteralFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::BoundedUntilFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::ConditionalFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::CumulativeRewardFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::EventuallyFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::TimeOperatorFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::GloballyFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::InstantaneousRewardFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::LongRunAverageOperatorFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::LongRunAverageRewardFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::NextFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::ProbabilityOperatorFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::RewardOperatorFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::UnaryBooleanStateFormula const& f, boost::any const& data) const;
virtual boost::any visit(storm::logic::UntilFormula const& f, boost::any const& data) const;
private:
FormulaToJaniJson(bool continuousModel) : continuous(continuousModel) { }
bool continuous;
};
class JsonExporter {
JsonExporter() = default;
public:
static void toFile(storm::jani::Model const& janiModel, std::string const& filepath, bool checkValid = true);
static void toStream(storm::jani::Model const& janiModel, std::ostream& ostream, bool checkValid = false);
static void toFile(storm::jani::Model const& janiModel, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, std::string const& filepath, bool checkValid = true);
static void toStream(storm::jani::Model const& janiModel, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, std::ostream& ostream, bool checkValid = false);
private:
void convertModel(storm::jani::Model const& model);
void convertProperties(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool timeContinuousModel);
void appendVariableDeclaration(storm::jani::Variable const& variable);
modernjson::json finalize() {

28
src/storage/jani/Property.cpp

@ -1,10 +1,23 @@
#include "Property.h"
namespace storm {
namespace jani {
Property::Property(std::string const& name, std::shared_ptr<const storm::logic::Formula> const& formula, std::string const& comment)
: name(name), formula(formula), comment(comment)
std::ostream& operator<<(std::ostream& os, FilterExpression const& fe) {
return os << "Obtain " << toString(fe.getFilterType()) << " the 'initial'-states with values described by '" << *fe.getFormula() << "'";
}
Property::Property(std::string const& name, std::shared_ptr<storm::logic::Formula const> const& formula, std::string const& comment)
: name(name), comment(comment), filterExpression(FilterExpression(formula))
{
}
Property::Property(std::string const& name, FilterExpression const& fe, std::string const& comment)
: name(name), comment(comment), filterExpression(fe)
{
}
std::string const& Property::getName() const {
@ -14,10 +27,15 @@ namespace storm {
std::string const& Property::getComment() const {
return this->comment;
}
std::shared_ptr<storm::logic::Formula const> const& Property::getFormula() const {
return this->formula;
FilterExpression const& Property::getFilter() const {
return this->filterExpression;
}
std::ostream& operator<<(std::ostream& os, Property const& p) {
return os << "(" << p.getName() << ") : " << p.getFilter();
}
}
}

66
src/storage/jani/Property.h

@ -1,10 +1,56 @@
#pragma once
#include "src/logic/formulas.h"
#include "src/modelchecker/results/FilterType.h"
namespace storm {
namespace jani {
/**
* Property intervals as per Jani Specification.
* Currently mainly used to help parsing.
*/
struct PropertyInterval {
storm::expressions::Expression lowerBound;
bool lowerBoundStrict = false;
storm::expressions::Expression upperBound;
bool upperBoundStrict = false;
bool hasLowerBound() {
return lowerBound.isInitialized();
}
bool hasUpperBound() {
return upperBound.isInitialized();
}
};
class FilterExpression {
public:
explicit FilterExpression(std::shared_ptr<storm::logic::Formula const> formula, storm::modelchecker::FilterType ft = storm::modelchecker::FilterType::VALUES) : values(formula), ft(ft) {}
std::shared_ptr<storm::logic::Formula const> const& getFormula() const {
return values;
}
storm::modelchecker::FilterType getFilterType() const {
return ft;
}
private:
// For now, we assume that the states are always the initial states.
std::shared_ptr<storm::logic::Formula const> values;
storm::modelchecker::FilterType ft;
};
std::ostream& operator<<(std::ostream& os, FilterExpression const& fe);
class Property {
public:
/**
* Constructs the property
* @param name the name
@ -12,6 +58,13 @@ namespace storm {
* @param comment An optional comment
*/
Property(std::string const& name, std::shared_ptr<storm::logic::Formula const> const& formula, std::string const& comment = "");
/**
* Constructs the property
* @param name the name
* @param formula the formula representation
* @param comment An optional comment
*/
Property(std::string const& name, FilterExpression const& fe, std::string const& comment = "");
/**
* Get the provided name
* @return the name
@ -22,17 +75,16 @@ namespace storm {
* @return the comment
*/
std::string const& getComment() const;
/**
* Get the formula
* @return the formula
*/
std::shared_ptr<storm::logic::Formula const> const& getFormula() const;
FilterExpression const& getFilter() const;
private:
std::string name;
std::shared_ptr<storm::logic::Formula const> formula;
std::string comment;
FilterExpression filterExpression;
};
std::ostream& operator<<(std::ostream& os, Property const& p);
}
}

2
src/storage/jani/RealVariable.cpp

@ -3,7 +3,7 @@
namespace storm {
namespace jani {
RealVariable::RealVariable(std::string const& name, storm::expressions::Variable const& variable, bool transient) : storm::jani::Variable(name, variable, transient) {
RealVariable::RealVariable(std::string const& name, storm::expressions::Variable const& variable) : storm::jani::Variable(name, variable) {
// Intentionally left empty.
}

2
src/storage/jani/RealVariable.h

@ -10,7 +10,7 @@ namespace storm {
/*!
* Creates a real variable without initial value.
*/
RealVariable(std::string const& name, storm::expressions::Variable const& variable, bool transient=false);
RealVariable(std::string const& name, storm::expressions::Variable const& variable);
/*!
* Creates a real variable with initial value.

2
src/storage/jani/UnboundedIntegerVariable.cpp

@ -7,7 +7,7 @@ namespace storm {
// Intentionally left empty.
}
UnboundedIntegerVariable::UnboundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, bool transient) : Variable(name, variable, transient) {
UnboundedIntegerVariable::UnboundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, bool transient) : Variable(name, variable) {
// Intentionally left empty.
}

2
src/storage/jani/Variable.cpp

@ -12,7 +12,7 @@ namespace storm {
// Intentionally left empty.
}
Variable::Variable(std::string const& name, storm::expressions::Variable const& variable, bool transient) : name(name), variable(variable), transient(transient), init() {
Variable::Variable(std::string const& name, storm::expressions::Variable const& variable) : name(name), variable(variable), transient(false), init() {
// Intentionally left empty.
}

2
src/storage/jani/Variable.h

@ -25,7 +25,7 @@ namespace storm {
/*!
* Creates a new variable without initial value construct.
*/
Variable(std::string const& name, storm::expressions::Variable const& variable, bool transient = false);
Variable(std::string const& name, storm::expressions::Variable const& variable);
virtual ~Variable();

2
src/storage/ppg/defines.h

@ -1,6 +1,8 @@
#pragma once
#include <cassert>
#include <vector>
#include <cstdint>
namespace storm {
namespace ppg {
class ProgramGraph;

4
src/storage/prism/Module.cpp

@ -196,12 +196,12 @@ namespace storm {
bool Module::containsVariablesOnlyInUpdateProbabilities(std::set<storm::expressions::Variable> const& undefinedConstantVariables) const {
for (auto const& booleanVariable : this->getBooleanVariables()) {
if (booleanVariable.getInitialValueExpression().containsVariable(undefinedConstantVariables)) {
if (booleanVariable.hasInitialValue() && booleanVariable.getInitialValueExpression().containsVariable(undefinedConstantVariables)) {
return false;
}
}
for (auto const& integerVariable : this->getIntegerVariables()) {
if (integerVariable.getInitialValueExpression().containsVariable(undefinedConstantVariables)) {
if (integerVariable.hasInitialValue() && integerVariable.getInitialValueExpression().containsVariable(undefinedConstantVariables)) {
return false;
}
if (integerVariable.getLowerBoundExpression().containsVariable(undefinedConstantVariables)) {

6
src/storage/prism/ToJaniConverter.cpp

@ -47,7 +47,7 @@ namespace storm {
storm::jani::BoundedIntegerVariable const& createdVariable = janiModel.addVariable(storm::jani::BoundedIntegerVariable(variable.getName(), variable.getExpressionVariable(), variable.getInitialValueExpression(), false, variable.getLowerBoundExpression(), variable.getUpperBoundExpression()));
variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable);
} else {
storm::jani::BoundedIntegerVariable const& createdVariable = janiModel.addVariable(storm::jani::BoundedIntegerVariable(variable.getName(), variable.getExpressionVariable(), false, variable.getLowerBoundExpression(), variable.getUpperBoundExpression()));
storm::jani::BoundedIntegerVariable const& createdVariable = janiModel.addVariable(storm::jani::BoundedIntegerVariable(variable.getName(), variable.getExpressionVariable(), variable.getLowerBoundExpression(), variable.getUpperBoundExpression()));
variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable);
}
}
@ -56,7 +56,7 @@ namespace storm {
storm::jani::BooleanVariable const& createdVariable = janiModel.addVariable(storm::jani::BooleanVariable(variable.getName(), variable.getExpressionVariable(), variable.getInitialValueExpression(), false));
variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable);
} else {
storm::jani::BooleanVariable const& createdVariable = janiModel.addVariable(storm::jani::BooleanVariable(variable.getName(), variable.getExpressionVariable(), false));
storm::jani::BooleanVariable const& createdVariable = janiModel.addVariable(storm::jani::BooleanVariable(variable.getName(), variable.getExpressionVariable()));
variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable);
}
}
@ -100,7 +100,7 @@ namespace storm {
std::vector<storm::jani::Assignment> transientLocationAssignments;
for (auto const& rewardModel : program.getRewardModels()) {
auto newExpressionVariable = manager->declareRationalVariable(rewardModel.getName().empty() ? "default" : rewardModel.getName());
storm::jani::RealVariable const& newTransientVariable = janiModel.addVariable(storm::jani::RealVariable(rewardModel.getName(), newExpressionVariable, true));
storm::jani::RealVariable const& newTransientVariable = janiModel.addVariable(storm::jani::RealVariable(rewardModel.getName().empty() ? "defaultReward" : rewardModel.getName(), newExpressionVariable, manager->rational(0.0), true));
if (rewardModel.hasStateRewards()) {
storm::expressions::Expression transientLocationExpression;

95
src/utility/constants.cpp

@ -5,7 +5,10 @@
#include "src/settings/SettingsManager.h"
#include "src/settings/modules/GeneralSettings.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "src/adapters/CarlAdapter.h"
#include "src/utility/macros.h"
namespace storm {
namespace utility {
@ -167,6 +170,80 @@ namespace storm {
return std::fabs(number);
}
template<>
storm::RationalFunction minimum(std::vector<storm::RationalFunction> const& values)
{
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Minimum for rational functions is not defined");
}
template<typename ValueType>
ValueType minimum(std::vector<ValueType> const& values) {
assert(!values.empty());
ValueType min = values.front();
for (auto const& vt : values) {
if (vt < min) {
min = vt;
}
}
return min;
}
template<>
storm::RationalFunction maximum(std::vector<storm::RationalFunction> const& values)
{
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Maximum for rational functions is not defined");
}
template<typename ValueType>
ValueType maximum(std::vector<ValueType> const& values) {
assert(!values.empty());
ValueType max = values.front();
for (auto const& vt : values) {
if (vt > max) {
max = vt;
}
}
return max;
}
template<>
storm::RationalFunction minimum(std::map<uint64_t, storm::RationalFunction> const& values)
{
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Minimum for rational functions is not defined");
}
template< typename K, typename ValueType>
ValueType minimum(std::map<K, ValueType> const& values) {
assert(!values.empty());
ValueType min = values.begin()->second;
for (auto const& vt : values) {
if (vt.second < min) {
min = vt.second;
}
}
return min;
}
template<>
storm::RationalFunction maximum(std::map<uint64_t, storm::RationalFunction> const& values)
{
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Maximum for rational functions is not defined");
}
template<typename K, typename ValueType>
ValueType maximum(std::map<K, ValueType> const& values) {
assert(!values.empty());
ValueType max = values.begin()->second;
for (auto const& vt : values) {
if (vt.second > max) {
max = vt.second;
}
}
return max;
}
#ifdef STORM_HAVE_CARL
template<>
RationalFunction& simplify(RationalFunction& value);
@ -346,6 +423,24 @@ namespace storm {
template storm::storage::MatrixEntry<storm::storage::sparse::state_type, storm::storage::sparse::state_type>& simplify(storm::storage::MatrixEntry<storm::storage::sparse::state_type, storm::storage::sparse::state_type>& matrixEntry);
template storm::storage::MatrixEntry<storm::storage::sparse::state_type, storm::storage::sparse::state_type>&& simplify(storm::storage::MatrixEntry<storm::storage::sparse::state_type, storm::storage::sparse::state_type>&& matrixEntry);
template double minimum(std::vector<double> const&);
template double maximum(std::vector<double> const&);
template storm::RationalNumber minimum(std::vector<storm::RationalNumber> const&);
template storm::RationalNumber maximum(std::vector<storm::RationalNumber> const&);
template storm::RationalFunction minimum(std::vector<storm::RationalFunction> const&);
template storm::RationalFunction maximum(std::vector<storm::RationalFunction> const&);
template double minimum(std::map<uint64_t, double> const&);
template double maximum(std::map<uint64_t, double> const&);
template storm::RationalNumber minimum(std::map<uint64_t, storm::RationalNumber> const&);
template storm::RationalNumber maximum(std::map<uint64_t, storm::RationalNumber> const&);
template storm::RationalFunction minimum(std::map<uint64_t, storm::RationalFunction> const&);
template storm::RationalFunction maximum(std::map<uint64_t, storm::RationalFunction> const&);
#ifdef STORM_HAVE_CARL
// Instantiations for rational number.
template bool isOne(storm::RationalNumber const& value);

16
src/utility/constants.h

@ -13,6 +13,9 @@
#include <cstdint>
#include <string>
#include <vector>
#include <map>
namespace storm {
// Forward-declare MatrixEntry class.
@ -46,6 +49,19 @@ namespace storm {
template<typename ValueType>
ValueType simplify(ValueType value);
template<typename ValueType>
ValueType minimum(std::vector<ValueType> const& values);
template<typename ValueType>
ValueType maximum(std::vector<ValueType> const& values);
template< typename K, typename ValueType>
ValueType minimum(std::map<K, ValueType> const& values);
template<typename K, typename ValueType>
ValueType maximum(std::map<K, ValueType> const& values);
template<typename IndexType, typename ValueType>
storm::storage::MatrixEntry<IndexType, ValueType>& simplify(storm::storage::MatrixEntry<IndexType, ValueType>& matrixEntry);

15
src/utility/storm.cpp

@ -7,7 +7,16 @@
#include "src/utility/macros.h"
#include "src/storage/jani/Property.h"
namespace storm {
namespace storm{
std::vector<std::shared_ptr<storm::logic::Formula const>> formulasInProperties(std::vector<storm::jani::Property> const& properties) {
std::vector<std::shared_ptr<storm::logic::Formula const>> formulas;
for (auto const& prop : properties) {
formulas.push_back(prop.getFilter().getFormula());
}
return formulas;
}
storm::prism::Program parseProgram(std::string const& path) {
storm::prism::Program program = storm::parser::PrismParser::parse(path).simplify().simplify();
@ -15,8 +24,8 @@ namespace storm {
return program;
}
std::pair<storm::jani::Model, std::vector<storm::jani::Property>> parseJaniModel(std::string const& path) {
std::pair<storm::jani::Model, std::vector<storm::jani::Property>> modelAndFormulae = storm::parser::JaniParser::parse(path);
std::pair<storm::jani::Model, std::map<std::string, storm::jani::Property>> parseJaniModel(std::string const& path) {
std::pair<storm::jani::Model, std::map<std::string, storm::jani::Property>> modelAndFormulae = storm::parser::JaniParser::parse(path);
modelAndFormulae.first.checkValid();
return modelAndFormulae;
}

3
src/utility/storm.h

@ -100,7 +100,8 @@ namespace storm {
return storm::parser::AutoParser<>::parseModel(transitionsFile, labelingFile, stateRewardsFile ? stateRewardsFile.get() : "", transitionRewardsFile ? transitionRewardsFile.get() : "", choiceLabelingFile ? choiceLabelingFile.get() : "" );
}
std::pair<storm::jani::Model, std::vector<storm::jani::Property>> parseJaniModel(std::string const& path);
std::vector<std::shared_ptr<storm::logic::Formula const>> formulasInProperties(std::vector<storm::jani::Property> const& properties);
std::pair<storm::jani::Model, std::map<std::string, storm::jani::Property>> parseJaniModel(std::string const& path);
storm::prism::Program parseProgram(std::string const& path);
std::vector<std::shared_ptr<storm::logic::Formula const>> parseFormulasForExplicit(std::string const& inputString);
std::vector<std::shared_ptr<storm::logic::Formula const>> parseFormulasForPrismProgram(std::string const& inputString, storm::prism::Program const& program);
Loading…
Cancel
Save