Browse Source

Merge branch 'master' into gamebased

main
dehnert 7 years ago
parent
commit
5c7e63ee9a
  1. 16
      CMakeLists.txt
  2. 18
      resources/cmake/macros/export.cmake
  3. 11
      resources/cmake/stormConfigVersion.cmake.in
  4. 12
      resources/examples/testfiles/mdp/prism-mec-example1.nm
  5. 13
      resources/examples/testfiles/mdp/prism-mec-example2.nm
  6. 2
      src/storm-cli-utilities/CMakeLists.txt
  7. 2
      src/storm-dft-cli/CMakeLists.txt
  8. 2
      src/storm-dft/CMakeLists.txt
  9. 2
      src/storm-gspn-cli/CMakeLists.txt
  10. 2
      src/storm-gspn/CMakeLists.txt
  11. 2
      src/storm-pars-cli/CMakeLists.txt
  12. 2
      src/storm-pars/CMakeLists.txt
  13. 2
      src/storm-pgcl-cli/CMakeLists.txt
  14. 2
      src/storm-pgcl/CMakeLists.txt
  15. 4
      src/storm/CMakeLists.txt
  16. 11
      src/storm/builder/BuilderOptions.cpp
  17. 10
      src/storm/builder/BuilderOptions.h
  18. 1429
      src/storm/builder/DdPrismModelBuilder.cp
  19. 3
      src/storm/builder/ExplicitModelBuilder.cpp
  20. 21
      src/storm/counterexamples/SMTMinimalLabelSetGenerator.h
  21. 23
      src/storm/environment/Environment.cpp
  22. 13
      src/storm/environment/Environment.h
  23. 29
      src/storm/environment/SubEnvironment.cpp
  24. 4
      src/storm/environment/SubEnvironment.h
  25. 31
      src/storm/environment/modelchecker/ModelCheckerEnvironment.cpp
  26. 28
      src/storm/environment/modelchecker/ModelCheckerEnvironment.h
  27. 100
      src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.cpp
  28. 48
      src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h
  29. 7
      src/storm/generator/CompressedState.cpp
  30. 2
      src/storm/generator/CompressedState.h
  31. 4
      src/storm/generator/JaniNextStateGenerator.cpp
  32. 30
      src/storm/generator/NextStateGenerator.cpp
  33. 10
      src/storm/generator/NextStateGenerator.h
  34. 4
      src/storm/generator/PrismNextStateGenerator.cpp
  35. 23
      src/storm/generator/VariableInformation.cpp
  36. 5
      src/storm/generator/VariableInformation.h
  37. 2
      src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp
  38. 6
      src/storm/modelchecker/multiobjective/multiObjectiveModelChecking.cpp
  39. 7
      src/storm/modelchecker/multiobjective/pcaa/SparsePcaaAchievabilityQuery.cpp
  40. 22
      src/storm/modelchecker/multiobjective/pcaa/SparsePcaaParetoQuery.cpp
  41. 18
      src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.cpp
  42. 2
      src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.h
  43. 29
      src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.cpp
  44. 4
      src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.h
  45. 4
      src/storm/models/sparse/Model.cpp
  46. 21
      src/storm/models/symbolic/Model.cpp
  47. 10
      src/storm/models/symbolic/Model.h
  48. 33
      src/storm/storage/MaximalEndComponentDecomposition.cpp
  49. 90
      src/storm/storage/StronglyConnectedComponentDecomposition.cpp
  50. 38
      src/storm/storage/StronglyConnectedComponentDecomposition.h
  51. 43
      src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp

16
CMakeLists.txt

@ -78,6 +78,14 @@ set(BIN_INSTALL_DIR lib/ CACHE PATH "Installation directory for executables")
set(DEF_INSTALL_CMAKE_DIR "lib/CMake/storm")
set(CMAKE_INSTALL_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files")
# Add CMake install prefix
foreach(p LIB BIN INCLUDE CMAKE)
set(var ${p}_INSTALL_DIR)
if(NOT IS_ABSOLUTE "${${var}}")
set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}")
endif()
endforeach()
message("CMAKE_INSTALL_DIR: ${CMAKE_INSTALL_DIR}")
# If the STORM_DEVELOPER option was turned on, by default we target a debug version, otherwise a release version.
@ -231,7 +239,7 @@ if (STORM_COMPILER_CLANG OR STORM_COMPILER_APPLECLANG)
endif()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -stdlib=${CLANG_STDLIB} -ftemplate-depth=1024")
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffast-math -fno-finite-math-only")
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
if(LINUX)
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -rdynamic")
@ -242,7 +250,7 @@ if (STORM_COMPILER_CLANG OR STORM_COMPILER_APPLECLANG)
endif()
elseif (STORM_COMPILER_GCC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fprefetch-loop-arrays -ffast-math -fno-finite-math-only")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fprefetch-loop-arrays")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -rdynamic")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic")
endif ()
@ -500,4 +508,8 @@ add_subdirectory(src)
include(export)
install(FILES ${CMAKE_BINARY_DIR}/stormConfig.install.cmake DESTINATION ${CMAKE_INSTALL_DIR} RENAME stormConfig.cmake)
install(FILES ${CMAKE_BINARY_DIR}/stormConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_DIR})
install(EXPORT storm_Targets FILE stormTargets.cmake DESTINATION ${CMAKE_INSTALL_DIR})
include(StormCPackConfig.cmake)

18
resources/cmake/macros/export.cmake

@ -19,10 +19,26 @@ endforeach()
include(CMakePackageConfigHelpers)
write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/stormConfigVersion.cmake
VERSION 0.1.0
COMPATIBILITY SameMajorVersion )
# For the build tree
set(CONF_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/include/")
configure_package_config_file(
resources/cmake/stormConfig.cmake.in
${PROJECT_BINARY_DIR}/stormConfig.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_DIR}
PATH_VARS INCLUDE_INSTALL_DIR #SYSCONFIG_INSTALL_DIR
PATH_VARS INCLUDE_INSTALL_DIR
)
# For the install tree
file(RELATIVE_PATH REL_INCLUDE_DIR "${CMAKE_INSTALL_DIR}" "${INCLUDE_INSTALL_DIR}")
set(CONF_INCLUDE_DIRS "\${storm_CMAKE_DIR}/${REL_INCLUDE_DIR}/storm")
configure_package_config_file(
resources/cmake/stormConfig.cmake.in
${PROJECT_BINARY_DIR}/stormConfig.install.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_DIR}
PATH_VARS INCLUDE_INSTALL_DIR
)

11
resources/cmake/stormConfigVersion.cmake.in

@ -0,0 +1,11 @@
set(PACKAGE_VERSION "@storm_VERSION@")
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()

12
resources/examples/testfiles/mdp/prism-mec-example1.nm

@ -0,0 +1,12 @@
mdp
module test
x : [0..2];
[] x=0 -> true;
[] x=0 -> 0.5 : (x'=1) + 0.5: (x'=2);
[] x=1 -> (x'=0);
[] x=2 -> true;
endmodule

13
resources/examples/testfiles/mdp/prism-mec-example2.nm

@ -0,0 +1,13 @@
mdp
module test
x : [0..2];
[] x=0 -> true;
[] x=0 -> 0.5 : (x'=1) + 0.5: (x'=1);
[] x=0 -> (x'=2);
[] x=1 -> (x'=0);
[] x=2 -> true;
endmodule

2
src/storm-cli-utilities/CMakeLists.txt

@ -36,5 +36,5 @@ add_custom_target(copy_storm_cli_util_headers DEPENDS ${STORM_CLI_UTIL_OUTPUT_HE
add_dependencies(storm-cli-utilities copy_storm_pars_headers)
# installation
install(TARGETS storm-cli-utilities RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)
install(TARGETS storm-cli-utilities EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)

2
src/storm-dft-cli/CMakeLists.txt

@ -6,4 +6,4 @@ set_target_properties(storm-dft-cli PROPERTIES OUTPUT_NAME "storm-dft")
add_dependencies(binaries storm-dft-cli)
# installation
install(TARGETS storm-dft-cli RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)
install(TARGETS storm-dft-cli EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)

2
src/storm-dft/CMakeLists.txt

@ -36,5 +36,5 @@ add_custom_target(copy_storm_dft_headers DEPENDS ${STORM_DFT_OUTPUT_HEADERS} ${S
add_dependencies(storm-dft copy_storm_dft_headers)
# installation
install(TARGETS storm-dft RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)
install(TARGETS storm-dft EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)

2
src/storm-gspn-cli/CMakeLists.txt

@ -5,4 +5,4 @@ set_target_properties(storm-gspn-cli PROPERTIES OUTPUT_NAME "storm-gspn")
add_dependencies(binaries storm-gspn-cli)
# installation
install(TARGETS storm-gspn-cli RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)
install(TARGETS storm-gspn-cli EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)

2
src/storm-gspn/CMakeLists.txt

@ -15,4 +15,4 @@ set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE)
target_link_libraries(storm-gspn storm ${STORM_GSPN_LINK_LIBRARIES})
# installation
install(TARGETS storm-gspn RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)
install(TARGETS storm-gspn EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)

2
src/storm-pars-cli/CMakeLists.txt

@ -6,4 +6,4 @@ set_target_properties(storm-pars-cli PROPERTIES OUTPUT_NAME "storm-pars")
add_dependencies(binaries storm-pars-cli)
# installation
install(TARGETS storm-pars-cli RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)
install(TARGETS storm-pars-cli EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)

2
src/storm-pars/CMakeLists.txt

@ -36,5 +36,5 @@ add_custom_target(copy_storm_pars_headers DEPENDS ${STORM_PARS_OUTPUT_HEADERS} $
add_dependencies(storm-pars copy_storm_pars_headers)
# installation
install(TARGETS storm-pars RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)
install(TARGETS storm-pars EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)

2
src/storm-pgcl-cli/CMakeLists.txt

@ -5,4 +5,4 @@ set_target_properties(storm-pgcl-cli PROPERTIES OUTPUT_NAME "storm-pgcl")
add_dependencies(binaries storm-pgcl-cli)
# installation
install(TARGETS storm-pgcl-cli RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)
install(TARGETS storm-pgcl-cli EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)

2
src/storm-pgcl/CMakeLists.txt

@ -13,4 +13,4 @@ add_library(storm-pgcl SHARED ${STORM_PGCL_SOURCES} ${STORM_PGCL_HEADERS})
target_link_libraries(storm-pgcl storm)
# installation
install(TARGETS storm-pgcl RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)
install(TARGETS storm-pgcl EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)

4
src/storm/CMakeLists.txt

@ -72,7 +72,7 @@ add_dependencies(storm copy_resources_headers)
add_dependencies(binaries storm-main)
# installation
install(TARGETS storm RUNTIME DESTINATION bin LIBRARY DESTINATION lib)
install(TARGETS storm-main RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)
install(TARGETS storm EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib)
install(TARGETS storm-main EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)
install(DIRECTORY ${CMAKE_BINARY_DIR}/include/ DESTINATION include/storm
FILES_MATCHING PATTERN "*.h")

11
src/storm/builder/BuilderOptions.cpp

@ -36,7 +36,7 @@ namespace storm {
return boost::get<storm::expressions::Expression>(labelOrExpression);
}
BuilderOptions::BuilderOptions(bool buildAllRewardModels, bool buildAllLabels) : buildAllRewardModels(buildAllRewardModels), buildAllLabels(buildAllLabels), buildChoiceLabels(false), buildStateValuations(false), buildChoiceOrigins(false), explorationChecks(false), addOutOfBoundsState(false), showProgress(false), showProgressDelay(0) {
BuilderOptions::BuilderOptions(bool buildAllRewardModels, bool buildAllLabels) : buildAllRewardModels(buildAllRewardModels), buildAllLabels(buildAllLabels), buildChoiceLabels(false), buildStateValuations(false), buildChoiceOrigins(false), explorationChecks(false), addOverlappingGuardsLabel(false), addOutOfBoundsState(false), showProgress(false), showProgressDelay(0) {
// Intentionally left empty.
}
@ -164,6 +164,10 @@ namespace storm {
return addOutOfBoundsState;
}
bool BuilderOptions::isAddOverlappingGuardLabelSet() const {
return addOverlappingGuardsLabel;
}
BuilderOptions& BuilderOptions::setBuildAllRewardModels(bool newValue) {
buildAllRewardModels = newValue;
return *this;
@ -238,5 +242,10 @@ namespace storm {
return *this;
}
BuilderOptions& BuilderOptions::setAddOverlappingGuardsLabel(bool newValue) {
addOverlappingGuardsLabel = newValue;
return *this;
}
}
}

10
src/storm/builder/BuilderOptions.h

@ -108,6 +108,7 @@ namespace storm {
bool isExplorationChecksSet() const;
bool isShowProgressSet() const;
bool isAddOutOfBoundsStateSet() const;
bool isAddOverlappingGuardLabelSet() const;
uint64_t getShowProgressDelay() const;
/**
@ -164,6 +165,12 @@ namespace storm {
*/
BuilderOptions& setAddOutOfBoundsState(bool newValue = true);
/**
* Should a state be labelled for overlapping guards
* @param newValue the new value (default true)
*/
BuilderOptions& setAddOverlappingGuardsLabel(bool newValue = true);
private:
/// A flag that indicates whether all reward models are to be built. In this case, the reward model names are
@ -198,6 +205,9 @@ namespace storm {
/// A flag that stores whether exploration checks are to be performed.
bool explorationChecks;
/// A flag for states with overlapping guards
bool addOverlappingGuardsLabel;
/// A flag indicating that the an additional state for out of bounds should be created.
bool addOutOfBoundsState;

1429
src/storm/builder/DdPrismModelBuilder.cp
File diff suppressed because it is too large
View File

3
src/storm/builder/ExplicitModelBuilder.cpp

@ -275,6 +275,7 @@ namespace storm {
// (a) the transition matrix
// (b) the initial states
// (c) the hash map storing the mapping states -> ids
// (d) fix remapping for state-generation labels
// Fix (a).
transitionMatrixBuilder.replaceColumns(remapping, 0);
@ -287,6 +288,8 @@ namespace storm {
// Fix (c).
this->stateStorage.stateToId.remap([&remapping] (StateType const& state) { return remapping[state]; } );
this->generator->remapStateIds([&remapping] (StateType const& state) { return remapping[state]; });
}
}

21
src/storm/counterexamples/SMTMinimalLabelSetGenerator.h

@ -458,6 +458,12 @@ namespace storm {
// Now check for possible backward cuts.
for (auto const& labelSetAndPrecedingLabelSetsPair : precedingLabels) {
bool backwardImplicationAdded = false;
// std::cout << "labelSetAndPrecedingLabelSetsPair.first ";
// for (auto const& e : labelSetAndPrecedingLabelSetsPair.first) {
// std::cout << e << ", ";
// }
// std::cout << std::endl;
// Find out the commands for the currently considered label set.
storm::expressions::Expression guardConjunction;
@ -511,14 +517,17 @@ namespace storm {
if (checkResult == storm::solver::SmtSolver::CheckResult::Unsat) {
STORM_LOG_DEBUG("Selection not enabled in initial state.");
//std::cout << "not gc: " << !guardConjunction << std::endl;
localSolver->add(!guardConjunction);
STORM_LOG_DEBUG("Asserted disjunction of negated guards.");
// Now check the possible preceding label sets for the essential ones.
for (auto const& precedingLabelSet : labelSetAndPrecedingLabelSetsPair.second) {
if (labelSetAndPrecedingLabelSetsPair.first == precedingLabelSet) continue;
//std::cout << "push" << std::endl;
// Create a restore point so we can easily pop-off all weakest precondition expressions.
localSolver->push();
@ -577,6 +586,8 @@ namespace storm {
}
}
//std::cout << "pgc: " << preceedingGuardConjunction << std::endl;
// Assert all the guards of the preceding command set.
localSolver->add(preceedingGuardConjunction);
@ -624,9 +635,13 @@ namespace storm {
assertDisjunction(*localSolver, formulae, symbolicModel.isPrismProgram() ? symbolicModel.asPrismProgram().getManager() : symbolicModel.asJaniModel().getManager());
STORM_LOG_DEBUG("Asserted disjunction of all weakest preconditions.");
storm::solver::SmtSolver::CheckResult result = localSolver->check();
if (localSolver->check() == storm::solver::SmtSolver::CheckResult::Sat) {
if (result == storm::solver::SmtSolver::CheckResult::Sat) {
backwardImplications[labelSetAndPrecedingLabelSetsPair.first].insert(precedingLabelSet);
backwardImplicationAdded = true;
} else if (result == storm::solver::SmtSolver::CheckResult::Unknown) {
STORM_LOG_ERROR("The SMT solver does not come to a conclusive answer. Does your model contain integer division?");
}
localSolver->pop();
@ -637,6 +652,7 @@ namespace storm {
} else {
STORM_LOG_DEBUG("Selection is enabled in initial state.");
}
STORM_LOG_ERROR_COND(backwardImplicationAdded, "Error in adding cuts for counterexample generation (backward implication misses a label set).");
}
} else if (symbolicModel.isJaniModel()) {
STORM_LOG_WARN("Model uses assignment levels, did not assert backward implications.");
@ -1697,6 +1713,7 @@ namespace storm {
labelSets[choice] = choiceOrigins.getEdgeIndexSet(choice);
}
}
assert(labelSets.size() == model.getNumberOfChoices());
// (1) Check whether its possible to exceed the threshold if checkThresholdFeasible is set.
double maximalReachabilityProbability = 0;
@ -1764,7 +1781,7 @@ namespace storm {
solverClock = std::chrono::high_resolution_clock::now();
commandSet = findSmallestCommandSet(*solver, variableInformation, currentBound);
totalSolverTime += std::chrono::high_resolution_clock::now() - solverClock;
STORM_LOG_DEBUG("Computed minimal command set of size " << (commandSet.size() + relevancyInformation.knownLabels.size()) << ".");
STORM_LOG_DEBUG("Computed minimal command set of size " << commandSet.size() + relevancyInformation.knownLabels.size() << " (" << commandSet.size() << " + " << relevancyInformation.knownLabels.size() << ") ");
// Restrict the given model to the current set of labels and compute the reachability probability.
modelCheckingClock = std::chrono::high_resolution_clock::now();

23
src/storm/environment/Environment.cpp

@ -1,6 +1,8 @@
#include "storm/environment/Environment.h"
#include "storm/environment/SubEnvironment.h"
#include "storm/environment/solver/SolverEnvironment.h"
#include "storm/environment/modelchecker/ModelCheckerEnvironment.h"
namespace storm {
@ -12,11 +14,28 @@ namespace storm {
// Intentionally left empty.
}
Environment::Environment(Environment const& other) : internalEnv(other.internalEnv) {
// Intentionally left empty.
}
Environment& Environment::operator=(Environment const& other) {
internalEnv = other.internalEnv;
return *this;
}
SolverEnvironment& Environment::solver() {
return solverEnvironment.get();
return internalEnv.get().solverEnvironment.get();
}
SolverEnvironment const& Environment::solver() const {
return solverEnvironment.get();
return internalEnv.get().solverEnvironment.get();
}
ModelCheckerEnvironment& Environment::modelchecker() {
return internalEnv.get().modelcheckerEnvironment.get();
}
ModelCheckerEnvironment const& Environment::modelchecker() const {
return internalEnv.get().modelcheckerEnvironment.get();
}
}

13
src/storm/environment/Environment.h

@ -6,19 +6,30 @@ namespace storm {
// Forward declare sub-environments
class SolverEnvironment;
class ModelCheckerEnvironment;
// Avoid implementing ugly copy constructors for environment by using an internal environment.
struct InternalEnvironment {
SubEnvironment<SolverEnvironment> solverEnvironment;
SubEnvironment<ModelCheckerEnvironment> modelcheckerEnvironment;
};
class Environment {
public:
Environment();
virtual ~Environment();
Environment(Environment const& other);
Environment& operator=(Environment const& other);
SolverEnvironment& solver();
SolverEnvironment const& solver() const;
ModelCheckerEnvironment& modelchecker();
ModelCheckerEnvironment const& modelchecker() const;
private:
SubEnvironment<SolverEnvironment> solverEnvironment;
SubEnvironment<InternalEnvironment> internalEnv;
};
}

29
src/storm/environment/SubEnvironment.cpp

@ -1,4 +1,9 @@
#include<memory>
#include <memory>
#include "storm/environment/Environment.h"
#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h"
#include "storm/environment/modelchecker/ModelCheckerEnvironment.h"
#include "storm/environment/solver/SolverEnvironment.h"
#include "storm/environment/solver/EigenSolverEnvironment.h"
#include "storm/environment/solver/GmmxxSolverEnvironment.h"
@ -11,31 +16,49 @@
namespace storm {
template<typename EnvironmentType>
SubEnvironment<EnvironmentType>::SubEnvironment() : subEnv(std::make_unique<EnvironmentType>()) {
SubEnvironment<EnvironmentType>::SubEnvironment() : subEnv(nullptr) {
// Intentionally left empty
}
template<typename EnvironmentType>
SubEnvironment<EnvironmentType>::SubEnvironment(SubEnvironment const& other) : subEnv(new EnvironmentType(*other.subEnv)) {
SubEnvironment<EnvironmentType>::SubEnvironment(SubEnvironment const& other) : subEnv(other.subEnv ? new EnvironmentType(*other.subEnv) : nullptr) {
// Intentionally left empty
}
template<typename EnvironmentType>
SubEnvironment<EnvironmentType>& SubEnvironment<EnvironmentType>::operator=(SubEnvironment const& other) {
if (other.subEnv) {
subEnv = std::make_unique<EnvironmentType>(*other.subEnv);
} else {
subEnv.reset();
}
return *this;
}
template<typename EnvironmentType>
EnvironmentType const& SubEnvironment<EnvironmentType>::get() const {
assertInitialized();
return *subEnv;
}
template<typename EnvironmentType>
EnvironmentType& SubEnvironment<EnvironmentType>::get() {
assertInitialized();
return *subEnv;
}
template<typename EnvironmentType>
void SubEnvironment<EnvironmentType>::assertInitialized() const {
if (!subEnv) {
subEnv = std::make_unique<EnvironmentType>();
}
}
template class SubEnvironment<InternalEnvironment>;
template class SubEnvironment<MultiObjectiveModelCheckerEnvironment>;
template class SubEnvironment<ModelCheckerEnvironment>;
template class SubEnvironment<SolverEnvironment>;
template class SubEnvironment<EigenSolverEnvironment>;
template class SubEnvironment<GmmxxSolverEnvironment>;

4
src/storm/environment/SubEnvironment.h

@ -16,8 +16,8 @@ namespace storm {
EnvironmentType& get();
private:
std::unique_ptr<EnvironmentType> subEnv;
void assertInitialized() const;
mutable std::unique_ptr<EnvironmentType> subEnv;
};
}

31
src/storm/environment/modelchecker/ModelCheckerEnvironment.cpp

@ -0,0 +1,31 @@
#include "storm/environment/modelchecker/ModelCheckerEnvironment.h"
#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h"
#include "storm/settings/SettingsManager.h"
#include "storm/utility/macros.h"
#include "storm/exceptions/InvalidEnvironmentException.h"
#include "storm/exceptions/UnexpectedException.h"
namespace storm {
ModelCheckerEnvironment::ModelCheckerEnvironment() {
// Intentionally left empty
}
ModelCheckerEnvironment::~ModelCheckerEnvironment() {
// Intentionally left empty
}
MultiObjectiveModelCheckerEnvironment& ModelCheckerEnvironment::multi() {
return multiObjectiveModelCheckerEnvironment.get();
}
MultiObjectiveModelCheckerEnvironment const& ModelCheckerEnvironment::multi() const {
return multiObjectiveModelCheckerEnvironment.get();
}
}

28
src/storm/environment/modelchecker/ModelCheckerEnvironment.h

@ -0,0 +1,28 @@
#pragma once
#include <memory>
#include <boost/optional.hpp>
#include "storm/environment/Environment.h"
#include "storm/environment/SubEnvironment.h"
namespace storm {
// Forward declare subenvironments
class MultiObjectiveModelCheckerEnvironment;
class ModelCheckerEnvironment {
public:
ModelCheckerEnvironment();
~ModelCheckerEnvironment();
MultiObjectiveModelCheckerEnvironment& multi();
MultiObjectiveModelCheckerEnvironment const& multi() const;
private:
SubEnvironment<MultiObjectiveModelCheckerEnvironment> multiObjectiveModelCheckerEnvironment;
};
}

100
src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.cpp

@ -0,0 +1,100 @@
#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/modules/MultiObjectiveSettings.h"
#include "storm/utility/constants.h"
#include "storm/utility/macros.h"
namespace storm {
MultiObjectiveModelCheckerEnvironment::MultiObjectiveModelCheckerEnvironment() {
auto const& multiobjectiveSettings = storm::settings::getModule<storm::settings::modules::MultiObjectiveSettings>();
method = multiobjectiveSettings.getMultiObjectiveMethod();
if (multiobjectiveSettings.isExportPlotSet()) {
plotPathUnderApprox = multiobjectiveSettings.getExportPlotDirectory() + "underapproximation.csv";
plotPathOverApprox = multiobjectiveSettings.getExportPlotDirectory() + "overapproximation.csv";
plotPathParetoPoints = multiobjectiveSettings.getExportPlotDirectory() + "paretopoints.csv";
}
precision = storm::utility::convertNumber<storm::RationalNumber>(multiobjectiveSettings.getPrecision());
if (multiobjectiveSettings.isMaxStepsSet()) {
maxSteps = multiobjectiveSettings.getMaxSteps();
}
}
MultiObjectiveModelCheckerEnvironment::~MultiObjectiveModelCheckerEnvironment() {
// Intentionally left empty
}
storm::modelchecker::multiobjective::MultiObjectiveMethod const& MultiObjectiveModelCheckerEnvironment::getMethod() const {
return this->method;
}
void MultiObjectiveModelCheckerEnvironment::setMethod(storm::modelchecker::multiobjective::MultiObjectiveMethod value) {
this->method = value;
}
bool MultiObjectiveModelCheckerEnvironment::isExportPlotSet() const {
return this->plotPathUnderApprox.is_initialized() || this->plotPathOverApprox.is_initialized() || this->plotPathParetoPoints.is_initialized();
}
boost::optional<std::string> MultiObjectiveModelCheckerEnvironment::getPlotPathUnderApproximation() const {
return plotPathUnderApprox;
}
void MultiObjectiveModelCheckerEnvironment::setPlotPathUnderApproximation(std::string const& path) {
plotPathUnderApprox = path;
}
void MultiObjectiveModelCheckerEnvironment::unsetPlotPathUnderApproximation() {
plotPathUnderApprox = boost::none;
}
boost::optional<std::string> MultiObjectiveModelCheckerEnvironment::getPlotPathOverApproximation() const {
return plotPathOverApprox;
}
void MultiObjectiveModelCheckerEnvironment::setPlotPathOverApproximation(std::string const& path) {
plotPathOverApprox = path;
}
void MultiObjectiveModelCheckerEnvironment::unsetPlotPathOverApproximation() {
plotPathOverApprox = boost::none;
}
boost::optional<std::string> MultiObjectiveModelCheckerEnvironment::getPlotPathParetoPoints() const {
return plotPathParetoPoints;
}
void MultiObjectiveModelCheckerEnvironment::setPlotPathParetoPoints(std::string const& path) {
plotPathParetoPoints = path;
}
void MultiObjectiveModelCheckerEnvironment::unsetPlotPathParetoPoints() {
plotPathParetoPoints = boost::none;
}
storm::RationalNumber const& MultiObjectiveModelCheckerEnvironment::getPrecision() const {
return precision;
}
void MultiObjectiveModelCheckerEnvironment::setPrecision(storm::RationalNumber const& value) {
precision = value;
}
bool MultiObjectiveModelCheckerEnvironment::isMaxStepsSet() const {
return maxSteps.is_initialized();
}
uint64_t const& MultiObjectiveModelCheckerEnvironment::getMaxSteps() const {
return maxSteps.get();
}
void MultiObjectiveModelCheckerEnvironment::setMaxSteps(uint64_t const& value) {
maxSteps = value;
}
void MultiObjectiveModelCheckerEnvironment::unsetMaxSteps() {
maxSteps = boost::none;
}
}

48
src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h

@ -0,0 +1,48 @@
#pragma once
#include <string>
#include "storm/environment/modelchecker/ModelCheckerEnvironment.h"
#include "storm/modelchecker/multiobjective/MultiObjectiveModelCheckingMethod.h"
#include "storm/adapters/RationalNumberAdapter.h"
namespace storm {
class MultiObjectiveModelCheckerEnvironment {
public:
MultiObjectiveModelCheckerEnvironment();
~MultiObjectiveModelCheckerEnvironment();
storm::modelchecker::multiobjective::MultiObjectiveMethod const& getMethod() const;
void setMethod(storm::modelchecker::multiobjective::MultiObjectiveMethod value);
bool isExportPlotSet() const;
boost::optional<std::string> getPlotPathUnderApproximation() const;
void setPlotPathUnderApproximation(std::string const& path);
void unsetPlotPathUnderApproximation();
boost::optional<std::string> getPlotPathOverApproximation() const;
void setPlotPathOverApproximation(std::string const& path);
void unsetPlotPathOverApproximation();
boost::optional<std::string> getPlotPathParetoPoints() const;
void setPlotPathParetoPoints(std::string const& path);
void unsetPlotPathParetoPoints();
storm::RationalNumber const& getPrecision() const;
void setPrecision(storm::RationalNumber const& value);
uint64_t const& getMaxSteps() const;
bool isMaxStepsSet() const;
void setMaxSteps(uint64_t const& value);
void unsetMaxSteps();
private:
storm::modelchecker::multiobjective::MultiObjectiveMethod method;
boost::optional<std::string> plotPathUnderApprox, plotPathOverApprox, plotPathParetoPoints;
storm::RationalNumber precision;
boost::optional<uint64_t> maxSteps;
};
}

7
src/storm/generator/CompressedState.cpp

@ -46,6 +46,13 @@ namespace storm {
template void unpackStateIntoEvaluator<double>(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<double>& evaluator);
storm::expressions::SimpleValuation unpackStateIntoValuation(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionManager const& manager);
CompressedState createOutOfBoundsState(VariableInformation const& varInfo, bool roundTo64Bit) {
CompressedState result(varInfo.getTotalBitOffset(roundTo64Bit));
assert(varInfo.hasOutOfBoundsBit());
result.set(varInfo.getOutOfBoundsBit());
return result;
}
#ifdef STORM_HAVE_CARL
template void unpackStateIntoEvaluator<storm::RationalNumber>(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<storm::RationalNumber>& evaluator);
template void unpackStateIntoEvaluator<storm::RationalFunction>(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<storm::RationalFunction>& evaluator);

2
src/storm/generator/CompressedState.h

@ -36,6 +36,8 @@ namespace storm {
* @return A valuation that corresponds to the compressed state.
*/
storm::expressions::SimpleValuation unpackStateIntoValuation(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionManager const& manager);
CompressedState createOutOfBoundsState(VariableInformation const& varInfo, bool roundTo64Bit = true);
}
}

4
src/storm/generator/JaniNextStateGenerator.cpp

@ -321,6 +321,10 @@ namespace storm {
if (this->isDeterministicModel() && totalNumberOfChoices > 1) {
Choice<ValueType> globalChoice;
if (this->options.isAddOverlappingGuardLabelSet()) {
this->overlappingGuardStates->push_back(stateToIdCallback(*this->state));
}
// For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs
// this is equal to the number of choices, which is why we initialize it like this here.
ValueType totalExitRate = this->isDiscreteTimeModel() ? static_cast<ValueType>(totalNumberOfChoices) : storm::utility::zero<ValueType>();

30
src/storm/generator/NextStateGenerator.cpp

@ -1,4 +1,5 @@
#include <storm/exceptions/WrongFormatException.h>
#include <storm/exceptions/NotImplementedException.h>
#include "storm/generator/NextStateGenerator.h"
#include "storm/adapters/RationalFunctionAdapter.h"
@ -18,12 +19,22 @@ namespace storm {
template<typename ValueType, typename StateType>
NextStateGenerator<ValueType, StateType>::NextStateGenerator(storm::expressions::ExpressionManager const& expressionManager, VariableInformation const& variableInformation, NextStateGeneratorOptions const& options) : options(options), expressionManager(expressionManager.getSharedPointer()), variableInformation(variableInformation), evaluator(nullptr), state(nullptr) {
// Intentionally left empty.
if(variableInformation.hasOutOfBoundsBit()) {
outOfBoundsState = createOutOfBoundsState(variableInformation);
}
if (options.isAddOverlappingGuardLabelSet()) {
overlappingGuardStates = std::vector<uint64_t>();
}
}
template<typename ValueType, typename StateType>
NextStateGenerator<ValueType, StateType>::NextStateGenerator(storm::expressions::ExpressionManager const& expressionManager, NextStateGeneratorOptions const& options) : options(options), expressionManager(expressionManager.getSharedPointer()), variableInformation(), evaluator(nullptr), state(nullptr) {
// Intentionally left empty.
if(variableInformation.hasOutOfBoundsBit()) {
outOfBoundsState = createOutOfBoundsState(variableInformation);
}
if (options.isAddOverlappingGuardLabelSet()) {
overlappingGuardStates = std::vector<uint64_t>();
}
}
template<typename ValueType, typename StateType>
@ -101,6 +112,14 @@ namespace storm {
}
}
if (this->options.isAddOverlappingGuardLabelSet()) {
STORM_LOG_THROW(!result.containsLabel("overlap_guards"), storm::exceptions::WrongFormatException, "Label 'overlap_guards' is reserved when adding overlapping guard labels");
result.addLabel("overlap_guards");
for (auto index : overlappingGuardStates.get()) {
result.addLabelToState("overlap_guards", index);
}
}
if (this->options.isAddOutOfBoundsStateSet() && stateStorage.stateToId.contains(outOfBoundsState)) {
STORM_LOG_THROW(!result.containsLabel("out_of_bounds"),storm::exceptions::WrongFormatException, "Label 'out_of_bounds' is reserved when adding out of bounds states.");
result.addLabel("out_of_bounds");
@ -163,6 +182,13 @@ namespace storm {
return nullptr;
}
template<typename ValueType, typename StateType>
void NextStateGenerator<ValueType, StateType>::remapStateIds(std::function<StateType(StateType const&)> const& remapping) {
if (overlappingGuardStates != boost::none) {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Remapping of Ids during model building is not supported for overlapping guard statements.");
}
}
template class NextStateGenerator<double>;
#ifdef STORM_HAVE_CARL

10
src/storm/generator/NextStateGenerator.h

@ -67,6 +67,13 @@ namespace storm {
virtual std::shared_ptr<storm::storage::sparse::ChoiceOrigins> generateChoiceOrigins(std::vector<boost::any>& dataForChoiceOrigins) const;
/*!
* Performs a remapping of all values stored by applying the given remapping.
*
* @param remapping The remapping to apply.
*/
void remapStateIds(std::function<StateType(StateType const&)> const& remapping);
protected:
/*!
* Creates the state labeling for the given states using the provided labels and expressions.
@ -98,6 +105,9 @@ namespace storm {
/// A state that encodes the outOfBoundsState
CompressedState outOfBoundsState;
/// A map that stores the indices of states with overlapping guards.
boost::optional<std::vector<uint64_t>> overlappingGuardStates;
};
}
}

4
src/storm/generator/PrismNextStateGenerator.cpp

@ -230,6 +230,10 @@ namespace storm {
if (this->isDeterministicModel() && totalNumberOfChoices > 1) {
Choice<ValueType> globalChoice;
if (this->options.isAddOverlappingGuardLabelSet()) {
this->overlappingGuardStates->push_back(stateToIdCallback(*this->state));
}
// For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs
// this is equal to the number of choices, which is why we initialize it like this here.
ValueType totalExitRate = this->isDiscreteTimeModel() ? static_cast<ValueType>(totalNumberOfChoices) : storm::utility::zero<ValueType>();

23
src/storm/generator/VariableInformation.cpp

@ -31,11 +31,14 @@ namespace storm {
VariableInformation::VariableInformation(storm::prism::Program const& program, bool outOfBoundsState) : totalBitOffset(0) {
if(outOfBoundsState) {
deadlockBit = 0;
outOfBoundsBit = 0;
++totalBitOffset;
} else {
deadlockBit = boost::none;
outOfBoundsBit = boost::none;
}
for (auto const& booleanVariable : program.getGlobalBooleanVariables()) {
booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), totalBitOffset, true);
++totalBitOffset;
@ -75,12 +78,14 @@ namespace storm {
STORM_LOG_THROW(!automaton.getVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException, "Cannot build model from JANI model that contains non-transient real variables in automaton '" << automaton.getName() << "'.");
}
if(outOfBoundsState) {
deadlockBit = 0;
outOfBoundsBit = 0;
++totalBitOffset;
} else {
deadlockBit = boost::none;
outOfBoundsBit = boost::none;
}
for (auto const& variable : model.getGlobalVariables().getBooleanVariables()) {
if (!variable.isTransient()) {
booleanVariables.emplace_back(variable.getExpressionVariable(), totalBitOffset, true);
@ -135,6 +140,16 @@ namespace storm {
return result;
}
bool VariableInformation::hasOutOfBoundsBit() const {
return outOfBoundsBit != boost::none;
}
uint64_t VariableInformation::getOutOfBoundsBit() const {
assert(hasOutOfBoundsBit());
return outOfBoundsBit.get();
}
void VariableInformation::sortVariables() {
// Sort the variables so we can make some assumptions when iterating over them (in the next-state generators).
std::sort(booleanVariables.begin(), booleanVariables.end(), [] (BooleanVariableInformation const& a, BooleanVariableInformation const& b) { return a.variable < b.variable; } );

5
src/storm/generator/VariableInformation.h

@ -93,9 +93,12 @@ namespace storm {
/// The integer variables.
std::vector<IntegerVariableInformation> integerVariables;
bool hasOutOfBoundsBit() const;
uint64_t getOutOfBoundsBit() const;
private:
boost::optional<uint64_t> deadlockBit;
boost::optional<uint64_t> outOfBoundsBit;
/*!
* Sorts the variables to establish a known ordering.

2
src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp

@ -722,7 +722,7 @@ namespace storm {
for (uint_fast64_t row = 0; row < generatorMatrix.getRowCount(); ++row) {
for (auto& entry : generatorMatrix.getRow(row)) {
if (entry.getColumn() == row) {
entry.setValue(-exitRates[row]);
entry.setValue(-exitRates[row] + entry.getValue());
}
}
}

6
src/storm/modelchecker/multiobjective/multiObjectiveModelChecking.cpp

@ -1,7 +1,7 @@
#include "storm/modelchecker/multiobjective/multiObjectiveModelChecking.h"
#include "storm/utility/macros.h"
#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h"
#include "storm/models/sparse/Mdp.h"
#include "storm/models/sparse/MarkovAutomaton.h"
#include "storm/models/sparse/StandardRewardModel.h"
@ -74,8 +74,8 @@ namespace storm {
result = query->check(env);
if(storm::settings::getModule<storm::settings::modules::MultiObjectiveSettings>().isExportPlotSet()) {
query->exportPlotOfCurrentApproximation(storm::settings::getModule<storm::settings::modules::MultiObjectiveSettings>().getExportPlotDirectory());
if (env.modelchecker().multi().isExportPlotSet()) {
query->exportPlotOfCurrentApproximation(env);
}
break;
}

7
src/storm/modelchecker/multiobjective/pcaa/SparsePcaaAchievabilityQuery.cpp

@ -7,9 +7,8 @@
#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
#include "storm/utility/constants.h"
#include "storm/utility/vector.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/modules/GeneralSettings.h"
#include "storm/settings/modules/MultiObjectiveSettings.h"
#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h"
#include "storm/exceptions/InvalidOperationException.h"
@ -57,7 +56,7 @@ namespace storm {
template <class SparseModelType, typename GeometryValueType>
bool SparsePcaaAchievabilityQuery<SparseModelType, GeometryValueType>::checkAchievability(Environment const& env) {
// repeatedly refine the over/ under approximation until the threshold point is either in the under approx. or not in the over approx.
while(!this->maxStepsPerformed()){
while(!this->maxStepsPerformed(env)){
WeightVector separatingVector = this->findSeparatingVector(thresholds);
this->updateWeightedPrecision(separatingVector);
this->performRefinementStep(env, std::move(separatingVector));

22
src/storm/modelchecker/multiobjective/pcaa/SparsePcaaParetoQuery.cpp

@ -7,10 +7,7 @@
#include "storm/modelchecker/results/ExplicitParetoCurveCheckResult.h"
#include "storm/utility/constants.h"
#include "storm/utility/vector.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/modules/MultiObjectiveSettings.h"
#include "storm/settings/modules/GeneralSettings.h"
#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h"
namespace storm {
namespace modelchecker {
@ -19,20 +16,19 @@ namespace storm {
template <class SparseModelType, typename GeometryValueType>
SparsePcaaParetoQuery<SparseModelType, GeometryValueType>::SparsePcaaParetoQuery(SparseMultiObjectivePreprocessorResult<SparseModelType>& preprocessorResult) : SparsePcaaQuery<SparseModelType, GeometryValueType>(preprocessorResult) {
STORM_LOG_ASSERT(preprocessorResult.queryType==SparseMultiObjectivePreprocessorResult<SparseModelType>::QueryType::Pareto, "Invalid query Type");
}
template <class SparseModelType, typename GeometryValueType>
std::unique_ptr<CheckResult> SparsePcaaParetoQuery<SparseModelType, GeometryValueType>::check(Environment const& env) {
// Set the precision of the weight vector checker
typename SparseModelType::ValueType weightedPrecision = storm::utility::convertNumber<typename SparseModelType::ValueType>(storm::settings::getModule<storm::settings::modules::MultiObjectiveSettings>().getPrecision());
typename SparseModelType::ValueType weightedPrecision = storm::utility::convertNumber<typename SparseModelType::ValueType>(env.modelchecker().multi().getPrecision());
weightedPrecision /= storm::utility::sqrt(storm::utility::convertNumber<typename SparseModelType::ValueType, uint_fast64_t>(this->objectives.size()));
// multiobjPrecision / sqrt(numObjectives) is the largest possible value for which termination is guaranteed.
// Lets be a little bit more precise to reduce the number of required iterations.
weightedPrecision *= storm::utility::convertNumber<typename SparseModelType::ValueType>(0.9);
this->weightVectorChecker->setWeightedPrecision(weightedPrecision);
}
template <class SparseModelType, typename GeometryValueType>
std::unique_ptr<CheckResult> SparsePcaaParetoQuery<SparseModelType, GeometryValueType>::check(Environment const& env) {
// refine the approximation
exploreSetOfAchievablePoints(env);
@ -55,13 +51,13 @@ namespace storm {
void SparsePcaaParetoQuery<SparseModelType, GeometryValueType>::exploreSetOfAchievablePoints(Environment const& env) {
//First consider the objectives individually
for(uint_fast64_t objIndex = 0; objIndex<this->objectives.size() && !this->maxStepsPerformed(); ++objIndex) {
for(uint_fast64_t objIndex = 0; objIndex<this->objectives.size() && !this->maxStepsPerformed(env); ++objIndex) {
WeightVector direction(this->objectives.size(), storm::utility::zero<GeometryValueType>());
direction[objIndex] = storm::utility::one<GeometryValueType>();
this->performRefinementStep(env, std::move(direction));
}
while(!this->maxStepsPerformed()) {
while(!this->maxStepsPerformed(env)) {
// Get the halfspace of the underApproximation with maximal distance to a vertex of the overApproximation
std::vector<storm::storage::geometry::Halfspace<GeometryValueType>> underApproxHalfspaces = this->underApproximation->getHalfspaces();
std::vector<Point> overApproxVertices = this->overApproximation->getVertices();
@ -76,7 +72,7 @@ namespace storm {
}
}
}
if(farestDistance < storm::utility::convertNumber<GeometryValueType>(storm::settings::getModule<storm::settings::modules::MultiObjectiveSettings>().getPrecision())) {
if(farestDistance < storm::utility::convertNumber<GeometryValueType>(env.modelchecker().multi().getPrecision())) {
// Goal precision reached!
return;
}

18
src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.cpp

@ -8,9 +8,7 @@
#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
#include "storm/utility/constants.h"
#include "storm/utility/vector.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/modules/MultiObjectiveSettings.h"
#include "storm/settings/modules/GeneralSettings.h"
#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h"
#include "storm/exceptions/InvalidOperationException.h"
@ -99,7 +97,7 @@ namespace storm {
// We don't care for the optimizing objective at this point
this->diracWeightVectorsToBeChecked.set(indexOfOptimizingObjective, false);
while(!this->maxStepsPerformed()){
while(!this->maxStepsPerformed(env)){
WeightVector separatingVector = this->findSeparatingVector(thresholds);
this->updateWeightedPrecisionInAchievabilityPhase(separatingVector);
this->performRefinementStep(env, std::move(separatingVector));
@ -150,10 +148,10 @@ namespace storm {
// the supremum over all strategies. Hence, one could combine a scheduler inducing the optimum value (but possibly violating strict
// thresholds) and (with very low probability) a scheduler that satisfies all (possibly strict) thresholds.
GeometryValueType result = storm::utility::zero<GeometryValueType>();
while(!this->maxStepsPerformed()) {
while(!this->maxStepsPerformed(env)) {
if (this->refinementSteps.empty()) {
// We did not make any refinement steps during the checkAchievability phase (e.g., because there is only one objective).
this->weightVectorChecker->setWeightedPrecision(storm::utility::convertNumber<typename SparseModelType::ValueType>(storm::settings::getModule<storm::settings::modules::MultiObjectiveSettings>().getPrecision()));
this->weightVectorChecker->setWeightedPrecision(storm::utility::convertNumber<typename SparseModelType::ValueType>(env.modelchecker().multi().getPrecision()));
WeightVector separatingVector = directionOfOptimizingObjective;
this->performRefinementStep(env, std::move(separatingVector));
}
@ -165,7 +163,7 @@ namespace storm {
optimizationRes = this->overApproximation->intersection(thresholdsAsPolytope)->optimize(directionOfOptimizingObjective);
if (optimizationRes.second) {
GeometryValueType precisionOfResult = optimizationRes.first[indexOfOptimizingObjective] - result;
if (precisionOfResult < storm::utility::convertNumber<GeometryValueType>(storm::settings::getModule<storm::settings::modules::MultiObjectiveSettings>().getPrecision())) {
if (precisionOfResult < storm::utility::convertNumber<GeometryValueType>(env.modelchecker().multi().getPrecision())) {
// Goal precision reached!
return result;
} else {
@ -176,7 +174,7 @@ namespace storm {
thresholds[indexOfOptimizingObjective] = result + storm::utility::one<GeometryValueType>();
}
WeightVector separatingVector = this->findSeparatingVector(thresholds);
this->updateWeightedPrecisionInImprovingPhase(separatingVector);
this->updateWeightedPrecisionInImprovingPhase(env, separatingVector);
this->performRefinementStep(env, std::move(separatingVector));
}
STORM_LOG_ERROR("Could not reach the desired precision: Exceeded maximum number of refinement steps");
@ -185,11 +183,11 @@ namespace storm {
template <class SparseModelType, typename GeometryValueType>
void SparsePcaaQuantitativeQuery<SparseModelType, GeometryValueType>::updateWeightedPrecisionInImprovingPhase(WeightVector const& weights) {
void SparsePcaaQuantitativeQuery<SparseModelType, GeometryValueType>::updateWeightedPrecisionInImprovingPhase(Environment const& env, WeightVector const& weights) {
STORM_LOG_THROW(!storm::utility::isZero(weights[this->indexOfOptimizingObjective]), exceptions::UnexpectedException, "The chosen weight-vector gives zero weight for the objective that is to be optimized.");
// If weighs[indexOfOptimizingObjective] is low, the computation of the weightVectorChecker needs to be more precise.
// Our heuristic ensures that if p is the new vertex of the under-approximation, then max{ eps | p' = p + (0..0 eps 0..0) is in the over-approximation } <= multiobjective_precision/0.9
GeometryValueType weightedPrecision = weights[this->indexOfOptimizingObjective] * storm::utility::convertNumber<GeometryValueType>(storm::settings::getModule<storm::settings::modules::MultiObjectiveSettings>().getPrecision());
GeometryValueType weightedPrecision = weights[this->indexOfOptimizingObjective] * storm::utility::convertNumber<GeometryValueType>(env.modelchecker().multi().getPrecision());
// Normalize by division with the Euclidean Norm of the weight-vector
weightedPrecision /= storm::utility::sqrt(storm::utility::vector::dotProduct(weights, weights));
weightedPrecision *= storm::utility::convertNumber<GeometryValueType>(0.9);

2
src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.h

@ -45,7 +45,7 @@ namespace storm {
* Updates the precision of the weightVectorChecker w.r.t. the provided weights
*/
void updateWeightedPrecisionInAchievabilityPhase(WeightVector const& weights);
void updateWeightedPrecisionInImprovingPhase(WeightVector const& weights);
void updateWeightedPrecisionInImprovingPhase(Environment const& env, WeightVector const& weights);
/*
* Given that the thresholds are achievable, this function further refines the approximations and returns the optimized value

29
src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.cpp

@ -5,8 +5,7 @@
#include "storm/models/sparse/MarkovAutomaton.h"
#include "storm/models/sparse/StandardRewardModel.h"
#include "storm/modelchecker/multiobjective/Objective.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/modules/MultiObjectiveSettings.h"
#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h"
#include "storm/storage/geometry/Hyperrectangle.h"
#include "storm/utility/constants.h"
#include "storm/utility/vector.h"
@ -126,9 +125,9 @@ namespace storm {
}
template <class SparseModelType, typename GeometryValueType>
bool SparsePcaaQuery<SparseModelType, GeometryValueType>::maxStepsPerformed() const {
return storm::settings::getModule<storm::settings::modules::MultiObjectiveSettings>().isMaxStepsSet() &&
this->refinementSteps.size() >= storm::settings::getModule<storm::settings::modules::MultiObjectiveSettings>().getMaxSteps();
bool SparsePcaaQuery<SparseModelType, GeometryValueType>::maxStepsPerformed(Environment const& env) const {
return env.modelchecker().multi().isMaxStepsSet() &&
this->refinementSteps.size() >= env.modelchecker().multi().getMaxSteps();
}
@ -191,7 +190,7 @@ namespace storm {
}
template<typename SparseModelType, typename GeometryValueType>
void SparsePcaaQuery<SparseModelType, GeometryValueType>::exportPlotOfCurrentApproximation(std::string const& destinationDir) const {
void SparsePcaaQuery<SparseModelType, GeometryValueType>::exportPlotOfCurrentApproximation(Environment const& env) const {
STORM_LOG_ERROR_COND(objectives.size()==2, "Exporting plot requested but this is only implemented for the two-dimensional case.");
@ -223,35 +222,33 @@ namespace storm {
std::vector<std::string> columnHeaders = {"x", "y"};
std::vector<std::vector<double>> pointsForPlotting;
if (env.modelchecker().multi().getPlotPathUnderApproximation()) {
underApproxVertices = transformedUnderApprox->intersection(boundariesAsPolytope)->getVerticesInClockwiseOrder();
pointsForPlotting.reserve(underApproxVertices.size());
for(auto const& v : underApproxVertices) {
pointsForPlotting.push_back(storm::utility::vector::convertNumericVector<double>(v));
}
storm::utility::exportDataToCSVFile<double, std::string>(destinationDir + "underapproximation.csv", pointsForPlotting, columnHeaders);
storm::utility::exportDataToCSVFile<double, std::string>(env.modelchecker().multi().getPlotPathUnderApproximation().get(), pointsForPlotting, columnHeaders);
}
if (env.modelchecker().multi().getPlotPathOverApproximation()) {
pointsForPlotting.clear();
overApproxVertices = transformedOverApprox->intersection(boundariesAsPolytope)->getVerticesInClockwiseOrder();
pointsForPlotting.reserve(overApproxVertices.size());
for(auto const& v : overApproxVertices) {
pointsForPlotting.push_back(storm::utility::vector::convertNumericVector<double>(v));
}
storm::utility::exportDataToCSVFile<double, std::string>(destinationDir + "overapproximation.csv", pointsForPlotting, columnHeaders);
storm::utility::exportDataToCSVFile<double, std::string>(env.modelchecker().multi().getPlotPathOverApproximation().get(), pointsForPlotting, columnHeaders);
}
if (env.modelchecker().multi().getPlotPathParetoPoints()) {
pointsForPlotting.clear();
pointsForPlotting.reserve(paretoPoints.size());
for(auto const& v : paretoPoints) {
pointsForPlotting.push_back(storm::utility::vector::convertNumericVector<double>(v));
}
storm::utility::exportDataToCSVFile<double, std::string>(destinationDir + "paretopoints.csv", pointsForPlotting, columnHeaders);
pointsForPlotting.clear();
auto boundVertices = boundariesAsPolytope->getVerticesInClockwiseOrder();
pointsForPlotting.reserve(4);
for(auto const& v : boundVertices) {
pointsForPlotting.push_back(storm::utility::vector::convertNumericVector<double>(v));
storm::utility::exportDataToCSVFile<double, std::string>(env.modelchecker().multi().getPlotPathParetoPoints().get(), pointsForPlotting, columnHeaders);
}
storm::utility::exportDataToCSVFile<double, std::string>(destinationDir + "boundaries.csv", pointsForPlotting, columnHeaders);
}
#ifdef STORM_HAVE_CARL

4
src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.h

@ -38,7 +38,7 @@ namespace storm {
* Note that the approximations will be intersected with a (sufficiently large) hyperrectangle in order to ensure that the polytopes are bounded
* This only works for 2 dimensional queries.
*/
void exportPlotOfCurrentApproximation(std::string const& destinationDir) const;
void exportPlotOfCurrentApproximation(Environment const& env) const;
protected:
@ -87,7 +87,7 @@ namespace storm {
/*
* Returns true iff the maximum number of refinement steps (as possibly specified in the settings) has been reached
*/
bool maxStepsPerformed() const;
bool maxStepsPerformed(Environment const& env) const;
/*
* Transforms the given point (or polytope) to values w.r.t. the original model/formula (e.g. negates values for minimizing objectives).

4
src/storm/models/sparse/Model.cpp

@ -423,11 +423,7 @@ namespace storm {
template<typename ValueType, typename RewardModelType>
bool Model<ValueType, RewardModelType>::supportsParameters() const {
#ifdef STORM_HAVE_CARL
return std::is_same<ValueType, storm::RationalFunction>::value;
#else
return false;
#endif
}
template<typename ValueType, typename RewardModelType>

21
src/storm/models/symbolic/Model.cpp

@ -15,6 +15,7 @@
#include "storm/models/symbolic/StandardRewardModel.h"
#include "storm/utility/constants.h"
#include "storm/utility/macros.h"
#include "storm/utility/dd.h"
@ -363,6 +364,26 @@ namespace storm {
return true;
}
template<storm::dd::DdType Type, typename ValueType>
bool Model<Type, ValueType>::supportsParameters() const {
return std::is_same<ValueType, storm::RationalFunction>::value;
}
template<storm::dd::DdType Type, typename ValueType>
bool Model<Type, ValueType>::hasParameters() const {
if (!this->supportsParameters()) {
return false;
}
// Check for parameters
for (auto it = this->getTransitionMatrix().begin(false); it != this->getTransitionMatrix().end(); ++it) {
if (!storm::utility::isConstant((*it).second)) {
return true;
}
}
// Only constant values present
return false;
}
template<storm::dd::DdType Type, typename ValueType>
void Model<Type, ValueType>::addParameters(std::set<storm::RationalFunctionVariable> const& parameters) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This value type does not support parameters.");

10
src/storm/models/symbolic/Model.h

@ -321,6 +321,16 @@ namespace storm {
virtual bool isSymbolicModel() const override;
virtual bool supportsParameters() const override;
/*!
* Checks whether the model has parameters.
* Performance warning: the worst-case complexity is linear in the number of transitions.
*
* @return True iff the model has parameters.
*/
virtual bool hasParameters() const override;
std::vector<std::string> getLabels() const;
void addParameters(std::set<storm::RationalFunctionVariable> const& parameters);

33
src/storm/storage/MaximalEndComponentDecomposition.cpp

@ -80,6 +80,19 @@ namespace storm {
endComponentStateSets.emplace_back(states.begin(), states.end(), true);
}
storm::storage::BitVector statesToCheck(numberOfStates);
storm::storage::BitVector includedChoices;
if (choices) {
includedChoices = *choices;
} else if (states) {
includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount());
for (auto state : *states) {
for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) {
includedChoices.set(choice, true);
}
}
} else {
includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount(), true);
}
for (std::list<StateBlock>::const_iterator mecIterator = endComponentStateSets.begin(); mecIterator != endComponentStateSets.end();) {
StateBlock const& mec = *mecIterator;
@ -88,7 +101,7 @@ namespace storm {
bool mecChanged = false;
// Get an SCC decomposition of the current MEC candidate.
StronglyConnectedComponentDecomposition<ValueType> sccs(transitionMatrix, mec, true);
StronglyConnectedComponentDecomposition<ValueType> sccs(transitionMatrix, mec, includedChoices, true);
// We need to do another iteration in case we have either more than once SCC or the SCC is smaller than
// the MEC canditate itself.
@ -105,11 +118,17 @@ namespace storm {
bool keepStateInMEC = false;
for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) {
// If the choice is not part of our subsystem, skip it.
if (choices && !choices->get(choice)) {
continue;
}
// If the choice is not included any more, skip it.
if (!includedChoices.get(choice)) {
continue;
}
bool choiceContainedInMEC = true;
for (auto const& entry : transitionMatrix.getRow(choice)) {
if (storm::utility::isZero(entry.getValue())) {
@ -117,6 +136,7 @@ namespace storm {
}
if (!scc.containsState(entry.getColumn())) {
includedChoices.set(choice, false);
choiceContainedInMEC = false;
break;
}
@ -125,7 +145,6 @@ namespace storm {
// If there is at least one choice whose successor states are fully contained in the MEC, we can leave the state in the MEC.
if (choiceContainedInMEC) {
keepStateInMEC = true;
break;
}
}
@ -185,15 +204,7 @@ namespace storm {
continue;
}
bool choiceContained = true;
for (auto const& entry : transitionMatrix.getRow(choice)) {
if (!mecStateSet.containsState(entry.getColumn())) {
choiceContained = false;
break;
}
}
if (choiceContained) {
if (includedChoices.get(choice)) {
containedChoices.insert(choice);
}
}

90
src/storm/storage/StronglyConnectedComponentDecomposition.cpp

@ -23,30 +23,40 @@ namespace storm {
template <typename RewardModelType>
StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<ValueType, RewardModelType> const& model, StateBlock const& block, bool dropNaiveSccs, bool onlyBottomSccs) {
storm::storage::BitVector subsystem(model.getNumberOfStates(), block.begin(), block.end());
performSccDecomposition(model.getTransitionMatrix(), subsystem, dropNaiveSccs, onlyBottomSccs);
performSccDecomposition(model.getTransitionMatrix(), &subsystem, nullptr, dropNaiveSccs, onlyBottomSccs);
}
template <typename ValueType>
template <typename RewardModelType>
StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(storm::models::sparse::Model<ValueType, RewardModelType> const& model, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs) {
performSccDecomposition(model.getTransitionMatrix(), subsystem, dropNaiveSccs, onlyBottomSccs);
performSccDecomposition(model.getTransitionMatrix(), &subsystem, nullptr, dropNaiveSccs, onlyBottomSccs);
}
template <typename ValueType>
StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, StateBlock const& block, bool dropNaiveSccs, bool onlyBottomSccs) {
storm::storage::BitVector subsystem(transitionMatrix.getRowGroupCount(), block.begin(), block.end());
performSccDecomposition(transitionMatrix, subsystem, dropNaiveSccs, onlyBottomSccs);
performSccDecomposition(transitionMatrix, &subsystem, nullptr, dropNaiveSccs, onlyBottomSccs);
}
template <typename ValueType>
StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, StateBlock const& block, storm::storage::BitVector const& choices, bool dropNaiveSccs, bool onlyBottomSccs) {
storm::storage::BitVector subsystem(transitionMatrix.getRowGroupCount(), block.begin(), block.end());
performSccDecomposition(transitionMatrix, &subsystem, &choices, dropNaiveSccs, onlyBottomSccs);
}
template <typename ValueType>
StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, bool dropNaiveSccs, bool onlyBottomSccs) {
performSccDecomposition(transitionMatrix, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true), dropNaiveSccs, onlyBottomSccs);
performSccDecomposition(transitionMatrix, nullptr, nullptr, dropNaiveSccs, onlyBottomSccs);
}
template <typename ValueType>
StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs) {
performSccDecomposition(transitionMatrix, subsystem, dropNaiveSccs, onlyBottomSccs);
performSccDecomposition(transitionMatrix, &subsystem, nullptr, dropNaiveSccs, onlyBottomSccs);
}
template <typename ValueType>
StronglyConnectedComponentDecomposition<ValueType>::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& choices, bool dropNaiveSccs, bool onlyBottomSccs) {
performSccDecomposition(transitionMatrix, &subsystem, &choices, dropNaiveSccs, onlyBottomSccs);
}
template <typename ValueType>
@ -72,7 +82,10 @@ namespace storm {
}
template <typename ValueType>
void StronglyConnectedComponentDecomposition<ValueType>::performSccDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs) {
void StronglyConnectedComponentDecomposition<ValueType>::performSccDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const* subsystem, storm::storage::BitVector const* choices, bool dropNaiveSccs, bool onlyBottomSccs) {
STORM_LOG_ASSERT(!choices || subsystem, "Expecting subsystem if choices are given.");
uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount();
// Set up the environment of the algorithm.
@ -94,17 +107,31 @@ namespace storm {
// Start the search for SCCs from every state in the block.
uint_fast64_t currentIndex = 0;
for (auto state : subsystem) {
if (subsystem) {
for (auto state : *subsystem) {
if (!hasPreorderNumber.get(state)) {
performSccDecompositionGCM(transitionMatrix, state, statesWithSelfLoop, subsystem, currentIndex, hasPreorderNumber, preorderNumbers, s, p, stateHasScc, stateToSccMapping, sccCount);
performSccDecompositionGCM(transitionMatrix, state, statesWithSelfLoop, subsystem, choices, currentIndex, hasPreorderNumber, preorderNumbers, s, p, stateHasScc, stateToSccMapping, sccCount);
}
}
} else {
for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) {
if (!hasPreorderNumber.get(state)) {
performSccDecompositionGCM(transitionMatrix, state, statesWithSelfLoop, subsystem, choices, currentIndex, hasPreorderNumber, preorderNumbers, s, p, stateHasScc, stateToSccMapping, sccCount);
}
}
}
// After we obtained the state-to-SCC mapping, we build the actual blocks.
this->blocks.resize(sccCount);
for (auto state : subsystem) {
if (subsystem) {
for (auto state : *subsystem) {
this->blocks[stateToSccMapping[state]].insert(state);
}
} else {
for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) {
this->blocks[stateToSccMapping[state]].insert(state);
}
}
// Now flag all trivial SCCs as such.
for (uint_fast64_t sccIndex = 0; sccIndex < sccCount; ++sccIndex) {
@ -132,11 +159,16 @@ namespace storm {
// If requested, we need to drop all non-bottom SCCs.
if (onlyBottomSccs) {
for (uint_fast64_t state = 0; state < numberOfStates; ++state) {
if (subsystem) {
for (uint64_t state : *subsystem) {
// If the block of the state is already known to be dropped, we don't need to check the transitions.
if (!blocksToDrop.get(stateToSccMapping[state])) {
for (typename storm::storage::SparseMatrix<ValueType>::const_iterator successorIt = transitionMatrix.getRowGroup(state).begin(), successorIte = transitionMatrix.getRowGroup(state).end(); successorIt != successorIte; ++successorIt) {
if (subsystem.get(successorIt->getColumn()) && stateToSccMapping[state] != stateToSccMapping[successorIt->getColumn()]) {
for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row != endRow; ++row) {
if (choices && !choices->get(row)) {
continue;
}
for (auto const& entry : transitionMatrix.getRow(row)) {
if (subsystem->get(entry.getColumn()) && stateToSccMapping[state] != stateToSccMapping[entry.getColumn()]) {
blocksToDrop.set(stateToSccMapping[state]);
break;
}
@ -144,6 +176,22 @@ namespace storm {
}
}
}
} else {
for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) {
// If the block of the state is already known to be dropped, we don't need to check the transitions.
if (!blocksToDrop.get(stateToSccMapping[state])) {
for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row != endRow; ++row) {
for (auto const& entry : transitionMatrix.getRow(row)) {
if (stateToSccMapping[state] != stateToSccMapping[entry.getColumn()]) {
blocksToDrop.set(stateToSccMapping[state]);
break;
}
}
}
}
}
}
}
// Create the new set of blocks by moving all the blocks we need to keep into it.
std::vector<block_type> newBlocks((~blocksToDrop).getNumberOfSetBits());
@ -163,15 +211,11 @@ namespace storm {
template <typename ValueType>
template <typename RewardModelType>
void StronglyConnectedComponentDecomposition<ValueType>::performSccDecomposition(storm::models::sparse::Model<ValueType, RewardModelType> const& model, bool dropNaiveSccs, bool onlyBottomSccs) {
// Prepare a block that contains all states for a call to the other overload of this function.
storm::storage::BitVector fullSystem(model.getNumberOfStates(), true);
// Call the overloaded function.
performSccDecomposition(model.getTransitionMatrix(), fullSystem, dropNaiveSccs, onlyBottomSccs);
performSccDecomposition(model.getTransitionMatrix(), nullptr, nullptr, dropNaiveSccs, onlyBottomSccs);
}
template <typename ValueType>
void StronglyConnectedComponentDecomposition<ValueType>::performSccDecompositionGCM(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& statesWithSelfLoop, storm::storage::BitVector const& subsystem, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector<uint_fast64_t>& preorderNumbers, std::vector<uint_fast64_t>& s, std::vector<uint_fast64_t>& p, storm::storage::BitVector& stateHasScc, std::vector<uint_fast64_t>& stateToSccMapping, uint_fast64_t& sccCount) {
void StronglyConnectedComponentDecomposition<ValueType>::performSccDecompositionGCM(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& statesWithSelfLoop, storm::storage::BitVector const* subsystem, storm::storage::BitVector const* choices, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector<uint_fast64_t>& preorderNumbers, std::vector<uint_fast64_t>& s, std::vector<uint_fast64_t>& p, storm::storage::BitVector& stateHasScc, std::vector<uint_fast64_t>& stateToSccMapping, uint_fast64_t& sccCount) {
// Prepare the stack used for turning the recursive procedure into an iterative one.
std::vector<uint_fast64_t> recursionStateStack;
@ -190,8 +234,13 @@ namespace storm {
s.push_back(currentState);
p.push_back(currentState);
for (auto const& successor : transitionMatrix.getRowGroup(currentState)) {
if (subsystem.get(successor.getColumn()) && successor.getValue() != storm::utility::zero<ValueType>()) {
for (uint64_t row = transitionMatrix.getRowGroupIndices()[currentState], rowEnd = transitionMatrix.getRowGroupIndices()[currentState + 1]; row != rowEnd; ++row) {
if (choices && !choices->get(row)) {
continue;
}
for (auto const& successor : transitionMatrix.getRow(row)) {
if ((!subsystem || subsystem->get(successor.getColumn())) && successor.getValue() != storm::utility::zero<ValueType>()) {
if (currentState == successor.getColumn()) {
statesWithSelfLoop.set(currentState);
}
@ -209,6 +258,7 @@ namespace storm {
}
}
}
}
} else {
// In this case, we have searched all successors of the current state and can exit the "recursion"
// on the current state.

38
src/storm/storage/StronglyConnectedComponentDecomposition.h

@ -79,6 +79,20 @@ namespace storm {
*/
StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, StateBlock const& block, bool dropNaiveSccs = false, bool onlyBottomSccs = false);
/*
* Creates an SCC decomposition of the given subsystem in the given system (whose transition relation is
* given by a sparse matrix).
*
* @param transitionMatrix The transition matrix of the system to decompose.
* @param block The block to decompose into SCCs.
* @param choices A bit vector indicating which choices of the states are contained in the subsystem.
* @param dropNaiveSccs A flag that indicates whether trivial SCCs (i.e. SCCs consisting of just one state
* without a self-loop) are to be kept in the decomposition.
* @param onlyBottomSccs If set to true, only bottom SCCs, i.e. SCCs in which all states have no way of
* leaving the SCC), are kept.
*/
StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, StateBlock const& block, storm::storage::BitVector const& choices, bool dropNaiveSccs = false, bool onlyBottomSccs = false);
/*
* Creates an SCC decomposition of the given system (whose transition relation is given by a sparse matrix).
*
@ -103,6 +117,20 @@ namespace storm {
*/
StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& subsystem, bool dropNaiveSccs = false, bool onlyBottomSccs = false);
/*
* Creates an SCC decomposition of the given subsystem in the given system (whose transition relation is
* given by a sparse matrix).
*
* @param transitionMatrix The transition matrix of the system to decompose.
* @param subsystem A bit vector indicating which subsystem to consider for the decomposition into SCCs.
* @param choices A bit vector indicating which choices of the states are contained in the subsystem.
* @param dropNaiveSccs A flag that indicates whether trivial SCCs (i.e. SCCs consisting of just one state
* without a self-loop) are to be kept in the decomposition.
* @param onlyBottomSccs If set to true, only bottom SCCs, i.e. SCCs in which all states have no way of
* leaving the SCC), are kept.
*/
StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& choices, bool dropNaiveSccs = false, bool onlyBottomSccs = false);
/*!
* Creates an SCC decomposition by copying the given SCC decomposition.
*
@ -158,13 +186,14 @@ namespace storm {
* the vector of blocks of the decomposition.
*
* @param transitionMatrix The transition matrix of the system to decompose.
* @param subsystem A bit vector indicating which subsystem to consider for the decomposition into SCCs.
* @param subsystem An optional bit vector indicating which subsystem to consider.
* @param choices An optional bit vector indicating which choices belong to the subsystem.
* @param dropNaiveSccs A flag that indicates whether trivial SCCs (i.e. SCCs consisting of just one state
* without a self-loop) are to be kept in the decomposition.
* @param onlyBottomSccs If set to true, only bottom SCCs, i.e. SCCs in which all states have no way of
* leaving the SCC), are kept.
*/
void performSccDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs);
void performSccDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const* subsystem, storm::storage::BitVector const* choices, bool dropNaiveSccs, bool onlyBottomSccs);
/*!
* Uses the algorithm by Gabow/Cheriyan/Mehlhorn ("Path-based strongly connected component algorithm") to
@ -175,7 +204,8 @@ namespace storm {
* @param startState The starting state for the search of Tarjan's algorithm.
* @param statesWithSelfLoop A bit vector that is to be filled with all states that have a self-loop. This
* is later needed for identification of the naive SCCs.
* @param subsystem The subsystem to search.
* @param subsystem An optional bit vector indicating which subsystem to consider.
* @param choices An optional bit vector indicating which choices belong to the subsystem.
* @param currentIndex The next free index that can be assigned to states.
* @param hasPreorderNumber A bit that is used to keep track of the states that already have a preorder number.
* @param preorderNumbers A vector storing the preorder number for each state.
@ -187,7 +217,7 @@ namespace storm {
* @param sccCount The number of SCCs that have been computed. As a side effect of this function, this count
* is increased.
*/
void performSccDecompositionGCM(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& statesWithSelfLoop, storm::storage::BitVector const& subsystem, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector<uint_fast64_t>& preorderNumbers, std::vector<uint_fast64_t>& s, std::vector<uint_fast64_t>& p, storm::storage::BitVector& stateHasScc, std::vector<uint_fast64_t>& stateToSccMapping, uint_fast64_t& sccCount);
void performSccDecompositionGCM(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& statesWithSelfLoop, storm::storage::BitVector const* subsystem, storm::storage::BitVector const* choices, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector<uint_fast64_t>& preorderNumbers, std::vector<uint_fast64_t>& s, std::vector<uint_fast64_t>& p, storm::storage::BitVector& stateHasScc, std::vector<uint_fast64_t>& stateToSccMapping, uint_fast64_t& sccCount);
};
}
}

43
src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp

@ -3,7 +3,11 @@
#include "storm/parser/AutoParser.h"
#include "storm/storage/MaximalEndComponentDecomposition.h"
#include "storm/models/sparse/MarkovAutomaton.h"
#include "storm/models/sparse/Mdp.h"
#include "storm/models/sparse/StandardRewardModel.h"
#include "storm/builder/ExplicitModelBuilder.h"
#include "storm/storage/SymbolicModelDescription.h"
#include "storm/parser/PrismParser.h"
TEST(MaximalEndComponentDecomposition, FullSystem1) {
std::shared_ptr<storm::models::sparse::Model<double>> abstractModel = storm::parser::AutoParser<>::parseModel(STORM_TEST_RESOURCES_DIR "/tra/tiny1.tra", STORM_TEST_RESOURCES_DIR "/lab/tiny1.lab", "", "");
@ -133,3 +137,42 @@ TEST(MaximalEndComponentDecomposition, Subsystem) {
ASSERT_TRUE(false);
}
}
TEST(MaximalEndComponentDecomposition, Example1) {
std::string prismModelPath = STORM_TEST_RESOURCES_DIR "/mdp/prism-mec-example1.nm";
storm::storage::SymbolicModelDescription modelDescription = storm::parser::PrismParser::parse(prismModelPath);
storm::prism::Program program = modelDescription.preprocess().asPrismProgram();
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitModelBuilder<double>(program).build();
std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = model->as<storm::models::sparse::Mdp<double>>();
storm::storage::MaximalEndComponentDecomposition<double> mecDecomposition(*mdp);
EXPECT_EQ(mecDecomposition.size(), 2);
ASSERT_TRUE(mecDecomposition[0].getStateSet() == storm::storage::MaximalEndComponent::set_type{2});
EXPECT_TRUE(mecDecomposition[0].getChoicesForState(2) == storm::storage::MaximalEndComponent::set_type{3});
ASSERT_TRUE(mecDecomposition[1].getStateSet() == storm::storage::MaximalEndComponent::set_type{0});
EXPECT_TRUE(mecDecomposition[1].getChoicesForState(0) == storm::storage::MaximalEndComponent::set_type{0});
}
TEST(MaximalEndComponentDecomposition, Example2) {
std::string prismModelPath = STORM_TEST_RESOURCES_DIR "/mdp/prism-mec-example2.nm";
storm::storage::SymbolicModelDescription modelDescription = storm::parser::PrismParser::parse(prismModelPath);
storm::prism::Program program = modelDescription.preprocess().asPrismProgram();
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitModelBuilder<double>(program).build();
std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = model->as<storm::models::sparse::Mdp<double>>();
storm::storage::MaximalEndComponentDecomposition<double> mecDecomposition(*mdp);
EXPECT_EQ(mecDecomposition.size(), 2);
ASSERT_TRUE(mecDecomposition[0].getStateSet() == storm::storage::MaximalEndComponent::set_type{2});
EXPECT_TRUE(mecDecomposition[0].getChoicesForState(2) == storm::storage::MaximalEndComponent::set_type{4});
ASSERT_TRUE((mecDecomposition[1].getStateSet() == storm::storage::MaximalEndComponent::set_type{0, 1}));
EXPECT_TRUE((mecDecomposition[1].getChoicesForState(0) == storm::storage::MaximalEndComponent::set_type{0, 1}));
EXPECT_TRUE((mecDecomposition[1].getChoicesForState(1) == storm::storage::MaximalEndComponent::set_type{3}));
}
Loading…
Cancel
Save