Browse Source

Merge remote-tracking branch 'origin/master' into choicelabels

main
TimQu 8 years ago
parent
commit
9bc55e3107
  1. 22
      CMakeLists.txt
  2. 21
      resources/3rdparty/CMakeLists.txt
  3. 26
      src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp
  4. 33
      src/storm-gspn/parser/PnmlParser.cpp
  5. 1
      src/storm/adapters/CarlAdapter.h
  6. 10
      src/storm/adapters/MathsatExpressionAdapter.h
  7. 20
      src/storm/adapters/Z3ExpressionAdapter.cpp
  8. 113
      src/storm/analysis/GraphConditions.cpp
  9. 76
      src/storm/analysis/GraphConditions.h
  10. 8
      src/storm/cli/entrypoints.h
  11. 499
      src/storm/generator/JaniNextStateGenerator.cpp
  12. 45
      src/storm/generator/JaniNextStateGenerator.h
  13. 50
      src/storm/generator/VariableInformation.cpp
  14. 8
      src/storm/generator/VariableInformation.h
  15. 4
      src/storm/logic/VariableSubstitutionVisitor.cpp
  16. 15
      src/storm/modelchecker/CheckTask.h
  17. 11
      src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp
  18. 95
      src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp
  19. 22
      src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h
  20. 2
      src/storm/modelchecker/multiobjective/pcaa.cpp
  21. 28
      src/storm/modelchecker/multiobjective/pcaa/SparseMaPcaaWeightVectorChecker.cpp
  22. 6
      src/storm/modelchecker/multiobjective/pcaa/SparseMaPcaaWeightVectorChecker.h
  23. 2
      src/storm/modelchecker/multiobjective/pcaa/SparsePcaaAchievabilityQuery.cpp
  24. 2
      src/storm/modelchecker/multiobjective/pcaa/SparsePcaaParetoQuery.cpp
  25. 1
      src/storm/modelchecker/multiobjective/pcaa/SparsePcaaPreprocessor.cpp
  26. 2
      src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.cpp
  27. 6
      src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.cpp
  28. 16
      src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.cpp
  29. 56
      src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp
  30. 42
      src/storm/models/sparse/Dtmc.cpp
  31. 54
      src/storm/models/sparse/Dtmc.h
  32. 19
      src/storm/models/sparse/MarkovAutomaton.cpp
  33. 11
      src/storm/models/sparse/NondeterministicModel.cpp
  34. 75
      src/storm/parser/DeterministicSparseTransitionParser.cpp
  35. 3
      src/storm/parser/DeterministicSparseTransitionParser.h
  36. 3
      src/storm/settings/ArgumentValidators.cpp
  37. 90
      src/storm/storage/BitVector.cpp
  38. 16
      src/storm/storage/BitVector.h
  39. 28
      src/storm/storage/SparseMatrix.cpp
  40. 13
      src/storm/storage/SparseMatrix.h
  41. 8
      src/storm/storage/expressions/SimpleValuation.cpp
  42. 4
      src/storm/storage/expressions/Valuation.cpp
  43. 8
      src/storm/storage/expressions/Valuation.h
  44. 4
      src/storm/storage/geometry/nativepolytopeconversion/QuickHull.cpp
  45. 11
      src/storm/transformer/GoalStateMerger.cpp
  46. 4
      src/storm/transformer/SparseParametricModelSimplifier.cpp
  47. 18
      src/storm/utility/storm.h
  48. 20
      src/storm/utility/vector.h
  49. 15
      src/test/storage/BitVectorTest.cpp

22
CMakeLists.txt

@ -27,12 +27,13 @@ option(STORM_USE_LTO "Sets whether link-time optimizations are enabled." ON)
MARK_AS_ADVANCED(STORM_USE_LTO)
option(STORM_PORTABLE "Sets whether a build needs to be portable." OFF)
MARK_AS_ADVANCED(STORM_PORTABLE)
option(STORM_USE_POPCNT "Sets whether the popcnt instruction is going to be used." ON)
MARK_AS_ADVANCED(STORM_USE_POPCNT)
# Force POPCNT is helpful for portable code targetting platforms with SSE4.2 operation support.
option(STORM_FORCE_POPCNT "Sets whether the popcnt instruction is forced to be used (advanced)." OFF)
MARK_AS_ADVANCED(STORM_FORCE_POPCNT)
option(USE_BOOST_STATIC_LIBRARIES "Sets whether the Boost libraries should be linked statically." OFF)
option(STORM_USE_INTELTBB "Sets whether the Intel TBB libraries should be used." OFF)
option(STORM_USE_GUROBI "Sets whether Gurobi should be used." OFF)
option(USE_CARL "Sets whether carl should be included." ON)
set(USE_CARL ON)
option(STORM_FORCE_SHIPPED_CARL "Sets whether the shipped version of carl is to be used no matter whether carl is found or not." OFF)
MARK_AS_ADVANCED(STORM_FORCE_SHIPPED_CARL)
option(USE_SMTRAT "Sets whether SMT-RAT should be included." OFF)
@ -198,7 +199,7 @@ endif()
## Compiler independent settings
##
#############################################################
if (STORM_USE_POPCNT)
if (STORM_FORCE_POPCNT)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mpopcnt")
endif()
@ -397,9 +398,18 @@ else()
else()
set(STORM_VERSION_DIRTY "false")
endif()
message(STATUS "Storm - version is ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH} (${STORM_VERSION_COMMITS_AHEAD} commits ahead of tag), building from git: ${STORM_VERSION_GIT_HASH} (dirty: ${STORM_VERSION_DIRTY}).")
set(STORM_VERSION_DEV_STRING "")
if(STORM_VERSION_COMMITS_AHEAD)
MATH(EXPR STORM_VERSION_DEV_PATCH "${STORM_VERSION_PATCH}+1")
set(STORM_VERSION_DEV_STRING "(dev)")
else()
set(STORM_VERSION_DEV_PATCH ${STORM_VERSION_PATCH})
endif()
message(STATUS "Storm - version is ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_DEV_PATCH}${STORM_VERSION_DEV_STRING} (version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH} + ${STORM_VERSION_COMMITS_AHEAD} commits), building from git: ${STORM_VERSION_GIT_HASH} (dirty: ${STORM_VERSION_DIRTY}).")
endif()
set(STORM_VERSION "${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}")
set(STORM_VERSION "${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_DEV_PATCH}")
# Configure a header file to pass some of the CMake settings to the source code

21
resources/3rdparty/CMakeLists.txt

@ -213,15 +213,17 @@ if(USE_CARL)
set(STORM_SHIPPED_CARL OFF)
set(STORM_HAVE_CARL ON)
message(STATUS "Storm - Use system version of carl.")
message(STATUS "Storm - Linking with carl ${carl_VERSION} (CARL_USE_CLN_NUMBERS: ${CARL_USE_CLN_NUMBERS}).")
message(STATUS "Storm - Linking with carl ${carl_VERSION} (CARL_USE_CLN_NUMBERS: ${CARL_USE_CLN_NUMBERS}, CARL_USE_GINAC: ${CARL_USE_GINAC}).")
set(STORM_HAVE_CLN ${CARL_USE_CLN_NUMBERS})
set(STORM_HAVE_GINAC ${CARL_USE_GINAC})
else()
set(STORM_SHIPPED_CARL ON)
# The first external project will be built at *configure stage*
message("START CARL CONFIG PROCESS")
file(MAKE_DIRECTORY ${STORM_3RDPARTY_BINARY_DIR}/carl_download)
execute_process(
COMMAND ${CMAKE_COMMAND} ${STORM_3RDPARTY_SOURCE_DIR}/carl "-DSTORM_3RDPARTY_BINARY_DIR=${STORM_3RDPARTY_BINARY_DIR}" "-DCARL_USE_CLN_NUMBERS=ON" "-DBoost_LIBRARY_DIRS=${Boost_LIBRARY_DIRS}" "-DBoost_INCLUDE_DIRS=${Boost_INCLUDE_DIRS}" "-DTHREAD_SAFE=ON"
COMMAND ${CMAKE_COMMAND} ${STORM_3RDPARTY_SOURCE_DIR}/carl "-DSTORM_3RDPARTY_BINARY_DIR=${STORM_3RDPARTY_BINARY_DIR}" "-DUSE_CLN_NUMBERS=ON" "-DUSE_GINAC=ON" "-DBoost_LIBRARY_DIRS=${Boost_LIBRARY_DIRS}" "-DBoost_INCLUDE_DIRS=${Boost_INCLUDE_DIRS}" "-DTHREAD_SAFE=ON"
WORKING_DIRECTORY ${STORM_3RDPARTY_BINARY_DIR}/carl_download
OUTPUT_VARIABLE carlconfig_out
RESULT_VARIABLE carlconfig_result)
@ -253,8 +255,12 @@ if(USE_CARL)
BUILD_BYPRODUCTS ${STORM_3RDPARTY_BINARY_DIR}/carl/lib/libcarl${DYNAMIC_EXT}
)
include(${STORM_3RDPARTY_BINARY_DIR}/carl/carlConfig.cmake)
message("CARL_USE_CLN_NUMBERS: ${CARL_USE_CLN_NUMBERS}")
set(STORM_HAVE_CLN ${CARL_USE_CLN_NUMBERS})
message("CARL_USE_CLN_NUMBERS: ${CARL_USE_CLN_NUMBERS}, CARL_USE_GINAC: ${CARL_USE_GINAC}")
set(STORM_HAVE_CLN ${CARL_USE_CLN_NUMBERS})
set(STORM_HAVE_GINAC ${CARL_USE_GINAC})
add_dependencies(resources carl)
set(carl_INCLUDE_DIR "${STORM_3RDPARTY_BINARY_DIR}/carl/include/")
set(carl_LIBRARIES ${STORM_3RDPARTY_BINARY_DIR}/carl/lib/libcarl${DYNAMIC_EXT})
@ -263,15 +269,20 @@ if(USE_CARL)
# install the carl dynamic library if we build it
install(FILES ${STORM_3RDPARTY_BINARY_DIR}/carl/lib/libcarl.1.0.0${DYNAMIC_EXT} DESTINATION lib)
endif()
if(STORM_USE_CLN_RF AND NOT STORM_HAVE_CLN)
message(FATAL_ERROR "Cannot use CLN numbers if carl is build without.")
endif()
if(STORM_USE_CLN_RF AND NOT STORM_HAVE_GINAC)
message(FATAL_ERROR "Cannot use CLN numbers if carl is build without ginac.")
endif()
#The library that needs symbols must be first, then the library that resolves the symbol.
list(APPEND STORM_DEP_IMP_TARGETS lib_carl)
if(STORM_USE_CLN_EA OR STORM_USE_CLN_RF)
list(APPEND STORM_DEP_IMP_TARGETS CLN_SHARED)
list(APPEND STORM_DEP_IMP_TARGETS GINAC_SHARED CLN_SHARED)
endif()
list(APPEND STORM_DEP_IMP_TARGETS GMPXX_SHARED GMP_SHARED)

26
src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp

@ -2,6 +2,8 @@
#ifdef STORM_HAVE_XERCES
#include <iostream>
#include <algorithm>
#include "storm-gspn/adapters/XercesAdapter.h"
@ -9,8 +11,18 @@
#include "storm/exceptions/WrongFormatException.h"
#include "storm/utility/macros.h"
namespace {
bool isOnlyWhitespace(std::string const& in) {
return std::all_of(in.begin(), in.end(), [](char c){
return std::isspace(static_cast<unsigned char>(c));
});
}
}
namespace storm {
namespace parser {
storm::gspn::GSPN* GreatSpnEditorProjectParser::parse(xercesc::DOMElement const* elementRoot) {
if (storm::adapters::XMLtoString(elementRoot->getTagName()) == "project") {
traverseProjectElement(elementRoot);
@ -46,7 +58,7 @@ namespace storm {
if (name.compare("gspn") == 0) {
traverseGspnElement(child);
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else {
// Found node or attribute which is at the moment nod handled by this parser.
@ -84,7 +96,7 @@ namespace storm {
traverseNodesElement(child);
} else if (name.compare("edges") == 0) {
traverseEdgesElement(child);
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else {
// Found node or attribute which is at the moment nod handled by this parser.
@ -114,7 +126,7 @@ namespace storm {
traversePlaceElement(child);
} else if(name.compare("transition") == 0) {
traverseTransitionElement(child);
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else {
// Found node or attribute which is at the moment nod handled by this parser.
@ -144,7 +156,7 @@ namespace storm {
if (name.compare("arc") == 0) {
traverseArcElement(child);
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else {
// Found node or attribute which is at the moment nod handled by this parser.
@ -192,7 +204,7 @@ namespace storm {
auto child = node->getChildNodes()->item(i);
auto name = storm::adapters::getName(child);
if (std::all_of(name.begin(), name.end(), isspace)) {
if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else {
// Found node or attribute which is at the moment nod handled by this parser.
@ -252,7 +264,7 @@ namespace storm {
auto child = node->getChildNodes()->item(i);
auto name = storm::adapters::getName(child);
if (std::all_of(name.begin(), name.end(), isspace)) {
if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else {
// Found node or attribute which is at the moment nod handled by this parser.
@ -325,7 +337,7 @@ namespace storm {
auto child = node->getChildNodes()->item(i);
auto name = storm::adapters::getName(child);
if (std::all_of(name.begin(), name.end(), isspace)) {
if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else if(ignoreArcChild(name)) {
// ignore

33
src/storm-gspn/parser/PnmlParser.cpp

@ -9,8 +9,19 @@
#include "storm/exceptions/WrongFormatException.h"
#include "storm/utility/macros.h"
namespace {
bool isOnlyWhitespace(std::string const& in) {
return std::all_of(in.begin(), in.end(), [](char c){
return std::isspace(static_cast<unsigned char>(c));
});
}
}
namespace storm {
namespace parser {
storm::gspn::GSPN * PnmlParser::parse(xercesc::DOMElement const* elementRoot ) {
if (storm::adapters::getName(elementRoot) == "pnml") {
traversePnmlElement(elementRoot);
@ -39,7 +50,7 @@ namespace storm {
if (name == "net") {
traverseNetOrPage(child);
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else {
// Found node or attribute which is at the moment nod handled by this parser.
@ -79,7 +90,7 @@ namespace storm {
// Some pnml files have a child named page.
// The page node has the same children like the net node (e.g., place, transition, arc)
traverseNetOrPage(child);
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else {
// Found node or attribute which is at the moment nod handled by this parser.
@ -120,7 +131,7 @@ namespace storm {
} else if(name == "capacity") {
capacity.first = true;
capacity.second = traverseCapacity(child);
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else if (name == "name" ||
name == "graphics") {
@ -179,7 +190,7 @@ namespace storm {
timed.second = traverseTransitionType(child);
} else if (name == "priority") {
priority = traversePriority(child);
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else if (name == "graphics" ||
name == "name" ||
@ -255,7 +266,7 @@ namespace storm {
} else if(name == "inscription") {
multiplicity.first = true;
multiplicity.second = traverseMultiplicity(child);
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else if (name == "graphics" || name == "arcpath" || name == "tagged") {
// ignore these tags
@ -304,7 +315,7 @@ namespace storm {
auto value = storm::adapters::getName(child->getFirstChild());
value = value.substr(std::string("Default,").length());
result = std::stoull(value);
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else if (name == "graphics") {
// ignore these tags
@ -330,7 +341,7 @@ namespace storm {
result = std::stoull(value);
} else if (name == "graphics") {
// ignore these nodes
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else {
// Found node or attribute which is at the moment nod handled by this parser.
@ -354,7 +365,7 @@ namespace storm {
result = std::stoull(value);
} else if (name == "graphics") {
// ignore these nodes
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else {
// Found node or attribute which is at the moment nod handled by this parser.
@ -373,7 +384,7 @@ namespace storm {
auto name = storm::adapters::getName(child);
if (name == "value") {
result = storm::adapters::getName(child->getFirstChild());
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else {
// Found node or attribute which is at the moment nod handled by this parser.
@ -391,7 +402,7 @@ namespace storm {
auto name = storm::adapters::getName(child);
if (name == "value") {
result = storm::adapters::getName(child->getFirstChild()) == "true" ? true : false;
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else {
// Found node or attribute which is at the moment nod handled by this parser.
@ -428,7 +439,7 @@ namespace storm {
auto value = storm::adapters::getName(child->getFirstChild());
value = value.substr(std::string("Default,").length());
result = std::stoull(value);
} else if (std::all_of(name.begin(), name.end(), isspace)) {
} else if (isOnlyWhitespace(name)) {
// ignore node (contains only whitespace)
} else if (name == "graphics") {
// ignore these tags

1
src/storm/adapters/CarlAdapter.h

@ -9,6 +9,7 @@
#include <carl/core/Relation.h>
#include <carl/core/SimpleConstraint.h>
#include <carl/util/stringparser.h>
#include <carl/formula/Formula.h>
namespace carl {
// Define hash values for all polynomials and rational function.

10
src/storm/adapters/MathsatExpressionAdapter.h

@ -13,6 +13,7 @@
#include "storage/expressions/Expressions.h"
#include "storage/expressions/ExpressionVisitor.h"
#include "storm/utility/macros.h"
#include "storm/utility/constants.h"
#include "storm/exceptions/ExpressionEvaluationException.h"
#include "storm/exceptions/InvalidTypeException.h"
#include "storm/exceptions/InvalidArgumentException.h"
@ -181,7 +182,9 @@ namespace storm {
}
virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const&) override {
return msat_make_number(env, std::to_string(expression.getValueAsDouble()).c_str());
std::stringstream fractionStream;
fractionStream << expression.getValue();
return msat_make_number(env, fractionStream.str().c_str());
}
virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const&) override {
@ -250,10 +253,13 @@ namespace storm {
msat_free(name);
return result;
} else if (msat_term_is_number(env, term)) {
char* termAsCString = msat_term_repr(term);
std::string termString(termAsCString);
msat_free(termAsCString);
if (msat_is_integer_type(env, msat_term_get_type(term))) {
return manager.integer(std::stoll(msat_term_repr(term)));
} else if (msat_is_rational_type(env, msat_term_get_type(term))) {
return manager.rational(std::stod(msat_term_repr(term)));
return manager.rational(storm::utility::convertNumber<storm::RationalNumber>(termString));
}
}

20
src/storm/adapters/Z3ExpressionAdapter.cpp

@ -54,6 +54,24 @@ namespace storm {
return manager.boolean(false);
case Z3_OP_EQ:
return this->translateExpression(expr.arg(0)) == this->translateExpression(expr.arg(1));
case Z3_OP_DISTINCT: {
unsigned args = expr.num_args();
STORM_LOG_THROW(args != 0, storm::exceptions::ExpressionEvaluationException, "Failed to convert Z3 expression. DISTINCT (mutual != ) operator with 0-arity is assumed to be an error.");
if (args == 1) {
return manager.boolean(true);
} else {
storm::expressions::Expression retVal = this->translateExpression(expr.arg(0)) != this->translateExpression(expr.arg(1));
for (unsigned arg2 = 2; arg2 < args; ++arg2) {
retVal = retVal && (this->translateExpression(expr.arg(0)) != this->translateExpression(expr.arg(arg2)));
}
for (unsigned arg1 = 1; arg1 < args; ++arg1) {
for (unsigned arg2 = arg1 + 1; arg2 < args; ++arg2) {
retVal = retVal && (this->translateExpression(expr.arg(arg1)) != this->translateExpression(expr.arg(arg2)));
}
}
return retVal;
}
}
case Z3_OP_ITE:
return storm::expressions::ite(this->translateExpression(expr.arg(0)), this->translateExpression(expr.arg(1)), this->translateExpression(expr.arg(2)));
case Z3_OP_AND: {
@ -133,7 +151,7 @@ namespace storm {
STORM_LOG_THROW(expr.is_const(), storm::exceptions::ExpressionEvaluationException, "Failed to convert Z3 expression. Encountered non-constant uninterpreted function.");
return manager.getVariable(expr.decl().name().str()).getExpression();
default:
STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Failed to convert Z3 expression. Encountered unhandled Z3_decl_kind " << expr.decl().kind() <<".");
STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Failed to convert Z3 expression. Encountered unhandled Z3_decl_kind " << expr.decl().decl_kind() <<".");
break;
}
} else {

113
src/storm/analysis/GraphConditions.cpp

@ -0,0 +1,113 @@
#include "GraphConditions.h"
#include "storm/utility/constants.h"
#include "storm/exceptions/NotImplementedException.h"
#include "storm/models/sparse/StandardRewardModel.h"
namespace storm {
namespace analysis {
template <typename ValueType>
ConstraintCollector<ValueType>::ConstraintCollector(storm::models::sparse::Dtmc<ValueType> const& dtmc) {
process(dtmc);
}
template <typename ValueType>
std::unordered_set<typename ConstraintType<ValueType>::val> const& ConstraintCollector<ValueType>::getWellformedConstraints() const {
return this->wellformedConstraintSet;
}
template <typename ValueType>
std::unordered_set<typename ConstraintType<ValueType>::val> const& ConstraintCollector<ValueType>::getGraphPreservingConstraints() const {
return this->graphPreservingConstraintSet;
}
template <typename ValueType>
void ConstraintCollector<ValueType>::wellformedRequiresNonNegativeEntries(std::vector<ValueType> const& vec) {
for(auto const& entry : vec) {
if (!storm::utility::isConstant(entry)) {
if (entry.denominator().isConstant()) {
if (entry.denominatorAsNumber() > 0) {
wellformedConstraintSet.emplace(entry.nominator().polynomial(), storm::CompareRelation::GEQ);
} else if (entry.denominatorAsNumber() < 0) {
wellformedConstraintSet.emplace(entry.nominator().polynomial(), storm::CompareRelation::LEQ);
} else {
assert(false); // Should fail before.
}
} else {
wellformedConstraintSet.emplace(entry.denominator().polynomial(), storm::CompareRelation::NEQ);
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Rational functions at state rewards not yet supported.");
}
}
}
}
template <typename ValueType>
void ConstraintCollector<ValueType>::process(storm::models::sparse::Dtmc<ValueType> const& dtmc) {
for(uint_fast64_t state = 0; state < dtmc.getNumberOfStates(); ++state) {
ValueType sum = storm::utility::zero<ValueType>();
for (auto const& transition : dtmc.getRows(state)) {
sum += transition.getValue();
if (!storm::utility::isConstant(transition.getValue())) {
if (transition.getValue().denominator().isConstant()) {
if (transition.getValue().denominatorAsNumber() > 0) {
wellformedConstraintSet.emplace((transition.getValue().nominator() - transition.getValue().denominator()).polynomial(), storm::CompareRelation::LEQ);
wellformedConstraintSet.emplace(transition.getValue().nominator().polynomial(), storm::CompareRelation::GEQ);
} else if (transition.getValue().denominatorAsNumber() < 0) {
wellformedConstraintSet.emplace((transition.getValue().nominator() - transition.getValue().denominator()).polynomial(), storm::CompareRelation::GEQ);
wellformedConstraintSet.emplace(transition.getValue().nominator().polynomial(), storm::CompareRelation::LEQ);
} else {
assert(false); // Should fail before.
}
} else {
wellformedConstraintSet.emplace(transition.getValue().denominator().polynomial(), storm::CompareRelation::NEQ);
wellformedConstraintSet.emplace(carl::FormulaType::ITE, typename ConstraintType<ValueType>::val(transition.getValue().nominator().polynomial(), storm::CompareRelation::GREATER), typename ConstraintType<ValueType>::val(transition.getValue().nominator().polynomial(), storm::CompareRelation::GEQ), typename ConstraintType<ValueType>::val(transition.getValue().nominator().polynomial(), storm::CompareRelation::LEQ));
}
graphPreservingConstraintSet.emplace(transition.getValue().nominator().polynomial(), storm::CompareRelation::NEQ);
}
}
STORM_LOG_ASSERT(!storm::utility::isConstant(sum) || storm::utility::isOne(sum), "If the sum is a constant, it must be equal to 1.");
if(!storm::utility::isConstant(sum)) {
wellformedConstraintSet.emplace((sum.nominator() - sum.denominator()).polynomial(), storm::CompareRelation::EQ);
}
}
for(auto const& rewModelEntry : dtmc.getRewardModels()) {
if (rewModelEntry.second.hasStateRewards()) {
wellformedRequiresNonNegativeEntries(rewModelEntry.second.getStateRewardVector());
}
if (rewModelEntry.second.hasStateActionRewards()) {
wellformedRequiresNonNegativeEntries(rewModelEntry.second.getStateActionRewardVector());
}
if (rewModelEntry.second.hasTransitionRewards()) {
for (auto const& entry : rewModelEntry.second.getTransitionRewardMatrix()) {
if(!entry.getValue().isConstant()) {
if (entry.getValue().denominator().isConstant()) {
if (entry.getValue().denominatorAsNumber() > 0) {
wellformedConstraintSet.emplace(entry.getValue().nominator().polynomial(), storm::CompareRelation::GEQ);
} else if (entry.getValue().denominatorAsNumber() < 0) {
wellformedConstraintSet.emplace(entry.getValue().nominator().polynomial(), storm::CompareRelation::LEQ);
} else {
assert(false); // Should fail before.
}
} else {
wellformedConstraintSet.emplace(entry.getValue().denominator().polynomial(), storm::CompareRelation::NEQ);
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Rational functions at transition rewards are not yet supported.");
}
}
}
}
}
}
template <typename ValueType>
void ConstraintCollector<ValueType>::operator()(storm::models::sparse::Dtmc<ValueType> const& dtmc) {
process(dtmc);
}
template class ConstraintCollector<storm::RationalFunction>;
}
}

76
src/storm/analysis/GraphConditions.h

@ -0,0 +1,76 @@
#pragma once
#include <type_traits>
#include <unordered_set>
#include "storm/adapters/CarlAdapter.h"
#include "storm/models/sparse/Dtmc.h"
namespace storm {
namespace analysis {
template <typename ValueType, typename Enable=void>
struct ConstraintType {
typedef storm::ArithConstraint<ValueType> val;
};
template<typename ValueType>
struct ConstraintType<ValueType, typename std::enable_if<std::is_same<storm::RationalFunction, ValueType>::value>::type> {
typedef carl::Formula<typename ValueType::PolyType::PolyType> val;
};
/**
* Class to collect constraints on parametric Markov chains.
*/
template<typename ValueType>
class ConstraintCollector {
private:
// A set of constraints that says that the DTMC actually has valid probability distributions in all states.
std::unordered_set<typename ConstraintType<ValueType>::val> wellformedConstraintSet;
// A set of constraints that makes sure that the underlying graph of the model does not change depending
// on the parameter values.
std::unordered_set<typename ConstraintType<ValueType>::val> graphPreservingConstraintSet;
void wellformedRequiresNonNegativeEntries(std::vector<ValueType> const&);
public:
/*!
* Constructs the a constraint collector for the given DTMC. The constraints are built and ready for
* retrieval after the construction.
*
* @param dtmc The DTMC for which to create the constraints.
*/
ConstraintCollector(storm::models::sparse::Dtmc<ValueType> const& dtmc);
/*!
* Returns the set of wellformed-ness constraints.
*
* @return The set of wellformed-ness constraints.
*/
std::unordered_set<typename ConstraintType<ValueType>::val> const& getWellformedConstraints() const;
/*!
* Returns the set of graph-preserving constraints.
*
* @return The set of graph-preserving constraints.
*/
std::unordered_set<typename ConstraintType<ValueType>::val> const& getGraphPreservingConstraints() const;
/*!
* Constructs the constraints for the given DTMC.
*
* @param dtmc The DTMC for which to create the constraints.
*/
void process(storm::models::sparse::Dtmc<ValueType> const& dtmc);
/*!
* Constructs the constraints for the given DTMC by calling the process method.
*
* @param dtmc The DTMC for which to create the constraints.
*/
void operator()(storm::models::sparse::Dtmc<ValueType> const& dtmc);
};
}
}

8
src/storm/cli/entrypoints.h

@ -1,10 +1,10 @@
#ifndef STORM_ENTRYPOINTS_H_H
#define STORM_ENTRYPOINTS_H_H
#pragma once
#include <type_traits>
#include "storm/utility/storm.h"
#include "storm/analysis/GraphConditions.h"
#include "storm/storage/SymbolicModelDescription.h"
#include "storm/utility/DirectEncodingExporter.h"
#include "storm/utility/Stopwatch.h"
@ -112,7 +112,7 @@ namespace storm {
}
if (storm::settings::getModule<storm::settings::modules::ParametricSettings>().exportResultToFile()) {
exportParametricResultToFile(result->asExplicitQuantitativeCheckResult<storm::RationalFunction>()[*model->getInitialStates().begin()], storm::models::sparse::Dtmc<storm::RationalFunction>::ConstraintCollector(*(model->template as<storm::models::sparse::Dtmc<storm::RationalFunction>>())), storm::settings::getModule<storm::settings::modules::ParametricSettings>().exportResultPath());
exportParametricResultToFile(result->asExplicitQuantitativeCheckResult<storm::RationalFunction>()[*model->getInitialStates().begin()], storm::analysis::ConstraintCollector<storm::RationalFunction>(*(model->template as<storm::models::sparse::Dtmc<storm::RationalFunction>>())), storm::settings::getModule<storm::settings::modules::ParametricSettings>().exportResultPath());
}
}
}
@ -469,5 +469,3 @@ namespace storm {
}
}
#endif //STORM_ENTRYPOINTS_H_H

499
src/storm/generator/JaniNextStateGenerator.cpp

@ -34,12 +34,9 @@ namespace storm {
template<typename ValueType, typename StateType>
JaniNextStateGenerator<ValueType, StateType>::JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options, bool) : NextStateGenerator<ValueType, StateType>(model.getExpressionManager(), options), model(model), rewardVariables(), hasStateActionRewards(false) {
STORM_LOG_THROW(model.hasStandardComposition(), storm::exceptions::WrongFormatException, "The explicit next-state generator currently does not support custom system compositions.");
STORM_LOG_THROW(!model.hasNonGlobalTransientVariable(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support automata-local transient variables.");
STORM_LOG_THROW(!model.usesAssignmentLevels(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support assignment levels.");
STORM_LOG_THROW(!this->options.isBuildChoiceLabelsSet(), storm::exceptions::InvalidSettingsException, "JANI next-state generator cannot generate choice labels.");
STORM_LOG_THROW(!model.reusesActionsInComposition(), storm::exceptions::InvalidArgumentException, "The jit JANI model builder currently does not support reusing actions in parallel composition");
// Lift the transient edge destinations. We can do so, as we know that there are no assignment levels (because that's not supported anyway).
if (this->model.hasTransientEdgeDestinationAssignments()) {
@ -47,9 +44,12 @@ namespace storm {
}
STORM_LOG_THROW(!this->model.hasTransientEdgeDestinationAssignments(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support transient edge destination assignments.");
// Only after checking validity of the program, we initialize the variable information.
// Create all synchronization-related information, e.g. the automata that are put in parallel.
this->createSynchronizationInformation();
// Now we are ready to initialize the variable information.
this->checkValid();
this->variableInformation = VariableInformation(model);
this->variableInformation = VariableInformation(model, this->parallelAutomata);
// Create a proper evalator.
this->evaluator = std::make_unique<storm::expressions::ExpressionEvaluator<ValueType>>(model.getManager());
@ -92,11 +92,6 @@ namespace storm {
// If there are terminal states we need to handle, we now need to translate all labels to expressions.
if (this->options.hasTerminalStates()) {
std::vector<std::reference_wrapper<storm::jani::Automaton const>> composedAutomata;
for (auto const& automaton : this->model.getAutomata()) {
composedAutomata.emplace_back(automaton);
}
for (auto const& expressionOrLabelAndBool : this->options.getTerminalStates()) {
if (expressionOrLabelAndBool.first.isExpression()) {
this->terminalStates.push_back(std::make_pair(expressionOrLabelAndBool.first.getExpression(), expressionOrLabelAndBool.second));
@ -110,7 +105,7 @@ namespace storm {
STORM_LOG_THROW(variable.isBooleanVariable(), storm::exceptions::InvalidSettingsException, "Terminal states refer to non-boolean variable '" << expressionOrLabelAndBool.first.getLabel() << "'.");
STORM_LOG_THROW(variable.isTransient(), storm::exceptions::InvalidSettingsException, "Terminal states refer to non-transient variable '" << expressionOrLabelAndBool.first.getLabel() << "'.");
this->terminalStates.push_back(std::make_pair(this->model.getLabelExpression(variable.asBooleanVariable(), composedAutomata), expressionOrLabelAndBool.second));
this->terminalStates.push_back(std::make_pair(this->model.getLabelExpression(variable.asBooleanVariable(), this->parallelAutomata), expressionOrLabelAndBool.second));
}
}
}
@ -177,15 +172,11 @@ namespace storm {
storm::utility::solver::SmtSolverFactory factory;
std::unique_ptr<storm::solver::SmtSolver> solver = factory.create(model.getExpressionManager());
std::vector<std::reference_wrapper<storm::jani::Automaton const>> allAutomata;
for (auto const& automaton : model.getAutomata()) {
allAutomata.push_back(automaton);
}
std::vector<storm::expressions::Expression> rangeExpressions = model.getAllRangeExpressions(allAutomata);
std::vector<storm::expressions::Expression> rangeExpressions = model.getAllRangeExpressions(this->parallelAutomata);
for (auto const& expression : rangeExpressions) {
solver->add(expression);
}
solver->add(model.getInitialStatesExpression(allAutomata));
solver->add(model.getInitialStatesExpression(this->parallelAutomata));
// Proceed as long as the solver can still enumerate initial states.
std::vector<StateType> initialStateIndices;
@ -213,9 +204,10 @@ namespace storm {
// Gather iterators to the initial locations of all the automata.
std::vector<std::set<uint64_t>::const_iterator> initialLocationsIts;
std::vector<std::set<uint64_t>::const_iterator> initialLocationsItes;
for (auto const& automaton : allAutomata) {
initialLocationsIts.push_back(automaton.get().getInitialLocationIndices().cbegin());
initialLocationsItes.push_back(automaton.get().getInitialLocationIndices().cend());
for (auto const& automatonRef : this->parallelAutomata) {
auto const& automaton = automatonRef.get();
initialLocationsIts.push_back(automaton.getInitialLocationIndices().cbegin());
initialLocationsItes.push_back(automaton.getInitialLocationIndices().cend());
}
storm::utility::combinatorics::forEach(initialLocationsIts, initialLocationsItes, [this,&initialState] (uint64_t index, uint64_t value) { setLocation(initialState, this->variableInformation.locationVariables[index], value); }, [&stateToIdCallback,&initialStateIndices,&initialState] () {
// Register initial state.
@ -287,7 +279,8 @@ namespace storm {
// need the state rewards then.
std::vector<ValueType> stateRewards(this->rewardVariables.size(), storm::utility::zero<ValueType>());
uint64_t automatonIndex = 0;
for (auto const& automaton : model.getAutomata()) {
for (auto const& automatonRef : this->parallelAutomata) {
auto const& automaton = automatonRef.get();
uint64_t currentLocationIndex = locations[automatonIndex];
storm::jani::Location const& location = automaton.getLocation(currentLocationIndex);
auto valueIt = stateRewards.begin();
@ -307,12 +300,7 @@ namespace storm {
// Get all choices for the state.
result.setExpanded();
std::vector<Choice<ValueType>> allChoices = getSilentActionChoices(locations, *this->state, stateToIdCallback);
std::vector<Choice<ValueType>> allLabeledChoices = getNonsilentActionChoices(locations, *this->state, stateToIdCallback);
for (auto& choice : allLabeledChoices) {
allChoices.push_back(std::move(choice));
}
std::vector<Choice<ValueType>> allChoices = getActionChoices(locations, *this->state, stateToIdCallback);
std::size_t totalNumberOfChoices = allChoices.size();
// If there is not a single choice, we return immediately, because the state has no behavior (other than
@ -366,239 +354,235 @@ namespace storm {
return result;
}
template<typename ValueType, typename StateType>
std::vector<Choice<ValueType>> JaniNextStateGenerator<ValueType, StateType>::getSilentActionChoices(std::vector<uint64_t> const& locations, CompressedState const& state, StateToIdCallback stateToIdCallback) {
std::vector<Choice<ValueType>> result;
Choice<ValueType> JaniNextStateGenerator<ValueType, StateType>::expandNonSynchronizingEdge(storm::jani::Edge const& edge, uint64_t outputActionIndex, uint64_t automatonIndex, CompressedState const& state, StateToIdCallback stateToIdCallback) {
// Determine the exit rate if it's a Markovian edge.
boost::optional<ValueType> exitRate = boost::none;
if (edge.hasRate()) {
exitRate = this->evaluator->asRational(edge.getRate());
}
// Iterate over all automata.
uint64_t automatonIndex = 0;
Choice<ValueType> choice(edge.getActionIndex(), static_cast<bool>(exitRate));
for (auto const& automaton : model.getAutomata()) {
uint64_t location = locations[automatonIndex];
// Iterate over all updates of the current command.
ValueType probabilitySum = storm::utility::zero<ValueType>();
for (auto const& destination : edge.getDestinations()) {
ValueType probability = this->evaluator->asRational(destination.getProbability());
// Iterate over all edges from the source location.
for (auto const& edge : automaton.getEdgesFromLocation(location)) {
// Skip the edge if it is labeled with a non-silent action.
if (edge.getActionIndex() != storm::jani::Model::SILENT_ACTION_INDEX) {
continue;
}
if (probability != storm::utility::zero<ValueType>()) {
// Obtain target state index and add it to the list of known states. If it has not yet been
// seen, we also add it to the set of states that have yet to be explored.
auto newState = applyUpdate(state, destination, this->variableInformation.locationVariables[automatonIndex]);
// Skip the command, if it is not enabled.
if (!this->evaluator->asBool(edge.getGuard())) {
continue;
}
StateType stateIndex = stateToIdCallback(applyUpdate(state, destination, this->variableInformation.locationVariables[automatonIndex]));
// Determine the exit rate if it's a Markovian edge.
boost::optional<ValueType> exitRate = boost::none;
if (edge.hasRate()) {
exitRate = this->evaluator->asRational(edge.getRate());
}
// Update the choice by adding the probability/target state to it.
probability = exitRate ? exitRate.get() * probability : probability;
choice.addProbability(stateIndex, probability);
result.push_back(Choice<ValueType>(edge.getActionIndex(), static_cast<bool>(exitRate)));
Choice<ValueType>& choice = result.back();
if (this->options.isExplorationChecksSet()) {
probabilitySum += probability;
}
}
}
// Create the state-action reward for the newly created choice.
performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&choice] (ValueType const& value) { choice.addReward(value); } );
if (this->options.isExplorationChecksSet()) {
// Check that the resulting distribution is in fact a distribution.
STORM_LOG_THROW(!this->isDiscreteTimeModel() || this->comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Probabilities do not sum to one for edge (actually sum to " << probabilitySum << ").");
}
return choice;
}
template<typename ValueType, typename StateType>
std::vector<Choice<ValueType>> JaniNextStateGenerator<ValueType, StateType>::expandSynchronizingEdgeCombination(AutomataEdgeSets const& edgeCombination, uint64_t outputActionIndex, CompressedState const& state, StateToIdCallback stateToIdCallback) {
std::vector<Choice<ValueType>> result;
if (this->options.isExplorationChecksSet()) {
// Check whether a global variable is written multiple times in any combination.
checkGlobalVariableWritesValid(edgeCombination);
}
std::vector<EdgeSet::const_iterator> iteratorList(edgeCombination.size());
// Initialize the list of iterators.
for (size_t i = 0; i < edgeCombination.size(); ++i) {
iteratorList[i] = edgeCombination[i].second.cbegin();
}
// As long as there is one feasible combination of commands, keep on expanding it.
bool done = false;
while (!done) {
boost::container::flat_map<CompressedState, ValueType>* currentTargetStates = new boost::container::flat_map<CompressedState, ValueType>();
boost::container::flat_map<CompressedState, ValueType>* newTargetStates = new boost::container::flat_map<CompressedState, ValueType>();
std::vector<ValueType> stateActionRewards(rewardVariables.size(), storm::utility::zero<ValueType>());
currentTargetStates->emplace(state, storm::utility::one<ValueType>());
for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) {
storm::jani::Edge const& edge = **iteratorList[i];
// Iterate over all updates of the current command.
ValueType probabilitySum = storm::utility::zero<ValueType>();
for (auto const& destination : edge.getDestinations()) {
ValueType probability = this->evaluator->asRational(destination.getProbability());
if (probability != storm::utility::zero<ValueType>()) {
// Obtain target state index and add it to the list of known states. If it has not yet been
// seen, we also add it to the set of states that have yet to be explored.
StateType stateIndex = stateToIdCallback(applyUpdate(state, destination, this->variableInformation.locationVariables[automatonIndex]));
// Update the choice by adding the probability/target state to it.
probability = exitRate ? exitRate.get() * probability : probability;
choice.addProbability(stateIndex, probability);
for (auto const& stateProbabilityPair : *currentTargetStates) {
// Compute the new state under the current update and add it to the set of new target states.
CompressedState newTargetState = applyUpdate(stateProbabilityPair.first, destination, this->variableInformation.locationVariables[edgeCombination[i].first]);
if (this->options.isExplorationChecksSet()) {
probabilitySum += probability;
// If the new state was already found as a successor state, update the probability
// and otherwise insert it.
ValueType probability = stateProbabilityPair.second * this->evaluator->asRational(destination.getProbability());
if (edge.hasRate()) {
probability *= this->evaluator->asRational(edge.getRate());
}
if (probability != storm::utility::zero<ValueType>()) {
auto targetStateIt = newTargetStates->find(newTargetState);
if (targetStateIt != newTargetStates->end()) {
targetStateIt->second += probability;
} else {
newTargetStates->emplace(newTargetState, probability);
}
}
}
// Create the state-action reward for the newly created choice.
auto valueIt = stateActionRewards.begin();
performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } );
}
// Create the state-action reward for the newly created choice.
performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&choice] (ValueType const& value) { choice.addReward(value); } );
// If there is one more command to come, shift the target states one time step back.
if (i < iteratorList.size() - 1) {
delete currentTargetStates;
currentTargetStates = newTargetStates;
newTargetStates = new boost::container::flat_map<CompressedState, ValueType>();
}
}
// At this point, we applied all commands of the current command combination and newTargetStates
// contains all target states and their respective probabilities. That means we are now ready to
// add the choice to the list of transitions.
result.emplace_back(outputActionIndex);
// Now create the actual distribution.
Choice<ValueType>& choice = result.back();
// Add the rewards to the choice.
choice.addRewards(std::move(stateActionRewards));
// Add the probabilities/rates to the newly created choice.
ValueType probabilitySum = storm::utility::zero<ValueType>();
for (auto const& stateProbabilityPair : *newTargetStates) {
StateType actualIndex = stateToIdCallback(stateProbabilityPair.first);
choice.addProbability(actualIndex, stateProbabilityPair.second);
if (this->options.isExplorationChecksSet()) {
// Check that the resulting distribution is in fact a distribution.
STORM_LOG_THROW(!this->isDiscreteTimeModel() || this->comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Probabilities do not sum to one for edge (actually sum to " << probabilitySum << ").");
probabilitySum += stateProbabilityPair.second;
}
}
++automatonIndex;
if (this->options.isExplorationChecksSet()) {
// Check that the resulting distribution is in fact a distribution.
STORM_LOG_THROW(!this->isDiscreteTimeModel() || !this->comparator.isConstant(probabilitySum) || this->comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Sum of update probabilities do not sum to one for some command (actually sum to " << probabilitySum << ").");
}
// Dispose of the temporary maps.
delete currentTargetStates;
delete newTargetStates;
// Now, check whether there is one more command combination to consider.
bool movedIterator = false;
for (uint64_t j = 0; !movedIterator && j < iteratorList.size(); ++j) {
++iteratorList[j];
if (iteratorList[j] != edgeCombination[j].second.end()) {
movedIterator = true;
} else {
// Reset the iterator to the beginning of the list.
iteratorList[j] = edgeCombination[j].second.begin();
}
}
done = !movedIterator;
}
return result;
}
template<typename ValueType, typename StateType>
std::vector<Choice<ValueType>> JaniNextStateGenerator<ValueType, StateType>::getNonsilentActionChoices(std::vector<uint64_t> const& locations, CompressedState const& state, StateToIdCallback stateToIdCallback) {
std::vector<Choice<ValueType>> JaniNextStateGenerator<ValueType, StateType>::getActionChoices(std::vector<uint64_t> const& locations, CompressedState const& state, StateToIdCallback stateToIdCallback) {
std::vector<Choice<ValueType>> result;
for (uint64_t actionIndex : model.getNonsilentActionIndices()) {
std::vector<std::vector<storm::jani::Edge const*>> enabledEdges = getEnabledEdges(locations, actionIndex);
// Only process this action, if there is at least one feasible solution.
if (!enabledEdges.empty()) {
if (this->options.isExplorationChecksSet()) {
// Check whether a global variable is written multiple times in any combination.
checkGlobalVariableWritesValid(enabledEdges);
for (auto const& outputAndEdges : edges) {
auto const& edges = outputAndEdges.second;
if (edges.size() == 1) {
// If the synch consists of just one element, it's non-synchronizing.
auto const& nonsychingEdges = edges.front();
uint64_t automatonIndex = nonsychingEdges.first;
auto edgesIt = nonsychingEdges.second.find(locations[automatonIndex]);
if (edgesIt != nonsychingEdges.second.end()) {
for (auto const& edge : edgesIt->second) {
if (!this->evaluator->asBool(edge->getGuard())) {
continue;
}
Choice<ValueType> choice = expandNonSynchronizingEdge(*edge, outputAndEdges.first ? outputAndEdges.first.get() : edge->getActionIndex(), automatonIndex, state, stateToIdCallback);
result.emplace_back(std::move(choice));
}
}
} else {
// If the element has more than one set of edges, we need to perform a synchronization.
STORM_LOG_ASSERT(outputAndEdges.first, "Need output action index for synchronization.");
std::vector<std::vector<storm::jani::Edge const*>::const_iterator> iteratorList(enabledEdges.size());
// Initialize the list of iterators.
for (size_t i = 0; i < enabledEdges.size(); ++i) {
iteratorList[i] = enabledEdges[i].cbegin();
}
AutomataEdgeSets automataEdgeSets;
uint64_t outputActionIndex = outputAndEdges.first.get();
// As long as there is one feasible combination of commands, keep on expanding it.
bool done = false;
while (!done) {
boost::container::flat_map<CompressedState, ValueType>* currentTargetStates = new boost::container::flat_map<CompressedState, ValueType>();
boost::container::flat_map<CompressedState, ValueType>* newTargetStates = new boost::container::flat_map<CompressedState, ValueType>();
std::vector<ValueType> stateActionRewards(rewardVariables.size(), storm::utility::zero<ValueType>());
bool productiveCombination = true;
for (auto const& automatonAndEdges : outputAndEdges.second) {
uint64_t automatonIndex = automatonAndEdges.first;
EdgeSet enabledEdgesOfAutomaton;
currentTargetStates->emplace(state, storm::utility::one<ValueType>());
auto locationVariableIt = this->variableInformation.locationVariables.cbegin();
for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) {
storm::jani::Edge const& edge = **iteratorList[i];
for (auto const& destination : edge.getDestinations()) {
for (auto const& stateProbabilityPair : *currentTargetStates) {
// Compute the new state under the current update and add it to the set of new target states.
CompressedState newTargetState = applyUpdate(stateProbabilityPair.first, destination, *locationVariableIt);
// If the new state was already found as a successor state, update the probability
// and otherwise insert it.
ValueType probability = stateProbabilityPair.second * this->evaluator->asRational(destination.getProbability());
if (edge.hasRate()) {
probability *= this->evaluator->asRational(edge.getRate());
}
if (probability != storm::utility::zero<ValueType>()) {
auto targetStateIt = newTargetStates->find(newTargetState);
if (targetStateIt != newTargetStates->end()) {
targetStateIt->second += probability;
} else {
newTargetStates->emplace(newTargetState, probability);
}
}
bool atLeastOneEdge = false;
auto edgesIt = automatonAndEdges.second.find(locations[automatonIndex]);
if (edgesIt != automatonAndEdges.second.end()) {
for (auto const& edge : edgesIt->second) {
if (!this->evaluator->asBool(edge->getGuard())) {
continue;
}
// Create the state-action reward for the newly created choice.
auto valueIt = stateActionRewards.begin();
performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } );
}
// If there is one more command to come, shift the target states one time step back.
if (i < iteratorList.size() - 1) {
delete currentTargetStates;
currentTargetStates = newTargetStates;
newTargetStates = new boost::container::flat_map<CompressedState, ValueType>();
}
++locationVariableIt;
}
// At this point, we applied all commands of the current command combination and newTargetStates
// contains all target states and their respective probabilities. That means we are now ready to
// add the choice to the list of transitions.
result.push_back(Choice<ValueType>(actionIndex));
// Now create the actual distribution.
Choice<ValueType>& choice = result.back();
// Add the rewards to the choice.
choice.addRewards(std::move(stateActionRewards));
// Add the probabilities/rates to the newly created choice.
ValueType probabilitySum = storm::utility::zero<ValueType>();
for (auto const& stateProbabilityPair : *newTargetStates) {
StateType actualIndex = stateToIdCallback(stateProbabilityPair.first);
choice.addProbability(actualIndex, stateProbabilityPair.second);
if (this->options.isExplorationChecksSet()) {
probabilitySum += stateProbabilityPair.second;
atLeastOneEdge = true;
enabledEdgesOfAutomaton.emplace_back(edge);
}
}
if (this->options.isExplorationChecksSet()) {
// Check that the resulting distribution is in fact a distribution.
STORM_LOG_THROW(!this->isDiscreteTimeModel() || !this->comparator.isConstant(probabilitySum) || this->comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Sum of update probabilities do not sum to one for some command (actually sum to " << probabilitySum << ").");
}
// Dispose of the temporary maps.
delete currentTargetStates;
delete newTargetStates;
// Now, check whether there is one more command combination to consider.
bool movedIterator = false;
for (uint64_t j = 0; !movedIterator && j < iteratorList.size(); ++j) {
++iteratorList[j];
if (iteratorList[j] != enabledEdges[j].end()) {
movedIterator = true;
} else {
// Reset the iterator to the beginning of the list.
iteratorList[j] = enabledEdges[j].begin();
}
// If there is no enabled edge of this automaton, the whole combination is not productive.
if (!atLeastOneEdge) {
productiveCombination = false;
break;
}
done = !movedIterator;
automataEdgeSets.emplace_back(std::make_pair(automatonIndex, std::move(enabledEdgesOfAutomaton)));
}
}
}
return result;
}
template<typename ValueType, typename StateType>
std::vector<std::vector<storm::jani::Edge const*>> JaniNextStateGenerator<ValueType, StateType>::getEnabledEdges(std::vector<uint64_t> const& locationIndices, uint64_t actionIndex) {
std::vector<std::vector<storm::jani::Edge const*>> result;
// Iterate over all automata.
uint64_t automatonIndex = 0;
for (auto const& automaton : model.getAutomata()) {
// If the automaton has no edge labeled with the given action, we can skip it.
if (!automaton.hasEdgeLabeledWithActionIndex(actionIndex)) {
continue;
}
auto edges = automaton.getEdgesFromLocation(locationIndices[automatonIndex], actionIndex);
// If the automaton contains the action, but there is no edge available labeled with
// this action, we don't have any feasible command combinations.
if (edges.empty()) {
return std::vector<std::vector<storm::jani::Edge const*>>();
}
std::vector<storm::jani::Edge const*> edgePointers;
for (auto const& edge : edges) {
if (this->evaluator->asBool(edge.getGuard())) {
edgePointers.push_back(&edge);
if (productiveCombination) {
std::vector<Choice<ValueType>> choices = expandSynchronizingEdgeCombination(automataEdgeSets, outputActionIndex, state, stateToIdCallback);
for (auto const& choice : choices) {
result.emplace_back(std::move(choice));
}
}
}
// If there was no enabled edge although the automaton has some edge with the required action, we must
// not return anything.
if (edgePointers.empty()) {
return std::vector<std::vector<storm::jani::Edge const*>>();
}
result.emplace_back(std::move(edgePointers));
++automatonIndex;
}
}
return result;
}
template<typename ValueType, typename StateType>
void JaniNextStateGenerator<ValueType, StateType>::checkGlobalVariableWritesValid(std::vector<std::vector<storm::jani::Edge const*>> const& enabledEdges) const {
void JaniNextStateGenerator<ValueType, StateType>::checkGlobalVariableWritesValid(AutomataEdgeSets const& enabledEdges) const {
std::map<storm::expressions::Variable, uint64_t> writtenGlobalVariables;
for (auto edgeSetIt = enabledEdges.begin(), edgeSetIte = enabledEdges.end(); edgeSetIt != edgeSetIte; ++edgeSetIt) {
for (auto const& edge : *edgeSetIt) {
for (auto const& edge : edgeSetIt->second) {
for (auto const& globalVariable : edge->getWrittenGlobalVariables()) {
auto it = writtenGlobalVariables.find(globalVariable);
@ -625,20 +609,13 @@ namespace storm {
template<typename ValueType, typename StateType>
storm::models::sparse::StateLabeling JaniNextStateGenerator<ValueType, StateType>::label(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices, std::vector<StateType> const& deadlockStateIndices) {
// Prepare a mapping from automata names to the location variables.
std::vector<std::reference_wrapper<storm::jani::Automaton const>> composedAutomata;
for (auto const& automaton : model.getAutomata()) {
composedAutomata.emplace_back(automaton);
}
// As in JANI we can use transient boolean variable assignments in locations to identify states, we need to
// create a list of boolean transient variables and the expressions that define them.
std::unordered_map<storm::expressions::Variable, storm::expressions::Expression> transientVariableToExpressionMap;
for (auto const& variable : model.getGlobalVariables().getTransientVariables()) {
if (variable.isBooleanVariable()) {
if (this->options.isBuildAllLabelsSet() || this->options.getLabelNames().find(variable.getName()) != this->options.getLabelNames().end()) {
transientVariableToExpressionMap[variable.getExpressionVariable()] = model.getLabelExpression(variable.asBooleanVariable(), composedAutomata);
transientVariableToExpressionMap[variable.getExpressionVariable()] = model.getLabelExpression(variable.asBooleanVariable(), this->parallelAutomata);
}
}
}
@ -687,7 +664,8 @@ namespace storm {
}
// Then fill them.
for (auto const& automaton : model.getAutomata()) {
for (auto const& automatonRef : this->parallelAutomata) {
auto const& automaton = automatonRef.get();
for (auto const& location : automaton.getLocations()) {
auto rewardVariableIt = rewardVariables.begin();
auto rewardVariableIte = rewardVariables.end();
@ -727,6 +705,81 @@ namespace storm {
}
}
template<typename ValueType, typename StateType>
void JaniNextStateGenerator<ValueType, StateType>::createSynchronizationInformation() {
// Create synchronizing edges information.
storm::jani::Composition const& topLevelComposition = this->model.getSystemComposition();
if (topLevelComposition.isAutomatonComposition()) {
auto const& automaton = this->model.getAutomaton(topLevelComposition.asAutomatonComposition().getAutomatonName());
this->parallelAutomata.push_back(automaton);
LocationsAndEdges locationsAndEdges;
for (auto const& edge : automaton.getEdges()) {
locationsAndEdges[edge.getSourceLocationIndex()].emplace_back(&edge);
}
AutomataAndEdges automataAndEdges;
automataAndEdges.emplace_back(std::make_pair(0, std::move(locationsAndEdges)));
this->edges.emplace_back(std::make_pair(boost::none, std::move(automataAndEdges)));
} else {
STORM_LOG_THROW(topLevelComposition.isParallelComposition(), storm::exceptions::WrongFormatException, "Expected parallel composition.");
storm::jani::ParallelComposition const& parallelComposition = topLevelComposition.asParallelComposition();
uint64_t automatonIndex = 0;
for (auto const& composition : parallelComposition.getSubcompositions()) {
STORM_LOG_THROW(composition->isAutomatonComposition(), storm::exceptions::WrongFormatException, "Expected flat parallel composition.");
this->parallelAutomata.push_back(this->model.getAutomaton(composition->asAutomatonComposition().getAutomatonName()));
// Add edges with silent action.
LocationsAndEdges locationsAndEdges;
for (auto const& edge : parallelAutomata.back().get().getEdges()) {
if (edge.getActionIndex() == storm::jani::Model::SILENT_ACTION_INDEX) {
locationsAndEdges[edge.getSourceLocationIndex()].emplace_back(&edge);
}
}
if (!locationsAndEdges.empty()) {
AutomataAndEdges automataAndEdges;
automataAndEdges.emplace_back(std::make_pair(automatonIndex, std::move(locationsAndEdges)));
this->edges.emplace_back(std::make_pair(boost::none, std::move(automataAndEdges)));
}
++automatonIndex;
}
for (auto const& vector : parallelComposition.getSynchronizationVectors()) {
uint64_t outputActionIndex = this->model.getActionIndex(vector.getOutput());
AutomataAndEdges automataAndEdges;
bool atLeastOneEdge = true;
uint64_t automatonIndex = 0;
for (auto const& element : vector.getInput()) {
if (!storm::jani::SynchronizationVector::isNoActionInput(element)) {
LocationsAndEdges locationsAndEdges;
uint64_t actionIndex = this->model.getActionIndex(element);
for (auto const& edge : parallelAutomata[automatonIndex].get().getEdges()) {
if (edge.getActionIndex() == actionIndex) {
locationsAndEdges[edge.getSourceLocationIndex()].emplace_back(&edge);
}
}
if (locationsAndEdges.empty()) {
atLeastOneEdge = false;
break;
}
automataAndEdges.emplace_back(std::make_pair(automatonIndex, std::move(locationsAndEdges)));
}
++automatonIndex;
}
if (atLeastOneEdge) {
this->edges.emplace_back(std::make_pair(outputActionIndex, std::move(automataAndEdges)));
}
}
}
STORM_LOG_TRACE("Number of synchronizations: " << this->edges.size() << ".");
}
template<typename ValueType, typename StateType>
void JaniNextStateGenerator<ValueType, StateType>::checkValid() const {
// If the program still contains undefined constants and we are not in a parametric setting, assemble an appropriate error message.

45
src/storm/generator/JaniNextStateGenerator.h

@ -66,35 +66,33 @@ namespace storm {
CompressedState applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& update, storm::generator::LocationVariableInformation const& locationVariable);
/*!
* Retrieves all choices labeled with the silent action possible from the given state.
* Retrieves all choices possible from the given state.
*
* @param locations The current locations of all automata.
* @param state The state for which to retrieve the silent choices.
* @return The silent action choices of the state.
* @return The action choices of the state.
*/
std::vector<Choice<ValueType>> getSilentActionChoices(std::vector<uint64_t> const& locations, CompressedState const& state, StateToIdCallback stateToIdCallback);
std::vector<Choice<ValueType>> getActionChoices(std::vector<uint64_t> const& locations, CompressedState const& state, StateToIdCallback stateToIdCallback);
/*!
* Retrieves all choices labeled with some non-silent action possible from the given state.
*
* @param locations THe current locations of all automata.
* @param state The state for which to retrieve the non-silent choices.
* @return The non-silent action choices of the state.
* Retrieves the choice generated by the given edge.
*/
std::vector<Choice<ValueType>> getNonsilentActionChoices(std::vector<uint64_t> const& locations, CompressedState const& state, StateToIdCallback stateToIdCallback);
Choice<ValueType> expandNonSynchronizingEdge(storm::jani::Edge const& edge, uint64_t outputActionIndex, uint64_t automatonIndex, CompressedState const& state, StateToIdCallback stateToIdCallback);
/*!
* Retrieves a list of lists of edges such that the list at index i are all edges of automaton i enabled in
* the current state. If the list is empty, it means there was at least one automaton containing edges with
* the desired action, but none of them were enabled.
*/
std::vector<std::vector<storm::jani::Edge const*>> getEnabledEdges(std::vector<uint64_t> const& locationIndices, uint64_t actionIndex);
typedef std::vector<storm::jani::Edge const*> EdgeSet;
typedef std::unordered_map<uint64_t, EdgeSet> LocationsAndEdges;
typedef std::vector<std::pair<uint64_t, LocationsAndEdges>> AutomataAndEdges;
typedef std::pair<boost::optional<uint64_t>, AutomataAndEdges> OutputAndEdges;
typedef std::pair<uint64_t, EdgeSet> AutomatonAndEdgeSet;
typedef std::vector<AutomatonAndEdgeSet> AutomataEdgeSets;
std::vector<Choice<ValueType>> expandSynchronizingEdgeCombination(AutomataEdgeSets const& edgeCombination, uint64_t outputActionIndex, CompressedState const& state, StateToIdCallback stateToIdCallback);
/*!
* Checks the list of enabled edges (obtained by a call to <code>getEnabledEdges</code>) for multiple
* synchronized writes to the same global variable.
* Checks the list of enabled edges for multiple synchronized writes to the same global variable.
*/
void checkGlobalVariableWritesValid(std::vector<std::vector<storm::jani::Edge const*>> const& enabledEdges) const;
void checkGlobalVariableWritesValid(AutomataEdgeSets const& enabledEdges) const;
/*!
* Treats the given transient assignments by calling the callback function whenever a transient assignment
@ -107,6 +105,11 @@ namespace storm {
*/
void buildRewardModelInformation();
/*!
* Creates the internal information about synchronizing edges.
*/
void createSynchronizationInformation();
/*!
* Checks the underlying model for validity for this next-state generator.
*/
@ -115,6 +118,12 @@ namespace storm {
/// The model used for the generation of next states.
storm::jani::Model model;
/// The automata that are put into parallel by this generator.
std::vector<std::reference_wrapper<storm::jani::Automaton const>> parallelAutomata;
/// The vector storing the edges that need to be explored (synchronously or asynchronously).
std::vector<OutputAndEdges> edges;
/// The transient variables of reward models that need to be considered.
std::vector<storm::expressions::Variable> rewardVariables;

50
src/storm/generator/VariableInformation.cpp

@ -4,10 +4,13 @@
#include "storm/storage/jani/Model.h"
#include "storm/storage/jani/Automaton.h"
#include "storm/storage/jani/AutomatonComposition.h"
#include "storm/storage/jani/ParallelComposition.h"
#include "storm/storage/expressions/ExpressionManager.h"
#include "storm/utility/macros.h"
#include "storm/exceptions/InvalidArgumentException.h"
#include "storm/exceptions/WrongFormatException.h"
#include <cmath>
@ -55,7 +58,7 @@ namespace storm {
sortVariables();
}
VariableInformation::VariableInformation(storm::jani::Model const& model) : totalBitOffset(0) {
VariableInformation::VariableInformation(storm::jani::Model const& model, std::vector<std::reference_wrapper<storm::jani::Automaton const>> const& parallelAutomata) : totalBitOffset(0) {
// Check that the model does not contain non-transient unbounded integer or non-transient real variables.
STORM_LOG_THROW(!model.getGlobalVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException, "Cannot build model from JANI model that contains global non-transient real variables.");
STORM_LOG_THROW(!model.getGlobalVariables().containsNonTransientUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException, "Cannot build model from JANI model that contains non-transient unbounded integer variables.");
@ -79,29 +82,34 @@ namespace storm {
totalBitOffset += bitwidth;
}
}
for (auto const& automaton : model.getAutomata()) {
uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(automaton.getNumberOfLocations())));
locationVariables.emplace_back(automaton.getLocationExpressionVariable(), automaton.getNumberOfLocations() - 1, totalBitOffset, bitwidth);
totalBitOffset += bitwidth;
for (auto const& variable : automaton.getVariables().getBooleanVariables()) {
if (!variable.isTransient()) {
booleanVariables.emplace_back(variable.getExpressionVariable(), totalBitOffset);
++totalBitOffset;
}
for (auto const& automatonRef : parallelAutomata) {
createVariablesForAutomaton(automatonRef.get());
}
sortVariables();
}
void VariableInformation::createVariablesForAutomaton(storm::jani::Automaton const& automaton) {
uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(automaton.getNumberOfLocations())));
locationVariables.emplace_back(automaton.getLocationExpressionVariable(), automaton.getNumberOfLocations() - 1, totalBitOffset, bitwidth);
totalBitOffset += bitwidth;
for (auto const& variable : automaton.getVariables().getBooleanVariables()) {
if (!variable.isTransient()) {
booleanVariables.emplace_back(variable.getExpressionVariable(), totalBitOffset);
++totalBitOffset;
}
for (auto const& variable : automaton.getVariables().getBoundedIntegerVariables()) {
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;
}
}
for (auto const& variable : automaton.getVariables().getBoundedIntegerVariables()) {
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;
}
}
sortVariables();
}
uint_fast64_t VariableInformation::getTotalBitOffset(bool roundTo64Bit) const {

8
src/storm/generator/VariableInformation.h

@ -13,6 +13,7 @@ namespace storm {
namespace jani {
class Model;
class Automaton;
}
namespace generator {
@ -74,7 +75,7 @@ namespace storm {
// A structure storing information about the used variables of the program.
struct VariableInformation {
VariableInformation(storm::prism::Program const& program);
VariableInformation(storm::jani::Model const& model);
VariableInformation(storm::jani::Model const& model, std::vector<std::reference_wrapper<storm::jani::Automaton const>> const& parallelAutomata);
VariableInformation() = default;
uint_fast64_t getTotalBitOffset(bool roundTo64Bit = false) const;
@ -96,6 +97,11 @@ namespace storm {
* Sorts the variables to establish a known ordering.
*/
void sortVariables();
/*!
* Creates all necessary variables for a JANI automaton.
*/
void createVariablesForAutomaton(storm::jani::Automaton const& automaton);
};
}

4
src/storm/logic/VariableSubstitutionVisitor.cpp

@ -50,11 +50,11 @@ namespace storm {
return std::static_pointer_cast<Formula>(std::make_shared<BoundedUntilFormula>(left, right, lowerBound, upperBound, f.getTimeBoundType()));
}
boost::any VariableSubstitutionVisitor::visit(CumulativeRewardFormula const& f, boost::any const& data) const {
boost::any VariableSubstitutionVisitor::visit(CumulativeRewardFormula const& f, boost::any const&) const {
return std::static_pointer_cast<Formula>(std::make_shared<CumulativeRewardFormula>(storm::logic::TimeBound(f.isBoundStrict(), f.getBound().substitute(substitution)), f.getTimeBoundType()));
}
boost::any VariableSubstitutionVisitor::visit(InstantaneousRewardFormula const& f, boost::any const& data) const {
boost::any VariableSubstitutionVisitor::visit(InstantaneousRewardFormula const& f, boost::any const&) const {
return std::static_pointer_cast<Formula>(std::make_shared<InstantaneousRewardFormula>(f.getBound().substitute(substitution), f.getTimeBoundType()));
}

15
src/storm/modelchecker/CheckTask.h

@ -52,7 +52,6 @@ namespace storm {
template<typename NewFormulaType>
CheckTask<NewFormulaType, ValueType> substituteFormula(NewFormulaType const& newFormula) const {
CheckTask<NewFormulaType, ValueType> result(newFormula, this->optimizationDirection, this->rewardModel, this->onlyInitialStatesRelevant, this->bound, this->qualitative, this->produceSchedulers, this->hint);
result.updateOperatorInformation();
return result;
}
@ -68,13 +67,13 @@ namespace storm {
}
if (operatorFormula.hasBound()) {
if (onlyInitialStatesRelevant) {
this->bound = operatorFormula.getBound();
}
if (!optimizationDirection) {
this->optimizationDirection = operatorFormula.getComparisonType() == storm::logic::ComparisonType::Less || operatorFormula.getComparisonType() == storm::logic::ComparisonType::LessEqual ? OptimizationDirection::Maximize : OptimizationDirection::Minimize;
}
this->bound = operatorFormula.getBound();
}
if (operatorFormula.hasOptimalityType()) {
this->optimizationDirection = operatorFormula.getOptimalityType();
} else if (operatorFormula.hasBound()) {
this->optimizationDirection = operatorFormula.getComparisonType() == storm::logic::ComparisonType::Less || operatorFormula.getComparisonType() == storm::logic::ComparisonType::LessEqual ? OptimizationDirection::Maximize : OptimizationDirection::Minimize;
}
if (formula.get().isProbabilityOperatorFormula()) {

11
src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp

@ -66,7 +66,7 @@ namespace storm {
upperBound = storm::utility::infinity<double>();
}
std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper<ValueType>::computeBoundedUntilProbabilities(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), rightResult.getTruthValuesVector(), std::make_pair(lowerBound, upperBound), *minMaxLinearEquationSolverFactory);
std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), rightResult.getTruthValuesVector(), std::make_pair(lowerBound, upperBound), *minMaxLinearEquationSolverFactory);
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(result)));
}
@ -78,7 +78,7 @@ namespace storm {
std::unique_ptr<CheckResult> rightResultPointer = this->check(pathFormula.getRightSubformula());
ExplicitQualitativeCheckResult& leftResult = leftResultPointer->asExplicitQualitativeCheckResult();
ExplicitQualitativeCheckResult& rightResult = rightResultPointer->asExplicitQualitativeCheckResult();
std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper<ValueType>::computeUntilProbabilities(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *minMaxLinearEquationSolverFactory);
std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeUntilProbabilities(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *minMaxLinearEquationSolverFactory);
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(result)));
}
@ -90,7 +90,7 @@ namespace storm {
std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula());
ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult();
std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper<ValueType>::computeReachabilityRewards(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory);
std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeReachabilityRewards(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory);
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(result)));
}
@ -103,7 +103,7 @@ namespace storm {
std::unique_ptr<CheckResult> subResultPointer = this->check(stateFormula);
ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult();
std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper<ValueType>::computeLongRunAverageProbabilities(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory);
std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory);
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(result)));
}
@ -115,7 +115,7 @@ namespace storm {
std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula());
ExplicitQualitativeCheckResult& subResult = subResultPointer->asExplicitQualitativeCheckResult();
std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper<ValueType>::computeTimes(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory);
std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeReachabilityTimes(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory);
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(result)));
}
@ -125,5 +125,6 @@ namespace storm {
}
template class SparseMarkovAutomatonCslModelChecker<storm::models::sparse::MarkovAutomaton<double>>;
template class SparseMarkovAutomatonCslModelChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>;
}
}

95
src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp

@ -16,22 +16,23 @@
#include "storm/storage/expressions/Variable.h"
#include "storm/storage/expressions/Expression.h"
#include "storm/storage/expressions/ExpressionManager.h"
#include "storm/utility/numerical.h"
#include "storm/solver/MinMaxLinearEquationSolver.h"
#include "storm/solver/LpSolver.h"
#include "storm/exceptions/InvalidStateException.h"
#include "storm/exceptions/InvalidPropertyException.h"
#include "storm/exceptions/InvalidOperationException.h"
namespace storm {
namespace modelchecker {
namespace helper {
template<typename ValueType>
void SparseMarkovAutomatonCslHelper<ValueType>::computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector<ValueType>& markovianNonGoalValues, std::vector<ValueType>& probabilisticNonGoalValues, ValueType delta, uint_fast64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
template <typename ValueType, typename std::enable_if<storm::NumberTraits<ValueType>::SupportsExponential, int>::type>
void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector<ValueType>& markovianNonGoalValues, std::vector<ValueType>& probabilisticNonGoalValues, ValueType delta, uint_fast64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
// Start by computing four sparse matrices:
// * a matrix aMarkovian with all (discretized) transitions from Markovian non-goal states to all Markovian non-goal states.
@ -116,9 +117,14 @@ namespace storm {
storm::utility::vector::addVectors(bProbabilistic, bProbabilisticFixed, bProbabilistic);
solver->solveEquations(dir, probabilisticNonGoalValues, bProbabilistic);
}
template<typename ValueType>
std::vector<ValueType> SparseMarkovAutomatonCslHelper<ValueType>::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
template <typename ValueType, typename std::enable_if<!storm::NumberTraits<ValueType>::SupportsExponential, int>::type>
void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector<ValueType>& markovianNonGoalValues, std::vector<ValueType>& probabilisticNonGoalValues, ValueType delta, uint_fast64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded reachability probabilities is unsupported for this value type.");
}
template <typename ValueType, typename std::enable_if<storm::NumberTraits<ValueType>::SupportsExponential, int>::type>
std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount();
@ -180,16 +186,20 @@ namespace storm {
return result;
}
}
template <typename ValueType, typename std::enable_if<!storm::NumberTraits<ValueType>::SupportsExponential, int>::type>
std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded until probabilities is unsupported for this value type.");
}
template<typename ValueType>
std::vector<ValueType> SparseMarkovAutomatonCslHelper<ValueType>::computeUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
return std::move(storm::modelchecker::helper::SparseMdpPrctlHelper<ValueType>::computeUntilProbabilities(dir, transitionMatrix, backwardTransitions, phiStates, psiStates, qualitative, false, minMaxLinearEquationSolverFactory).values);
}
template <typename ValueType>
template <typename RewardModelType>
std::vector<ValueType> SparseMarkovAutomatonCslHelper<ValueType>::computeReachabilityRewards(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
template <typename ValueType, typename RewardModelType>
std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeReachabilityRewards(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
std::vector<ValueType> stateRewardWeights(transitionMatrix.getRowGroupCount());
for (auto const markovianState : markovianStates) {
stateRewardWeights[markovianState] = storm::utility::one<ValueType>() / exitRateVector[markovianState];
@ -199,7 +209,7 @@ namespace storm {
}
template<typename ValueType>
std::vector<ValueType> SparseMarkovAutomatonCslHelper<ValueType>::computeLongRunAverageProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount();
// If there are no goal states, we avoid the computation and directly return zero.
@ -213,7 +223,7 @@ namespace storm {
}
// Start by decomposing the Markov automaton into its MECs.
storm::storage::MaximalEndComponentDecomposition<double> mecDecomposition(transitionMatrix, backwardTransitions);
storm::storage::MaximalEndComponentDecomposition<ValueType> mecDecomposition(transitionMatrix, backwardTransitions);
// Get some data members for convenience.
std::vector<uint_fast64_t> const& nondeterministicChoiceIndices = transitionMatrix.getRowGroupIndices();
@ -354,7 +364,7 @@ namespace storm {
}
template <typename ValueType>
std::vector<ValueType> SparseMarkovAutomatonCslHelper<ValueType>::computeTimes(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeReachabilityTimes(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
std::vector<ValueType> rewardValues(transitionMatrix.getRowCount(), storm::utility::zero<ValueType>());
for (auto const markovianState : markovianStates) {
rewardValues[transitionMatrix.getRowGroupIndices()[markovianState]] = storm::utility::one<ValueType>() / exitRateVector[markovianState];
@ -363,8 +373,7 @@ namespace storm {
}
template<typename ValueType>
std::vector<ValueType>
SparseMarkovAutomatonCslHelper<ValueType>::computeExpectedRewards(OptimizationDirection dir,
std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeExpectedRewards(OptimizationDirection dir,
storm::storage::SparseMatrix<ValueType> const &transitionMatrix,
storm::storage::SparseMatrix<ValueType> const &backwardTransitions,
storm::storage::BitVector const &goalStates,
@ -380,7 +389,7 @@ namespace storm {
// reach a bottom SCC without a goal state.
// So we start by computing all bottom SCCs without goal states.
storm::storage::StronglyConnectedComponentDecomposition<double> sccDecomposition(transitionMatrix,
storm::storage::StronglyConnectedComponentDecomposition<ValueType> sccDecomposition(transitionMatrix,
~goalStates, true,
true);
@ -408,7 +417,7 @@ namespace storm {
// If we maximize the property, the expected time of a state is infinite, if an end-component without any goal state is reachable.
// So we start by computing all MECs that have no goal state.
storm::storage::MaximalEndComponentDecomposition<double> mecDecomposition(transitionMatrix,
storm::storage::MaximalEndComponentDecomposition<ValueType> mecDecomposition(transitionMatrix,
backwardTransitions,
~goalStates);
@ -463,10 +472,9 @@ namespace storm {
return result;
}
template<typename ValueType>
ValueType SparseMarkovAutomatonCslHelper<ValueType>::computeLraForMaximalEndComponent(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& goalStates, storm::storage::MaximalEndComponent const& mec) {
ValueType SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& goalStates, storm::storage::MaximalEndComponent const& mec) {
std::unique_ptr<storm::utility::solver::LpSolverFactory> lpSolverFactory(new storm::utility::solver::LpSolverFactory());
std::unique_ptr<storm::solver::LpSolver> solver = lpSolverFactory->create("LRA for MEC");
solver->setOptimizationDirection(invert(dir));
@ -490,11 +498,11 @@ namespace storm {
storm::expressions::Expression constraint = stateToVariableMap.at(state);
for (auto element : transitionMatrix.getRow(nondeterministicChoiceIndices[state])) {
constraint = constraint - stateToVariableMap.at(element.getColumn()) * solver->getConstant(element.getValue());
constraint = constraint - stateToVariableMap.at(element.getColumn()) * solver->getManager().rational((element.getValue()));
}
constraint = constraint + solver->getConstant(storm::utility::one<ValueType>() / exitRateVector[state]) * k;
storm::expressions::Expression rightHandSide = goalStates.get(state) ? solver->getConstant(storm::utility::one<ValueType>() / exitRateVector[state]) : solver->getConstant(0);
constraint = constraint + solver->getManager().rational(storm::utility::one<ValueType>() / exitRateVector[state]) * k;
storm::expressions::Expression rightHandSide = goalStates.get(state) ? solver->getManager().rational(storm::utility::one<ValueType>() / exitRateVector[state]) : solver->getManager().rational(storm::utility::zero<ValueType>());
if (dir == OptimizationDirection::Minimize) {
constraint = constraint <= rightHandSide;
} else {
@ -508,10 +516,10 @@ namespace storm {
storm::expressions::Expression constraint = stateToVariableMap.at(state);
for (auto element : transitionMatrix.getRow(choice)) {
constraint = constraint - stateToVariableMap.at(element.getColumn()) * solver->getConstant(element.getValue());
constraint = constraint - stateToVariableMap.at(element.getColumn()) * solver->getManager().rational(element.getValue());
}
storm::expressions::Expression rightHandSide = solver->getConstant(storm::utility::zero<ValueType>());
storm::expressions::Expression rightHandSide = solver->getManager().rational(storm::utility::zero<ValueType>());
if (dir == OptimizationDirection::Minimize) {
constraint = constraint <= rightHandSide;
} else {
@ -523,12 +531,43 @@ namespace storm {
}
solver->optimize();
return solver->getContinuousValue(k);
return storm::utility::convertNumber<ValueType>(solver->getContinuousValue(k));
}
template class SparseMarkovAutomatonCslHelper<double>;
template std::vector<double> SparseMarkovAutomatonCslHelper<double>::computeReachabilityRewards(OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, std::vector<double> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel<double> const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<double> const& minMaxLinearEquationSolverFactory);
template std::vector<double> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, std::vector<double> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory<double> const& minMaxLinearEquationSolverFactory);
template std::vector<double> SparseMarkovAutomatonCslHelper::computeUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory<double> const& minMaxLinearEquationSolverFactory);
template std::vector<double> SparseMarkovAutomatonCslHelper::computeReachabilityRewards(OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, std::vector<double> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel<double> const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<double> const& minMaxLinearEquationSolverFactory);
template std::vector<double> SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, std::vector<double> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<double> const& minMaxLinearEquationSolverFactory);
template std::vector<double> SparseMarkovAutomatonCslHelper::computeReachabilityTimes(OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, std::vector<double> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<double> const& minMaxLinearEquationSolverFactory);
template void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, std::vector<double> const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector<double>& markovianNonGoalValues, std::vector<double>& probabilisticNonGoalValues, double delta, uint_fast64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory<double> const& minMaxLinearEquationSolverFactory);
template double SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, std::vector<double> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& goalStates, storm::storage::MaximalEndComponent const& mec);
template std::vector<double> SparseMarkovAutomatonCslHelper::computeExpectedRewards(OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, storm::storage::BitVector const& goalStates, std::vector<double> const& stateRewards, storm::solver::MinMaxLinearEquationSolverFactory<double> const& minMaxLinearEquationSolverFactory);
template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, std::vector<storm::RationalNumber> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory<storm::RationalNumber> const& minMaxLinearEquationSolverFactory);
template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory<storm::RationalNumber> const& minMaxLinearEquationSolverFactory);
template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeReachabilityRewards(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, std::vector<storm::RationalNumber> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel<storm::RationalNumber> const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<storm::RationalNumber> const& minMaxLinearEquationSolverFactory);
template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, std::vector<storm::RationalNumber> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<storm::RationalNumber> const& minMaxLinearEquationSolverFactory);
template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeReachabilityTimes(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, std::vector<storm::RationalNumber> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<storm::RationalNumber> const& minMaxLinearEquationSolverFactory);
template void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, std::vector<storm::RationalNumber> const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector<storm::RationalNumber>& markovianNonGoalValues, std::vector<storm::RationalNumber>& probabilisticNonGoalValues, storm::RationalNumber delta, uint_fast64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory<storm::RationalNumber> const& minMaxLinearEquationSolverFactory);
template storm::RationalNumber SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, std::vector<storm::RationalNumber> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& goalStates, storm::storage::MaximalEndComponent const& mec);
template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeExpectedRewards(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, storm::storage::BitVector const& goalStates, std::vector<storm::RationalNumber> const& stateRewards, storm::solver::MinMaxLinearEquationSolverFactory<storm::RationalNumber> const& minMaxLinearEquationSolverFactory);
}
}
}

22
src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h

@ -5,28 +5,40 @@
#include "storm/storage/MaximalEndComponent.h"
#include "storm/solver/OptimizationDirection.h"
#include "storm/solver/MinMaxLinearEquationSolver.h"
#include "storm/utility/NumberTraits.h"
namespace storm {
namespace modelchecker {
namespace helper {
template <typename ValueType>
class SparseMarkovAutomatonCslHelper {
public:
template <typename ValueType, typename std::enable_if<storm::NumberTraits<ValueType>::SupportsExponential, int>::type = 0>
static std::vector<ValueType> computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
template <typename ValueType, typename std::enable_if<!storm::NumberTraits<ValueType>::SupportsExponential, int>::type = 0>
static std::vector<ValueType> computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
template <typename ValueType>
static std::vector<ValueType> computeUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
template <typename RewardModelType>
template <typename ValueType, typename RewardModelType>
static std::vector<ValueType> computeReachabilityRewards(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
template <typename ValueType>
static std::vector<ValueType> computeLongRunAverageProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
static std::vector<ValueType> computeTimes(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
template <typename ValueType>
static std::vector<ValueType> computeReachabilityTimes(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
private:
template <typename ValueType, typename std::enable_if<storm::NumberTraits<ValueType>::SupportsExponential, int>::type = 0>
static void computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector<ValueType>& markovianNonGoalValues, std::vector<ValueType>& probabilisticNonGoalValues, ValueType delta, uint_fast64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
template <typename ValueType, typename std::enable_if<!storm::NumberTraits<ValueType>::SupportsExponential, int>::type = 0>
static void computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector<ValueType>& markovianNonGoalValues, std::vector<ValueType>& probabilisticNonGoalValues, ValueType delta, uint_fast64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
/*!
@ -35,12 +47,13 @@ namespace storm {
* @param dir Sets whether the long-run average is to be minimized or maximized.
* @param transitionMatrix The transition matrix of the underlying Markov automaton.
* @param markovianStates A bit vector storing all markovian states.
* @param exitRateVector A vector with exit rates for all states. Exit rates of probabilistic states are
* @param exitRateVector A vector with exit rates for all states. Exit rates of probabilistic states are
* assumed to be zero.
* @param goalStates A bit vector indicating which states are to be considered as goal states.
* @param mec The maximal end component to consider for computing the long-run average.
* @return The long-run average of being in a goal state for the given MEC.
*/
template <typename ValueType>
static ValueType computeLraForMaximalEndComponent(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& goalStates, storm::storage::MaximalEndComponent const& mec);
/*!
@ -56,6 +69,7 @@ namespace storm {
* of the state.
* @return A vector that contains the expected reward for each state of the model.
*/
template <typename ValueType>
static std::vector<ValueType> computeExpectedRewards(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& goalStates, std::vector<ValueType> const& stateRewards, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
};

2
src/storm/modelchecker/multiobjective/pcaa.cpp

@ -80,7 +80,7 @@ namespace storm {
template std::unique_ptr<CheckResult> performPcaa<storm::models::sparse::MarkovAutomaton<double>>(storm::models::sparse::MarkovAutomaton<double> const& model, storm::logic::MultiObjectiveFormula const& formula);
#ifdef STORM_HAVE_CARL
template std::unique_ptr<CheckResult> performPcaa<storm::models::sparse::Mdp<storm::RationalNumber>>(storm::models::sparse::Mdp<storm::RationalNumber> const& model, storm::logic::MultiObjectiveFormula const& formula);
// template std::unique_ptr<CheckResult> performPcaa<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>(storm::models::sparse::MarkovAutomaton<storm::RationalNumber> const& model, storm::logic::MultiObjectiveFormula const& formula);
template std::unique_ptr<CheckResult> performPcaa<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>(storm::models::sparse::MarkovAutomaton<storm::RationalNumber> const& model, storm::logic::MultiObjectiveFormula const& formula);
#endif
}

28
src/storm/modelchecker/multiobjective/pcaa/SparseMaPcaaWeightVectorChecker.cpp

@ -7,6 +7,7 @@
#include "storm/models/sparse/StandardRewardModel.h"
#include "storm/utility/macros.h"
#include "storm/utility/vector.h"
#include "storm/solver/GmmxxLinearEquationSolver.h"
#include "storm/exceptions/InvalidOperationException.h"
#include "storm/exceptions/InvalidPropertyException.h"
@ -101,7 +102,7 @@ namespace storm {
storm::storage::BitVector probabilisticStates = ~this->model.getMarkovianStates();
result.states = createMS ? this->model.getMarkovianStates() : probabilisticStates;
result.choices = this->model.getTransitionMatrix().getRowIndicesOfRowGroups(result.states);
result.choices = this->model.getTransitionMatrix().getRowFilter(result.states);
STORM_LOG_ASSERT(!createMS || result.states.getNumberOfSetBits() == result.choices.getNumberOfSetBits(), "row groups for Markovian states should consist of exactly one row");
//We need to add diagonal entries for selfloops on Markovian states.
@ -298,14 +299,23 @@ namespace storm {
}
template <class SparseMaModelType>
template <typename VT, typename std::enable_if<storm::NumberTraits<VT>::SupportsExponential, int>::type>
std::unique_ptr<typename SparseMaPcaaWeightVectorChecker<SparseMaModelType>::LinEqSolverData> SparseMaPcaaWeightVectorChecker<SparseMaModelType>::initLinEqSolver(SubModel const& PS) const {
std::unique_ptr<LinEqSolverData> result(new LinEqSolverData());
auto factory = std::make_unique<storm::solver::GmmxxLinearEquationSolverFactory<ValueType>>();
// We choose Jacobi since we call the solver very frequently on 'easy' inputs (note that jacobi without preconditioning has very little overhead).
result->factory.getSettings().setSolutionMethod(storm::solver::GmmxxLinearEquationSolverSettings<ValueType>::SolutionMethod::Jacobi);
result->factory.getSettings().setPreconditioner(storm::solver::GmmxxLinearEquationSolverSettings<ValueType>::Preconditioner::None);
factory->getSettings().setSolutionMethod(storm::solver::GmmxxLinearEquationSolverSettings<ValueType>::SolutionMethod::Jacobi);
factory->getSettings().setPreconditioner(storm::solver::GmmxxLinearEquationSolverSettings<ValueType>::Preconditioner::None);
result->factory = std::move(factory);
result->b.resize(PS.getNumberOfStates());
return result;
}
template <class SparseMaModelType>
template <typename VT, typename std::enable_if<!storm::NumberTraits<VT>::SupportsExponential, int>::type>
std::unique_ptr<typename SparseMaPcaaWeightVectorChecker<SparseMaModelType>::LinEqSolverData> SparseMaPcaaWeightVectorChecker<SparseMaModelType>::initLinEqSolver(SubModel const& PS) const {
STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded probabilities of MAs is unsupported for this value type.");
}
template <class SparseMaModelType>
void SparseMaPcaaWeightVectorChecker<SparseMaModelType>::updateDataToCurrentEpoch(SubModel& MS, SubModel& PS, MinMaxSolverData& minMax, storm::storage::BitVector& consideredObjectives, uint_fast64_t const& currentEpoch, std::vector<ValueType> const& weightVector, TimeBoundMap::iterator& upperTimeBoundIt, TimeBoundMap const& upperTimeBounds) {
@ -341,7 +351,7 @@ namespace storm {
linEq.solver = nullptr;
storm::storage::SparseMatrix<ValueType> linEqMatrix = PS.toPS.selectRowsFromRowGroups(optimalChoicesAtCurrentEpoch, true);
linEqMatrix.convertToEquationSystem();
linEq.solver = linEq.factory.create(std::move(linEqMatrix));
linEq.solver = linEq.factory->create(std::move(linEqMatrix));
linEq.solver->setCachingEnabled(true);
}
@ -393,11 +403,13 @@ namespace storm {
template double SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>::getDigitizationConstant<double>(std::vector<double> const& direction) const;
template void SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>::digitize<double>(SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>::SubModel& subModel, double const& digitizationConstant) const;
template void SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>::digitizeTimeBounds<double>( SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>::TimeBoundMap& upperTimeBounds, double const& digitizationConstant);
template std::unique_ptr<typename SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>::LinEqSolverData> SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>::initLinEqSolver<double>( SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>::SubModel const& PS ) const;
#ifdef STORM_HAVE_CARL
// template class SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>;
// template storm::RationalNumber SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::getDigitizationConstant<storm::RationalNumber>(std::vector<double> const& direction) const;
// template void SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::digitize<storm::RationalNumber>(SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::SubModel& subModel, storm::RationalNumber const& digitizationConstant) const;
// template void SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::digitizeTimeBounds<storm::RationalNumber>(SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>::TimeBoundMap& upperTimeBounds, storm::RationalNumber const& digitizationConstant);
template class SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>;
template storm::RationalNumber SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::getDigitizationConstant<storm::RationalNumber>(std::vector<storm::RationalNumber> const& direction) const;
template void SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::digitize<storm::RationalNumber>(SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::SubModel& subModel, storm::RationalNumber const& digitizationConstant) const;
template void SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::digitizeTimeBounds<storm::RationalNumber>(SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::TimeBoundMap& upperTimeBounds, storm::RationalNumber const& digitizationConstant);
template std::unique_ptr<typename SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::LinEqSolverData> SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::initLinEqSolver<storm::RationalNumber>( SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::SubModel const& PS ) const;
#endif
}

6
src/storm/modelchecker/multiobjective/pcaa/SparseMaPcaaWeightVectorChecker.h

@ -6,7 +6,6 @@
#include "storm/modelchecker/multiobjective/pcaa/SparsePcaaWeightVectorChecker.h"
#include "storm/solver/LinearEquationSolver.h"
#include "storm/solver/GmmxxLinearEquationSolver.h"
#include "storm/solver/MinMaxLinearEquationSolver.h"
#include "storm/utility/NumberTraits.h"
@ -71,7 +70,7 @@ namespace storm {
};
struct LinEqSolverData {
storm::solver::GmmxxLinearEquationSolverFactory<ValueType> factory;
std::unique_ptr<storm::solver::LinearEquationSolverFactory<ValueType>> factory;
std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> solver;
std::vector<ValueType> b;
};
@ -124,6 +123,9 @@ namespace storm {
/*!
* Initializes the data for the LinEq solver
*/
template <typename VT = ValueType, typename std::enable_if<storm::NumberTraits<VT>::SupportsExponential, int>::type = 0>
std::unique_ptr<LinEqSolverData> initLinEqSolver(SubModel const& PS) const;
template <typename VT = ValueType, typename std::enable_if<!storm::NumberTraits<VT>::SupportsExponential, int>::type = 0>
std::unique_ptr<LinEqSolverData> initLinEqSolver(SubModel const& PS) const;
/*

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

@ -105,7 +105,7 @@ namespace storm {
template class SparsePcaaAchievabilityQuery<storm::models::sparse::MarkovAutomaton<double>, storm::RationalNumber>;
template class SparsePcaaAchievabilityQuery<storm::models::sparse::Mdp<storm::RationalNumber>, storm::RationalNumber>;
// template class SparsePcaaAchievabilityQuery<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>, storm::RationalNumber>;
template class SparsePcaaAchievabilityQuery<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>, storm::RationalNumber>;
#endif
}
}

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

@ -95,7 +95,7 @@ namespace storm {
template class SparsePcaaParetoQuery<storm::models::sparse::MarkovAutomaton<double>, storm::RationalNumber>;
template class SparsePcaaParetoQuery<storm::models::sparse::Mdp<storm::RationalNumber>, storm::RationalNumber>;
// template class SparsePcaaParetoQuery<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>, storm::RationalNumber>;
template class SparsePcaaParetoQuery<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>, storm::RationalNumber>;
#endif
}
}

1
src/storm/modelchecker/multiobjective/pcaa/SparsePcaaPreprocessor.cpp

@ -81,6 +81,7 @@ namespace storm {
auto backwardTransitions = result.preprocessedModel.getBackwardTransitions();
analyzeEndComponents(result, backwardTransitions);
ensureRewardFiniteness(result, backwardTransitions);
break;
}
}
return result;

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

@ -201,7 +201,7 @@ namespace storm {
template class SparsePcaaQuantitativeQuery<storm::models::sparse::MarkovAutomaton<double>, storm::RationalNumber>;
template class SparsePcaaQuantitativeQuery<storm::models::sparse::Mdp<storm::RationalNumber>, storm::RationalNumber>;
// template class SparsePcaaQuantitativeQuery<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>, storm::RationalNumber>;
template class SparsePcaaQuantitativeQuery<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>, storm::RationalNumber>;
#endif
}
}

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

@ -46,6 +46,11 @@ namespace storm {
this->weightVectorChecker = std::unique_ptr<SparsePcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>>(new SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<double>>(model, objectives, actionsWithNegativeReward, ecActions, possiblyRecurrentStates));
}
template<>
void SparsePcaaQuery<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>, storm::RationalNumber>::initializeWeightVectorChecker(storm::models::sparse::MarkovAutomaton<storm::RationalNumber> const& model, std::vector<PcaaObjective<storm::RationalNumber>> const& objectives, storm::storage::BitVector const& actionsWithNegativeReward, storm::storage::BitVector const& ecActions, storm::storage::BitVector const& possiblyRecurrentStates) {
this->weightVectorChecker = std::unique_ptr<SparsePcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>>(new SparseMaPcaaWeightVectorChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>(model, objectives, actionsWithNegativeReward, ecActions, possiblyRecurrentStates));
}
template <class SparseModelType, typename GeometryValueType>
typename SparsePcaaQuery<SparseModelType, GeometryValueType>::WeightVector SparsePcaaQuery<SparseModelType, GeometryValueType>::findSeparatingVector(Point const& pointToBeSeparated) {
STORM_LOG_DEBUG("Searching a weight vector to seperate the point given by " << storm::utility::vector::toString(storm::utility::vector::convertNumericVector<double>(pointToBeSeparated)) << ".");
@ -239,6 +244,7 @@ namespace storm {
template class SparsePcaaQuery<storm::models::sparse::MarkovAutomaton<double>, storm::RationalNumber>;
template class SparsePcaaQuery<storm::models::sparse::Mdp<storm::RationalNumber>, storm::RationalNumber>;
template class SparsePcaaQuery<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>, storm::RationalNumber>;
#endif
}
}

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

@ -69,7 +69,7 @@ namespace storm {
// Create the vector of one-step probabilities to go to target states.
std::vector<typename SparseModelType::ValueType> b = this->parametricModel.getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getRowCount(), true), psiStates);
parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, this->parametricModel.getTransitionMatrix().getRowIndicesOfRowGroups(maybeStates), maybeStates);
parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, this->parametricModel.getTransitionMatrix().getRowFilter(maybeStates), maybeStates);
computePlayer1Matrix();
applyPreviousResultAsHint = false;
@ -104,7 +104,7 @@ namespace storm {
// Create the vector of one-step probabilities to go to target states.
std::vector<typename SparseModelType::ValueType> b = this->parametricModel.getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getRowCount(), true), statesWithProbability01.second);
parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, this->parametricModel.getTransitionMatrix().getRowIndicesOfRowGroups(maybeStates), maybeStates);
parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, this->parametricModel.getTransitionMatrix().getRowFilter(maybeStates), maybeStates);
computePlayer1Matrix();
// Check whether there is an EC consisting of maybestates
@ -146,16 +146,8 @@ namespace storm {
std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel.getTransitionMatrix());
// We need to handle choices that lead to an infinity state.
// As a maybeState does not have reward infinity, such a choice will never be picked. Hence, we can unselect the corresponding rows
storm::storage::BitVector selectedRows = this->parametricModel.getTransitionMatrix().getRowIndicesOfRowGroups(maybeStates);
for (uint_fast64_t row : selectedRows) {
for (auto const& element : this->parametricModel.getTransitionMatrix().getRow(row)) {
if (infinityStates.get(element.getColumn())) {
selectedRows.set(row, false);
break;
}
}
}
// As a maybeState does not have reward infinity, a choice leading to an infinity state will never be picked. Hence, we can unselect the corresponding rows
storm::storage::BitVector selectedRows = this->parametricModel.getTransitionMatrix().getRowFilter(maybeStates, ~infinityStates);
parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, selectedRows, maybeStates);
computePlayer1Matrix();

56
src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp

@ -378,25 +378,20 @@ namespace storm {
if (!maybeStates.empty()) {
// In this case we have to compute the reward values for the remaining states.
// We can eliminate the rows and columns from the original transition probability matrix for states
// whose reward values are already known.
storm::storage::SparseMatrix<ValueType> submatrix = transitionMatrix.getSubmatrix(true, maybeStates, maybeStates, false);
// Prepare the right-hand side of the equation system.
std::vector<ValueType> b = totalStateRewardVectorGetter(submatrix.getRowCount(), transitionMatrix, maybeStates);
// Since we are cutting away target and infinity states, we need to account for this by giving
// choices the value infinity that have some successor contained in the infinity states.
uint_fast64_t currentRow = 0;
for (auto state : maybeStates) {
for (uint_fast64_t row = nondeterministicChoiceIndices[state]; row < nondeterministicChoiceIndices[state + 1]; ++row, ++currentRow) {
for (auto const& element : transitionMatrix.getRow(row)) {
if (infinityStates.get(element.getColumn())) {
b[currentRow] = storm::utility::infinity<ValueType>();
break;
}
}
}
// Prepare matrix and vector for the equation system.
storm::storage::SparseMatrix<ValueType> submatrix;
std::vector<ValueType> b;
// Remove rows and columns from the original transition probability matrix for states whose reward values are already known.
// If there are infinity states, we additionaly have to remove choices of maybeState that lead to infinity
boost::optional<storm::storage::BitVector> selectedChoices; // if not given, all maybeState choices are selected
if (infinityStates.empty()) {
submatrix = transitionMatrix.getSubmatrix(true, maybeStates, maybeStates, false);
b = totalStateRewardVectorGetter(submatrix.getRowCount(), transitionMatrix, maybeStates);
} else {
selectedChoices = transitionMatrix.getRowFilter(maybeStates, ~infinityStates);
submatrix = transitionMatrix.getSubmatrix(false, *selectedChoices, maybeStates, false);
b = totalStateRewardVectorGetter(transitionMatrix.getRowCount(), transitionMatrix, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true));
storm::utility::vector::filterVectorInPlace(b, *selectedChoices);
}
bool skipEcWithinMaybeStatesCheck = !goal.minimize() || (hint.isExplicitModelCheckerHint() && hint.asExplicitModelCheckerHint<ValueType>().getNoEndComponentsInMaybeStates());
@ -408,10 +403,25 @@ namespace storm {
if (produceScheduler) {
storm::storage::Scheduler const& subscheduler = *resultForMaybeStates.scheduler;
uint_fast64_t currentSubState = 0;
for (auto maybeState : maybeStates) {
scheduler->setChoice(maybeState, subscheduler.getChoice(currentSubState));
++currentSubState;
if (selectedChoices) {
uint_fast64_t currentSubState = 0;
for (auto maybeState : maybeStates) {
uint_fast64_t subChoice = subscheduler.getChoice(currentSubState);
// find the rowindex that corresponds to the selected row of the submodel
uint_fast64_t firstRowIndex = transitionMatrix.getRowGroupIndices()[maybeState];
uint_fast64_t selectedRowIndex = selectedChoices->getNextSetIndex(firstRowIndex);
for (uint_fast64_t choice = 0; choice < subChoice; ++choice) {
selectedRowIndex = selectedChoices->getNextSetIndex(selectedRowIndex + 1);
}
scheduler->setChoice(maybeState, selectedRowIndex - firstRowIndex);
++currentSubState;
}
} else {
uint_fast64_t currentSubState = 0;
for (auto maybeState : maybeStates) {
scheduler->setChoice(maybeState, subscheduler.getChoice(currentSubState));
++currentSubState;
}
}
}
}

42
src/storm/models/sparse/Dtmc.cpp

@ -25,47 +25,7 @@ namespace storm {
STORM_LOG_THROW(probabilityMatrix.isProbabilistic(), storm::exceptions::InvalidArgumentException, "The probability matrix is invalid.");
}
#ifdef STORM_HAVE_CARL
template <typename ValueType, typename RewardModelType>
Dtmc<ValueType, RewardModelType>::ConstraintCollector::ConstraintCollector(Dtmc<ValueType> const& dtmc) {
process(dtmc);
}
template <typename ValueType, typename RewardModelType>
std::unordered_set<storm::ArithConstraint<ValueType>> const& Dtmc<ValueType, RewardModelType>::ConstraintCollector::getWellformedConstraints() const {
return this->wellformedConstraintSet;
}
template <typename ValueType, typename RewardModelType>
std::unordered_set<storm::ArithConstraint<ValueType>> const& Dtmc<ValueType, RewardModelType>::ConstraintCollector::getGraphPreservingConstraints() const {
return this->graphPreservingConstraintSet;
}
template <typename ValueType, typename RewardModelType>
void Dtmc<ValueType, RewardModelType>::ConstraintCollector::process(storm::models::sparse::Dtmc<ValueType> const& dtmc) {
for(uint_fast64_t state = 0; state < dtmc.getNumberOfStates(); ++state) {
ValueType sum = storm::utility::zero<ValueType>();
for (auto const& transition : dtmc.getRows(state)) {
sum += transition.getValue();
if (!storm::utility::isConstant(transition.getValue())) {
wellformedConstraintSet.emplace(transition.getValue() - 1, storm::CompareRelation::LEQ);
wellformedConstraintSet.emplace(transition.getValue(), storm::CompareRelation::GEQ);
graphPreservingConstraintSet.emplace(transition.getValue(), storm::CompareRelation::GREATER);
}
}
STORM_LOG_ASSERT(!storm::utility::isConstant(sum) || storm::utility::isOne(sum), "If the sum is a constant, it must be equal to 1.");
if(!storm::utility::isConstant(sum)) {
wellformedConstraintSet.emplace(sum - 1, storm::CompareRelation::EQ);
}
}
}
template <typename ValueType, typename RewardModelType>
void Dtmc<ValueType, RewardModelType>::ConstraintCollector::operator()(storm::models::sparse::Dtmc<ValueType> const& dtmc) {
process(dtmc);
}
#endif
template class Dtmc<double>;
template class Dtmc<float>;

54
src/storm/models/sparse/Dtmc.h

@ -1,10 +1,7 @@
#ifndef STORM_MODELS_SPARSE_DTMC_H_
#define STORM_MODELS_SPARSE_DTMC_H_
#include <unordered_set>
#include "storm/models/sparse/DeterministicModel.h"
#include "storm/utility/OsDetection.h"
#include "storm/adapters/CarlAdapter.h"
namespace storm {
namespace models {
@ -47,56 +44,7 @@ namespace storm {
Dtmc(Dtmc<ValueType, RewardModelType>&& dtmc) = default;
Dtmc& operator=(Dtmc<ValueType, RewardModelType>&& dtmc) = default;
#ifdef STORM_HAVE_CARL
class ConstraintCollector {
private:
// A set of constraints that says that the DTMC actually has valid probability distributions in all states.
std::unordered_set<storm::ArithConstraint<ValueType>> wellformedConstraintSet;
// A set of constraints that makes sure that the underlying graph of the model does not change depending
// on the parameter values.
std::unordered_set<storm::ArithConstraint<ValueType>> graphPreservingConstraintSet;
public:
/*!
* Constructs the a constraint collector for the given DTMC. The constraints are built and ready for
* retrieval after the construction.
*
* @param dtmc The DTMC for which to create the constraints.
*/
ConstraintCollector(storm::models::sparse::Dtmc<ValueType> const& dtmc);
/*!
* Returns the set of wellformed-ness constraints.
*
* @return The set of wellformed-ness constraints.
*/
std::unordered_set<storm::ArithConstraint<ValueType>> const& getWellformedConstraints() const;
/*!
* Returns the set of graph-preserving constraints.
*
* @return The set of graph-preserving constraints.
*/
std::unordered_set<storm::ArithConstraint<ValueType>> const& getGraphPreservingConstraints() const;
/*!
* Constructs the constraints for the given DTMC.
*
* @param dtmc The DTMC for which to create the constraints.
*/
void process(storm::models::sparse::Dtmc<ValueType> const& dtmc);
/*!
* Constructs the constraints for the given DTMC by calling the process method.
*
* @param dtmc The DTMC for which to create the constraints.
*/
void operator()(storm::models::sparse::Dtmc<ValueType> const& dtmc);
};
#endif
};
} // namespace sparse

19
src/storm/models/sparse/MarkovAutomaton.cpp

@ -140,14 +140,14 @@ namespace storm {
this->getTransitionMatrix() = this->getTransitionMatrix().restrictRows(keptChoices);
for(auto& rewModel : this->getRewardModels()) {
if(rewModel.second.hasStateActionRewards()) {
rewModel.second.getStateActionRewardVector() = storm::utility::vector::filterVector(rewModel.second.getStateActionRewardVector(), keptChoices);
storm::utility::vector::filterVectorInPlace(rewModel.second.getStateActionRewardVector(), keptChoices);
}
if(rewModel.second.hasTransitionRewards()) {
rewModel.second.getTransitionRewardMatrix() = rewModel.second.getTransitionRewardMatrix().restrictRows(keptChoices);
}
}
if(this->hasChoiceLabeling()) {
this->getOptionalChoiceLabeling() = storm::utility::vector::filterVector(this->getOptionalChoiceLabeling().get(), keptChoices);
storm::utility::vector::filterVectorInPlace(this->getOptionalChoiceLabeling().get(), keptChoices);
}
// Mark the automaton as closed.
@ -157,7 +157,7 @@ namespace storm {
template <typename ValueType, typename RewardModelType>
void MarkovAutomaton<ValueType, RewardModelType>::writeDotToStream(std::ostream& outStream, bool includeLabeling, storm::storage::BitVector const* subsystem, std::vector<ValueType> const* firstValue, std::vector<ValueType> const* secondValue, std::vector<uint_fast64_t> const* stateColoring, std::vector<std::string> const* colors, std::vector<uint_fast64_t>* scheduler, bool finalizeOutput) const {
NondeterministicModel<ValueType, RewardModelType>::writeDotToStream(outStream, includeLabeling, subsystem, firstValue, secondValue, stateColoring, colors, scheduler, false);
Model<ValueType, RewardModelType>::writeDotToStream(outStream, includeLabeling, subsystem, firstValue, secondValue, stateColoring, colors, scheduler, false);
// Write the probability distributions for all the states.
for (uint_fast64_t state = 0; state < this->getNumberOfStates(); ++state) {
@ -166,7 +166,8 @@ namespace storm {
// For this, we need to iterate over all available nondeterministic choices in the current state.
for (uint_fast64_t choice = 0; choice < rowCount; ++choice) {
typename storm::storage::SparseMatrix<ValueType>::const_rows row = this->getTransitionMatrix().getRow(this->getTransitionMatrix().getRowGroupIndices()[state] + choice);
uint_fast64_t rowIndex = this->getTransitionMatrix().getRowGroupIndices()[state] + choice;
typename storm::storage::SparseMatrix<ValueType>::const_rows row = this->getTransitionMatrix().getRow(rowIndex);
if (scheduler != nullptr) {
// If the scheduler picked the current choice, we will not make it dotted, but highlight it.
@ -192,17 +193,17 @@ namespace storm {
}
outStream << "];" << std::endl;
outStream << "\t" << state << " -> \"" << state << "c" << choice << "\"";
outStream << "\t" << state << " -> \"" << state << "c" << choice << "\" [ label= \"" << rowIndex << "\"";
// If we were given a scheduler to highlight, we do so now.
if (scheduler != nullptr) {
if (highlightChoice) {
outStream << " [color=\"red\", penwidth = 2]";
outStream << ", color=\"red\", penwidth = 2";
} else {
outStream << " [style = \"dotted\"]";
outStream << ", style = \"dotted\"";
}
}
outStream << ";" << std::endl;
outStream << "];" << std::endl;
// Now draw all probabilitic arcs that belong to this nondeterminstic choice.
for (auto const& transition : row) {
@ -328,7 +329,7 @@ namespace storm {
storm::models::sparse::StateLabeling stateLabeling = this->getStateLabeling().getSubLabeling(keepStates);
boost::optional<std::vector<LabelSet>> optionalChoiceLabeling = this->getOptionalChoiceLabeling();
if (optionalChoiceLabeling) {
optionalChoiceLabeling = storm::utility::vector::filterVector(optionalChoiceLabeling.get(), keepStates);
storm::utility::vector::filterVectorInPlace(optionalChoiceLabeling.get(), keepStates);
}
//TODO update reward models according to kept states
STORM_LOG_WARN_COND(this->getRewardModels().empty(), "Conversion of MA to CTMC does not preserve rewards.");

11
src/storm/models/sparse/NondeterministicModel.cpp

@ -108,7 +108,8 @@ namespace storm {
// For this, we need to iterate over all available nondeterministic choices in the current state.
for (uint_fast64_t choice = 0; choice < rowCount; ++choice) {
typename storm::storage::SparseMatrix<ValueType>::const_rows row = this->getTransitionMatrix().getRow(this->getNondeterministicChoiceIndices()[state] + choice);
uint_fast64_t rowIndex = this->getNondeterministicChoiceIndices()[state] + choice;
typename storm::storage::SparseMatrix<ValueType>::const_rows row = this->getTransitionMatrix().getRow(rowIndex);
if (scheduler != nullptr) {
// If the scheduler picked the current choice, we will not make it dotted, but highlight it.
@ -131,17 +132,17 @@ namespace storm {
}
outStream << "];" << std::endl;
outStream << "\t" << state << " -> \"" << state << "c" << choice << "\"";
outStream << "\t" << state << " -> \"" << state << "c" << choice << "\" [ label= \"" << rowIndex << "\"";
// If we were given a scheduler to highlight, we do so now.
if (scheduler != nullptr) {
if (highlightChoice) {
outStream << " [color=\"red\", penwidth = 2]";
outStream << ", color=\"red\", penwidth = 2";
} else {
outStream << " [style = \"dotted\"]";
outStream << ", style = \"dotted\"";
}
}
outStream << ";" << std::endl;
outStream << "];" << std::endl;
// Now draw all probabilitic arcs that belong to this nondeterminstic choice.
for (auto const& transition : row) {

75
src/storm/parser/DeterministicSparseTransitionParser.cpp

@ -46,8 +46,7 @@ namespace storm {
char const* buf = file.getData();
// Perform first pass, i.e. count entries that are not zero.
bool insertDiagonalEntriesIfMissing = !isRewardFile;
DeterministicSparseTransitionParser<ValueType>::FirstPassResult firstPass = DeterministicSparseTransitionParser<ValueType>::firstPass(file.getData(), insertDiagonalEntriesIfMissing);
DeterministicSparseTransitionParser<ValueType>::FirstPassResult firstPass = DeterministicSparseTransitionParser<ValueType>::firstPass(file.getData());
STORM_LOG_TRACE("First pass on " << filename << " shows " << firstPass.numberOfNonzeroEntries << " non-zeros.");
@ -85,7 +84,6 @@ namespace storm {
double val;
bool dontFixDeadlocks = storm::settings::getModule<storm::settings::modules::CoreSettings>().isDontFixDeadlocksSet();
bool hadDeadlocks = false;
bool rowHadDiagonalEntry = false;
// Read all transitions from file. Note that we assume that the
// transitions are listed in canonical order, otherwise this will not
@ -131,16 +129,6 @@ namespace storm {
// Test if we moved to a new row.
// Handle all incomplete or skipped rows.
if (lastRow != row) {
if (!rowHadDiagonalEntry) {
if (insertDiagonalEntriesIfMissing) {
resultMatrix.addNextValue(lastRow, lastRow, storm::utility::zero<ValueType>());
STORM_LOG_DEBUG("While parsing " << filename << ": state " << lastRow << " has no transition to itself. Inserted a 0-transition. (1)");
} else {
STORM_LOG_WARN("Warning while parsing " << filename << ": state " << lastRow << " has no transition to itself.");
}
// No increment for lastRow.
rowHadDiagonalEntry = true;
}
for (uint_fast64_t skippedRow = lastRow + 1; skippedRow < row; ++skippedRow) {
hadDeadlocks = true;
if (!dontFixDeadlocks) {
@ -152,36 +140,12 @@ namespace storm {
}
}
lastRow = row;
rowHadDiagonalEntry = false;
}
if (col == row) {
rowHadDiagonalEntry = true;
}
if (col > row && !rowHadDiagonalEntry) {
if (insertDiagonalEntriesIfMissing) {
resultMatrix.addNextValue(row, row, storm::utility::zero<ValueType>());
STORM_LOG_DEBUG("While parsing " << filename << ": state " << row << " has no transition to itself. Inserted a 0-transition. (2)");
} else {
STORM_LOG_WARN("Warning while parsing " << filename << ": state " << row << " has no transition to itself.");
}
rowHadDiagonalEntry = true;
}
resultMatrix.addNextValue(row, col, val);
buf = trimWhitespaces(buf);
}
if (!rowHadDiagonalEntry) {
if (insertDiagonalEntriesIfMissing) {
resultMatrix.addNextValue(lastRow, lastRow, storm::utility::zero<ValueType>());
STORM_LOG_DEBUG("While parsing " << filename << ": state " << lastRow << " has no transition to itself. Inserted a 0-transition. (3)");
} else {
STORM_LOG_WARN("Warning while parsing " << filename << ": state " << lastRow << " has no transition to itself.");
}
}
// If we encountered deadlock and did not fix them, now is the time to throw the exception.
if (dontFixDeadlocks && hadDeadlocks) throw storm::exceptions::WrongFormatException() << "Some of the states do not have outgoing transitions.";
}
@ -199,7 +163,7 @@ namespace storm {
}
template<typename ValueType>
typename DeterministicSparseTransitionParser<ValueType>::FirstPassResult DeterministicSparseTransitionParser<ValueType>::firstPass(char const* buf, bool insertDiagonalEntriesIfMissing) {
typename DeterministicSparseTransitionParser<ValueType>::FirstPassResult DeterministicSparseTransitionParser<ValueType>::firstPass(char const* buf) {
DeterministicSparseTransitionParser<ValueType>::FirstPassResult result;
@ -231,30 +195,6 @@ namespace storm {
// The actual read value is not needed here.
checked_strtod(buf, &buf);
// Compensate for missing diagonal entries if desired.
if (insertDiagonalEntriesIfMissing) {
if (lastRow != row) {
if (!rowHadDiagonalEntry) {
++result.numberOfNonzeroEntries;
}
// Compensate for missing rows.
for (uint_fast64_t skippedRow = lastRow + 1; skippedRow < row; ++skippedRow) {
++result.numberOfNonzeroEntries;
}
rowHadDiagonalEntry = false;
}
if (col == row) {
rowHadDiagonalEntry = true;
}
if (col > row && !rowHadDiagonalEntry) {
rowHadDiagonalEntry = true;
++result.numberOfNonzeroEntries;
}
}
// Check if a higher state id was found.
if (row > result.highestStateIndex) result.highestStateIndex = row;
if (col > result.highestStateIndex) result.highestStateIndex = col;
@ -273,17 +213,6 @@ namespace storm {
buf = trimWhitespaces(buf);
}
if (insertDiagonalEntriesIfMissing) {
if (!rowHadDiagonalEntry) {
++result.numberOfNonzeroEntries;
}
//Compensate for missing rows at the end of the file.
for (uint_fast64_t skippedRow = (uint_fast64_t) (lastRow + 1); skippedRow <= result.highestStateIndex; ++skippedRow) {
++result.numberOfNonzeroEntries;
}
}
return result;
}

3
src/storm/parser/DeterministicSparseTransitionParser.h

@ -65,10 +65,9 @@ namespace storm {
* transitions and the maximum node id.
*
* @param buffer The buffer that contains the input.
* @param insertDiagonalEntriesIfMissing A flag set iff entries on the primary diagonal of the matrix should be added in case they are missing in the parsed file.
* @return A structure representing the result of the first pass.
*/
static FirstPassResult firstPass(char const* buffer, bool insertDiagonalEntriesIfMissing = true);
static FirstPassResult firstPass(char const* buffer);
/*
* The main parsing routine.

3
src/storm/settings/ArgumentValidators.cpp

@ -86,9 +86,6 @@ namespace storm {
return true;
} else if (mode == Mode::Writable) {
struct stat info;
STORM_LOG_THROW(stat (filename.c_str(), &info) != 0, storm::exceptions::IllegalArgumentValueException , "Could not open file '" << filename << "' for writing because file or directory already exists.");
std::ofstream filestream(filename);
STORM_LOG_THROW(filestream.is_open(), storm::exceptions::IllegalArgumentValueException , "Could not open file '" << filename << "' for writing.");
filestream.close();

90
src/storm/storage/BitVector.cpp

@ -22,7 +22,7 @@ namespace storm {
BitVector::const_iterator::const_iterator(uint64_t const* dataPtr, uint_fast64_t startIndex, uint_fast64_t endIndex, bool setOnFirstBit) : dataPtr(dataPtr), endIndex(endIndex) {
if (setOnFirstBit) {
// Set the index of the first set bit in the vector.
currentIndex = getNextSetIndex(dataPtr, startIndex, endIndex);
currentIndex = getNextIndexWithValue(true, dataPtr, startIndex, endIndex);
} else {
currentIndex = startIndex;
}
@ -43,13 +43,13 @@ namespace storm {
}
BitVector::const_iterator& BitVector::const_iterator::operator++() {
currentIndex = getNextSetIndex(dataPtr, ++currentIndex, endIndex);
currentIndex = getNextIndexWithValue(true, dataPtr, ++currentIndex, endIndex);
return *this;
}
BitVector::const_iterator& BitVector::const_iterator::operator+=(size_t n) {
for(size_t i = 0; i < n; ++i) {
currentIndex = getNextSetIndex(dataPtr, ++currentIndex, endIndex);
currentIndex = getNextIndexWithValue(true, dataPtr, ++currentIndex, endIndex);
}
return *this;
}
@ -628,10 +628,17 @@ namespace storm {
}
uint_fast64_t BitVector::getNextSetIndex(uint_fast64_t startingIndex) const {
return getNextSetIndex(buckets, startingIndex, bitCount);
return getNextIndexWithValue(true, buckets, startingIndex, bitCount);
}
uint_fast64_t BitVector::getNextSetIndex(uint64_t const* dataPtr, uint_fast64_t startingIndex, uint_fast64_t endIndex) {
uint_fast64_t BitVector::getNextUnsetIndex(uint_fast64_t startingIndex) const {
#ifdef ASSERT_BITVECTOR
STORM_LOG_ASSERT(getNextIndexWithValue(false, buckets, startingIndex, bitCount) == (~(*this)).getNextSetIndex(startingIndex), "The result is inconsistent with the next set index of the complement of this bitvector");
#endif
return getNextIndexWithValue(false, buckets, startingIndex, bitCount);
}
uint_fast64_t BitVector::getNextIndexWithValue(bool value, uint64_t const* dataPtr, uint_fast64_t startingIndex, uint_fast64_t endIndex) {
uint_fast8_t currentBitInByte = startingIndex & mod64mask;
uint64_t const* bucketIt = dataPtr + (startingIndex >> 6);
startingIndex = (startingIndex >> 6 << 6);
@ -642,31 +649,62 @@ namespace storm {
} else {
mask = (1ull << (64 - currentBitInByte)) - 1ull;
}
while (startingIndex < endIndex) {
// Compute the remaining bucket content.
uint64_t remainingInBucket = *bucketIt & mask;
// Check if there is at least one bit in the remainder of the bucket that is set to true.
if (remainingInBucket != 0) {
// As long as the current bit is not set, move the current bit.
while ((remainingInBucket & (1ull << (63 - currentBitInByte))) == 0) {
++currentBitInByte;
// For efficiency reasons, we branch on the desired value at this point
if (value) {
while (startingIndex < endIndex) {
// Compute the remaining bucket content.
uint64_t remainingInBucket = *bucketIt & mask;
// Check if there is at least one bit in the remainder of the bucket that is set to true.
if (remainingInBucket != 0) {
// As long as the current bit is not set, move the current bit.
while ((remainingInBucket & (1ull << (63 - currentBitInByte))) == 0) {
++currentBitInByte;
}
// Only return the index of the set bit if we are still in the valid range.
if (startingIndex + currentBitInByte < endIndex) {
return startingIndex + currentBitInByte;
} else {
return endIndex;
}
}
// Only return the index of the set bit if we are still in the valid range.
if (startingIndex + currentBitInByte < endIndex) {
return startingIndex + currentBitInByte;
} else {
return endIndex;
// Advance to the next bucket.
startingIndex += 64;
++bucketIt;
mask = -1ull;
currentBitInByte = 0;
}
} else {
while (startingIndex < endIndex) {
// Compute the remaining bucket content.
uint64_t remainingInBucket = *bucketIt & mask;
// Check if there is at least one bit in the remainder of the bucket that is set to false.
if (remainingInBucket != (-1ull & mask)) {
// As long as the current bit is not false, move the current bit.
while ((remainingInBucket & (1ull << (63 - currentBitInByte))) != 0) {
++currentBitInByte;
}
// Only return the index of the set bit if we are still in the valid range.
if (startingIndex + currentBitInByte < endIndex) {
return startingIndex + currentBitInByte;
} else {
return endIndex;
}
}
// Advance to the next bucket.
startingIndex += 64;
++bucketIt;
mask = -1ull;
currentBitInByte = 0;
}
// Advance to the next bucket.
startingIndex += 64;
++bucketIt;
mask = -1ull;
currentBitInByte = 0;
}
return endIndex;
}

16
src/storm/storage/BitVector.h

@ -477,6 +477,17 @@ namespace storm {
*/
uint_fast64_t getNextSetIndex(uint_fast64_t startingIndex) const;
/*
* Retrieves the index of the bit that is the next bit set to false in the bit vector. If there is none,
* this function returns the number of bits this vector holds in total. Put differently, if the return
* value is equal to a call to size(), then there is no unset bit after the specified position.
*
* @param startingIndex The index at which to start the search for the next bit that is not set. The
* bit at this index itself is included in the search range.
* @return The index of the next bit that is set after the given index.
*/
uint_fast64_t getNextUnsetIndex(uint_fast64_t startingIndex) const;
/*
* Compare two intervals [start1, start1+length] and [start2, start2+length] and swap them if the second
* one is larger than the first one. After the method the intervals are sorted in decreasing order.
@ -502,15 +513,16 @@ namespace storm {
BitVector(uint_fast64_t bucketCount, uint_fast64_t bitCount);
/*!
* Retrieves the index of the next bit that is set to true after (and including) the given starting index.
* Retrieves the index of the next bit that is set to the given value after (and including) the given starting index.
*
* @param value the value of the bit whose index is to be found.
* @param dataPtr A pointer to the first bucket of the data storage.
* @param startingIndex The index where to start the search.
* @param endIndex The index at which to stop the search.
* @return The index of the bit that is set after the given starting index, but before the given end index
* in the given bit vector or endIndex in case the end index was reached.
*/
static uint_fast64_t getNextSetIndex(uint64_t const* dataPtr, uint_fast64_t startingIndex, uint_fast64_t endIndex);
static uint_fast64_t getNextIndexWithValue(bool value, uint64_t const* dataPtr, uint_fast64_t startingIndex, uint_fast64_t endIndex);
/*!
* Truncate the last bucket so that no bits are set starting from bitCount.

28
src/storm/storage/SparseMatrix.cpp

@ -555,16 +555,38 @@ namespace storm {
}
template<typename ValueType>
storm::storage::BitVector SparseMatrix<ValueType>::getRowIndicesOfRowGroups(storm::storage::BitVector const& groups) const {
storm::storage::BitVector SparseMatrix<ValueType>::getRowFilter(storm::storage::BitVector const& groupConstraint) const {
storm::storage::BitVector res(this->getRowCount(), false);
for(auto group : groups) {
for(uint_fast64_t row = this->getRowGroupIndices()[group]; row < this->getRowGroupIndices()[group+1]; ++row) {
for(auto group : groupConstraint) {
uint_fast64_t const endOfGroup = this->getRowGroupIndices()[group + 1];
for(uint_fast64_t row = this->getRowGroupIndices()[group]; row < endOfGroup; ++row) {
res.set(row, true);
}
}
return res;
}
template<typename ValueType>
storm::storage::BitVector SparseMatrix<ValueType>::getRowFilter(storm::storage::BitVector const& groupConstraint, storm::storage::BitVector const& columnConstraint) const {
storm::storage::BitVector result(this->getRowCount(), false);
for (auto const& group : groupConstraint) {
uint_fast64_t const endOfGroup = this->getRowGroupIndices()[group + 1];
for (uint_fast64_t row = this->getRowGroupIndices()[group]; row < endOfGroup; ++row) {
bool choiceSatisfiesColumnConstraint = true;
for (auto const& entry : this->getRow(row)) {
if (!columnConstraint.get(entry.getColumn())) {
choiceSatisfiesColumnConstraint = false;
break;
}
}
if (choiceSatisfiesColumnConstraint) {
result.set(row, true);
}
}
}
return result;
}
template<typename ValueType>
void SparseMatrix<ValueType>::makeRowsAbsorbing(storm::storage::BitVector const& rows) {
for (auto row : rows) {

13
src/storm/storage/SparseMatrix.h

@ -569,7 +569,18 @@ namespace storm {
* @param groups the selected row groups
* @return a bit vector that is true at position i iff the row group of row i is selected.
*/
storm::storage::BitVector getRowIndicesOfRowGroups(storm::storage::BitVector const& groups) const;
storm::storage::BitVector getRowFilter(storm::storage::BitVector const& groupConstraint) const;
/*!
* Returns the indices of all rows that
* * are in a selected group and
* * only have entries within the selected columns.
*
* @param groupConstraint the selected groups
* @param columnConstraints the selected columns
* @return a bit vector that is true at position i iff row i satisfies the constraints.
*/
storm::storage::BitVector getRowFilter(storm::storage::BitVector const& groupConstraint, storm::storage::BitVector const& columnConstraints) const;
/*!
* This function makes the given rows absorbing.

8
src/storm/storage/expressions/SimpleValuation.cpp

@ -19,7 +19,7 @@ namespace storm {
// Intentionally left empty.
}
SimpleValuation::SimpleValuation(SimpleValuation const& other) : Valuation(other.getManager().getSharedPointer()) {
SimpleValuation::SimpleValuation(SimpleValuation const& other) : Valuation(other.getManagerAsSharedPtr()) {
if (this != &other) {
booleanValues = other.booleanValues;
integerValues = other.integerValues;
@ -29,7 +29,7 @@ namespace storm {
SimpleValuation& SimpleValuation::operator=(SimpleValuation const& other) {
if (this != &other) {
this->setManager(other.getManager().getSharedPointer());
this->setManager(other.getManagerAsSharedPtr());
booleanValues = other.booleanValues;
integerValues = other.integerValues;
rationalValues = other.rationalValues;
@ -37,7 +37,7 @@ namespace storm {
return *this;
}
SimpleValuation::SimpleValuation(SimpleValuation&& other) : Valuation(other.getManager().getSharedPointer()) {
SimpleValuation::SimpleValuation(SimpleValuation&& other) : Valuation(other.getManagerAsSharedPtr()) {
if (this != &other) {
booleanValues = std::move(other.booleanValues);
integerValues = std::move(other.integerValues);
@ -47,7 +47,7 @@ namespace storm {
SimpleValuation& SimpleValuation::operator=(SimpleValuation&& other) {
if (this != &other) {
this->setManager(other.getManager().getSharedPointer());
this->setManager(other.getManagerAsSharedPtr());
booleanValues = std::move(other.booleanValues);
integerValues = std::move(other.integerValues);
rationalValues = std::move(other.rationalValues);

4
src/storm/storage/expressions/Valuation.cpp

@ -15,6 +15,10 @@ namespace storm {
return *manager;
}
std::shared_ptr<ExpressionManager const> const& Valuation::getManagerAsSharedPtr() const {
return manager;
}
void Valuation::setManager(std::shared_ptr<ExpressionManager const> const& manager) {
this->manager = manager;
}

8
src/storm/storage/expressions/Valuation.h

@ -101,6 +101,14 @@ namespace storm {
ExpressionManager const& getManager() const;
protected:
/*!
* Retrieves the manager responsible for the variables of this valuation.
*
* @return The manager.
*/
std::shared_ptr<ExpressionManager const> const& getManagerAsSharedPtr() const;
/*!
* Sets the manager responsible for the variables in this valuation.
*

4
src/storm/storage/geometry/nativepolytopeconversion/QuickHull.cpp

@ -173,7 +173,7 @@ namespace storm {
}
}
}
points = storm::utility::vector::filterVector(points, keptPoints);
storm::utility::vector::filterVectorInPlace(points, keptPoints);
if (generateRelevantVerticesAndVertexSets) {
storm::storage::BitVector keptVertices(relevantVertices.size(), true);
@ -185,7 +185,7 @@ namespace storm {
}
}
}
relevantVertices = storm::utility::vector::filterVector(relevantVertices, keptVertices);
storm::utility::vector::filterVectorInPlace(relevantVertices, keptVertices);
STORM_LOG_WARN("Can not retrieve vertex sets for degenerated polytope (not implemented)");
vertexSets.clear();

11
src/storm/transformer/GoalStateMerger.cpp

@ -46,11 +46,12 @@ namespace storm {
// Get the reward models
std::unordered_map<std::string, typename SparseModelType::RewardModelType> rewardModels;
for (auto rewardModelName : selectedRewardModels) {
auto origTotalRewards = originalModel.getRewardModel(rewardModelName).getTotalRewardVector(originalModel.getTransitionMatrix());
auto transitionsOfMaybeStates = originalModel.getTransitionMatrix().getRowIndicesOfRowGroups(maybeStates);
auto resTotalRewards = storm::utility::vector::filterVector(origTotalRewards, transitionsOfMaybeStates);
resTotalRewards.resize(transitionMatrix.getRowCount(), storm::utility::zero<typename SparseModelType::RewardModelType::ValueType>());
rewardModels.insert(std::make_pair(rewardModelName, typename SparseModelType::RewardModelType(boost::none, resTotalRewards)));
auto totalRewards = originalModel.getRewardModel(rewardModelName).getTotalRewardVector(originalModel.getTransitionMatrix());
auto choicesOfMaybeStates = originalModel.getTransitionMatrix().getRowFilter(maybeStates);
storm::utility::vector::filterVectorInPlace(totalRewards, choicesOfMaybeStates);
// add zero reward for the sink and goal states (if they exists)
totalRewards.resize(transitionMatrix.getRowCount(), storm::utility::zero<typename SparseModelType::RewardModelType::ValueType>());
rewardModels.insert(std::make_pair(rewardModelName, typename SparseModelType::RewardModelType(boost::none, totalRewards)));
}
// modify the given target and sink states

4
src/storm/transformer/SparseParametricModelSimplifier.cpp

@ -138,13 +138,13 @@ namespace storm {
stateEliminator.eliminateState(state, true);
}
selectedStates.complement();
auto keptRows = sparseMatrix.getRowIndicesOfRowGroups(selectedStates);
auto keptRows = sparseMatrix.getRowFilter(selectedStates);
storm::storage::SparseMatrix<typename SparseModelType::ValueType> newTransitionMatrix = flexibleMatrix.createSparseMatrix(keptRows, selectedStates);
// obtain the reward model for the resulting system
std::unordered_map<std::string, typename SparseModelType::RewardModelType> rewardModels;
if(rewardModelName) {
actionRewards = storm::utility::vector::filterVector(actionRewards, keptRows);
storm::utility::vector::filterVectorInPlace(actionRewards, keptRows);
rewardModels.insert(std::make_pair(*rewardModelName, typename SparseModelType::RewardModelType(boost::none, std::move(actionRewards))));
}

18
src/storm/utility/storm.h

@ -93,6 +93,9 @@
#include "storm/generator/PrismNextStateGenerator.h"
#include "storm/generator/JaniNextStateGenerator.h"
#include "storm/analysis/GraphConditions.h"
// Headers related to exception handling.
#include "storm/exceptions/InvalidStateException.h"
#include "storm/exceptions/InvalidArgumentException.h"
@ -526,7 +529,7 @@ namespace storm {
}
template<typename ValueType>
std::unique_ptr<storm::modelchecker::CheckResult> verifySparseMarkovAutomaton(std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma, storm::modelchecker::CheckTask<storm::logic::Formula> const& task) {
std::unique_ptr<storm::modelchecker::CheckResult> verifySparseMarkovAutomaton(std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) {
std::unique_ptr<storm::modelchecker::CheckResult> result;
// Close the MA, if it is not already closed.
if (!ma->isClosed()) {
@ -572,25 +575,30 @@ namespace storm {
result = verifySparseCtmc(model->template as<storm::models::sparse::Ctmc<storm::RationalNumber>>(), task);
} else if (model->getType() == storm::models::ModelType::Mdp) {
result = verifySparseMdp(model->template as<storm::models::sparse::Mdp<storm::RationalNumber>>(), task);
} else if (model->getType() == storm::models::ModelType::MarkovAutomaton) {
result = verifySparseMarkovAutomaton(model->template as<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>(), task);
} else {
STORM_LOG_ASSERT(false, "Illegal model type.");
}
return result;
}
inline void exportParametricResultToFile(storm::RationalFunction const& result, storm::models::sparse::Dtmc<storm::RationalFunction>::ConstraintCollector const& constraintCollector, std::string const& path) {
inline void exportParametricResultToFile(storm::RationalFunction const& result, storm::analysis::ConstraintCollector<storm::RationalFunction> const& constraintCollector, std::string const& path) {
std::ofstream filestream;
storm::utility::openFile(path, filestream);
// TODO: add checks.
filestream << "!Parameters: ";
std::set<storm::RationalFunctionVariable> vars = result.gatherVariables();
std::copy(vars.begin(), vars.end(), std::ostream_iterator<storm::RationalFunctionVariable>(filestream, "; "));
filestream << std::endl;
filestream << "!Result: " << result << std::endl;
filestream << "!Well-formed Constraints: " << std::endl;
std::copy(constraintCollector.getWellformedConstraints().begin(), constraintCollector.getWellformedConstraints().end(), std::ostream_iterator<storm::ArithConstraint<storm::RationalFunction>>(filestream, "\n"));
std::vector<std::string> stringConstraints;
std::transform(constraintCollector.getWellformedConstraints().begin(), constraintCollector.getWellformedConstraints().end(), std::back_inserter(stringConstraints), [](carl::Formula<typename storm::Polynomial::PolyType> const& c) -> std::string { return c.toString();});
std::copy(stringConstraints.begin(), stringConstraints.end(), std::ostream_iterator<std::string>(filestream, "\n"));
filestream << "!Graph-preserving Constraints: " << std::endl;
std::copy(constraintCollector.getGraphPreservingConstraints().begin(), constraintCollector.getGraphPreservingConstraints().end(), std::ostream_iterator<storm::ArithConstraint<storm::RationalFunction>>(filestream, "\n"));
stringConstraints.clear();
std::transform(constraintCollector.getGraphPreservingConstraints().begin(), constraintCollector.getGraphPreservingConstraints().end(), std::back_inserter(stringConstraints), [](carl::Formula<typename storm::Polynomial::PolyType> const& c) -> std::string { return c.toString();});
std::copy(stringConstraints.begin(), stringConstraints.end(), std::ostream_iterator<std::string>(filestream, "\n"));
storm::utility::closeFile(filestream);
}

20
src/storm/utility/vector.h

@ -859,11 +859,29 @@ namespace storm {
return result;
}
template<typename Type>
void filterVectorInPlace(std::vector<Type>& v, storm::storage::BitVector const& filter) {
STORM_LOG_ASSERT(v.size() == filter.size(), "The filter size does not match the size of the input vector");
uint_fast64_t size = v.size();
// we can start our work at the first index where the filter has value zero
uint_fast64_t firstUnsetIndex = filter.getNextUnsetIndex(0);
if (firstUnsetIndex < size) {
auto vIt = v.begin() + firstUnsetIndex;
for (uint_fast64_t index = filter.getNextSetIndex(firstUnsetIndex + 1); index != size; index = filter.getNextSetIndex(index + 1)) {
*vIt = std::move(v[index]);
++vIt;
}
v.resize(vIt - v.begin());
v.shrink_to_fit();
}
STORM_LOG_ASSERT(v.size() == filter.getNumberOfSetBits(), "Result does not match.");
}
template<typename T>
bool hasNegativeEntry(std::vector<T> const& v){
return std::any_of(v.begin(), v.end(), [](T value){return value < storm::utility::zero<T>();});
}
template<typename T>
bool hasPositiveEntry(std::vector<T> const& v){
return std::any_of(v.begin(), v.end(), [](T value){return value > storm::utility::zero<T>();});

15
src/test/storage/BitVectorTest.cpp

@ -482,6 +482,21 @@ TEST(BitVectorTest, NextSetIndex) {
ASSERT_EQ(vector.size(), vector.getNextSetIndex(18));
}
TEST(BitVectorTest, NextUnsetIndex) {
storm::storage::BitVector vector(32);
vector.set(14);
vector.set(17);
vector.complement();
ASSERT_EQ(14ul, vector.getNextUnsetIndex(14));
ASSERT_EQ(17ul, vector.getNextUnsetIndex(15));
ASSERT_EQ(17ul, vector.getNextUnsetIndex(16));
ASSERT_EQ(17ul, vector.getNextUnsetIndex(17));
ASSERT_EQ(vector.size(), vector.getNextUnsetIndex(18));
}
TEST(BitVectorTest, Iterator) {
storm::storage::BitVector vector(32);

Loading…
Cancel
Save