Browse Source

Merge branch 'jani_support' of https://sselab.de/lab9/private/git/storm into jani_support

Former-commit-id: c8e7079004 [formerly d9b79118bf]
Former-commit-id: 749e0dca53
main
sjunges 9 years ago
parent
commit
5eac1e22ce
  1. 1
      examples/dtmc/die/die.pm
  2. 2
      resources/3rdparty/CMakeLists.txt
  3. 56
      src/adapters/AddExpressionAdapter.cpp
  4. 20
      src/adapters/AddExpressionAdapter.h
  5. 46
      src/adapters/DereferenceIteratorAdapter.h
  6. 46
      src/adapters/MathsatExpressionAdapter.h
  7. 46
      src/adapters/Z3ExpressionAdapter.cpp
  8. 20
      src/adapters/Z3ExpressionAdapter.h
  9. 286
      src/builder/DdJaniModelBuilder.cpp
  10. 32
      src/builder/DdJaniModelBuilder.h
  11. 37
      src/builder/DdPrismModelBuilder.cpp
  12. 11
      src/builder/DdPrismModelBuilder.h
  13. 40
      src/cli/cli.cpp
  14. 56
      src/cli/entrypoints.h
  15. 2
      src/counterexamples/SMTMinimalCommandSetGenerator.h
  16. 147
      src/generator/JaniNextStateGenerator.cpp
  17. 17
      src/generator/JaniNextStateGenerator.h
  18. 12
      src/generator/NextStateGenerator.cpp
  19. 3
      src/generator/NextStateGenerator.h
  20. 14
      src/generator/PrismNextStateGenerator.cpp
  21. 5
      src/generator/StateBehavior.cpp
  22. 7
      src/generator/StateBehavior.h
  23. 1
      src/modelchecker/AbstractModelChecker.cpp
  24. 2
      src/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp
  25. 32
      src/parser/ExpressionParser.cpp
  26. 16
      src/parser/ExpressionParser.h
  27. 5
      src/parser/FormulaParser.cpp
  28. 6
      src/parser/FormulaParser.h
  29. 2
      src/parser/JaniParser.cpp
  30. 3
      src/parser/JaniParser.h
  31. 20
      src/parser/PrismParser.cpp
  32. 6
      src/parser/PrismParser.h
  33. 5
      src/settings/modules/CoreSettings.cpp
  34. 1
      src/settings/modules/CoreSettings.h
  35. 2
      src/settings/modules/CounterexampleGeneratorSettings.cpp
  36. 47
      src/settings/modules/IOSettings.cpp
  37. 48
      src/settings/modules/IOSettings.h
  38. 83
      src/storage/SymbolicModelDescription.cpp
  39. 39
      src/storage/SymbolicModelDescription.h
  40. 82
      src/storage/expressions/BaseExpression.cpp
  41. 46
      src/storage/expressions/BaseExpression.h
  42. 4
      src/storage/expressions/BinaryBooleanFunctionExpression.cpp
  43. 2
      src/storage/expressions/BinaryBooleanFunctionExpression.h
  44. 8
      src/storage/expressions/BinaryNumericalFunctionExpression.cpp
  45. 2
      src/storage/expressions/BinaryNumericalFunctionExpression.h
  46. 4
      src/storage/expressions/BinaryRelationExpression.cpp
  47. 2
      src/storage/expressions/BinaryRelationExpression.h
  48. 4
      src/storage/expressions/BooleanLiteralExpression.cpp
  49. 2
      src/storage/expressions/BooleanLiteralExpression.h
  50. 39
      src/storage/expressions/DoubleLiteralExpression.cpp
  51. 53
      src/storage/expressions/DoubleLiteralExpression.h
  52. 13
      src/storage/expressions/Expression.cpp
  53. 9
      src/storage/expressions/Expression.h
  54. 6
      src/storage/expressions/ExpressionManager.cpp
  55. 9
      src/storage/expressions/ExpressionManager.h
  56. 22
      src/storage/expressions/ExpressionVisitor.h
  57. 2
      src/storage/expressions/Expressions.h
  58. 4
      src/storage/expressions/IfThenElseExpression.cpp
  59. 2
      src/storage/expressions/IfThenElseExpression.h
  60. 4
      src/storage/expressions/IntegerLiteralExpression.cpp
  61. 2
      src/storage/expressions/IntegerLiteralExpression.h
  62. 30
      src/storage/expressions/LinearCoefficientVisitor.cpp
  63. 20
      src/storage/expressions/LinearCoefficientVisitor.h
  64. 28
      src/storage/expressions/LinearityCheckVisitor.cpp
  65. 20
      src/storage/expressions/LinearityCheckVisitor.h
  66. 53
      src/storage/expressions/RationalLiteralExpression.cpp
  67. 78
      src/storage/expressions/RationalLiteralExpression.h
  68. 44
      src/storage/expressions/SubstitutionVisitor.cpp
  69. 20
      src/storage/expressions/SubstitutionVisitor.h
  70. 155
      src/storage/expressions/SyntacticalEqualityCheckVisitor.cpp
  71. 27
      src/storage/expressions/SyntacticalEqualityCheckVisitor.h
  72. 108
      src/storage/expressions/ToExprtkStringVisitor.cpp
  73. 20
      src/storage/expressions/ToExprtkStringVisitor.h
  74. 35
      src/storage/expressions/ToRationalFunctionVisitor.cpp
  75. 20
      src/storage/expressions/ToRationalFunctionVisitor.h
  76. 51
      src/storage/expressions/ToRationalNumberVisitor.cpp
  77. 20
      src/storage/expressions/ToRationalNumberVisitor.h
  78. 4
      src/storage/expressions/UnaryBooleanFunctionExpression.cpp
  79. 2
      src/storage/expressions/UnaryBooleanFunctionExpression.h
  80. 8
      src/storage/expressions/UnaryNumericalFunctionExpression.cpp
  81. 2
      src/storage/expressions/UnaryNumericalFunctionExpression.h
  82. 4
      src/storage/expressions/VariableExpression.cpp
  83. 2
      src/storage/expressions/VariableExpression.h
  84. 39
      src/storage/jani/Assignment.cpp
  85. 29
      src/storage/jani/Assignment.h
  86. 56
      src/storage/jani/Automaton.cpp
  87. 33
      src/storage/jani/Automaton.h
  88. 9
      src/storage/jani/BooleanVariable.cpp
  89. 5
      src/storage/jani/BooleanVariable.h
  90. 13
      src/storage/jani/BoundedIntegerVariable.cpp
  91. 7
      src/storage/jani/BoundedIntegerVariable.h
  92. 52
      src/storage/jani/Edge.cpp
  93. 28
      src/storage/jani/Edge.h
  94. 63
      src/storage/jani/EdgeDestination.cpp
  95. 45
      src/storage/jani/EdgeDestination.h
  96. 438
      src/storage/jani/Exporter.cpp
  97. 48
      src/storage/jani/Exporter.h
  98. 26
      src/storage/jani/Location.cpp
  99. 20
      src/storage/jani/Location.h
  100. 78
      src/storage/jani/Model.cpp

1
examples/dtmc/die/die.pm

@ -29,3 +29,4 @@ label "three" = s=7&d=3;
label "four" = s=7&d=4;
label "five" = s=7&d=5;
label "six" = s=7&d=6;
label "end" = s=7;

2
resources/3rdparty/CMakeLists.txt

@ -204,7 +204,7 @@ if(USE_CARL)
LOG_INSTALL ON
)
add_dependencies(resources xercesc)
add_dependencies(resources carl)
include_directories(${STORM_3RDPARTY_BINARY_DIR}/carl/include)
list(APPEND STORM_LINK_LIBRARIES ${STORM_3RDPARTY_BINARY_DIR}/carl/lib/libcarl${DYNAMIC_EXT})
set(STORM_HAVE_CARL ON)

56
src/adapters/AddExpressionAdapter.cpp

@ -19,37 +19,37 @@ namespace storm {
template<storm::dd::DdType Type, typename ValueType>
storm::dd::Add<Type, ValueType> AddExpressionAdapter<Type, ValueType>::translateExpression(storm::expressions::Expression const& expression) {
if (expression.hasBooleanType()) {
return boost::any_cast<storm::dd::Bdd<Type>>(expression.accept(*this)).template toAdd<ValueType>();
return boost::any_cast<storm::dd::Bdd<Type>>(expression.accept(*this, boost::none)).template toAdd<ValueType>();
} else {
return boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.accept(*this));
return boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.accept(*this, boost::none));
}
}
template<storm::dd::DdType Type, typename ValueType>
storm::dd::Bdd<Type> AddExpressionAdapter<Type, ValueType>::translateBooleanExpression(storm::expressions::Expression const& expression) {
STORM_LOG_THROW(expression.hasBooleanType(), storm::exceptions::InvalidArgumentException, "Expected expression of boolean type.");
return boost::any_cast<storm::dd::Bdd<Type>>(expression.accept(*this));
return boost::any_cast<storm::dd::Bdd<Type>>(expression.accept(*this, boost::none));
}
template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::IfThenElseExpression const& expression) {
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) {
if (expression.hasBooleanType()) {
storm::dd::Bdd<Type> elseDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getElseExpression()->accept(*this));
storm::dd::Bdd<Type> thenDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getThenExpression()->accept(*this));
storm::dd::Bdd<Type> conditionDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getCondition()->accept(*this));
storm::dd::Bdd<Type> elseDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getElseExpression()->accept(*this, data));
storm::dd::Bdd<Type> thenDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getThenExpression()->accept(*this, data));
storm::dd::Bdd<Type> conditionDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getCondition()->accept(*this, data));
return conditionDd.ite(thenDd, elseDd);
} else {
storm::dd::Add<Type, ValueType> elseDd = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getElseExpression()->accept(*this));
storm::dd::Add<Type, ValueType> thenDd = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getThenExpression()->accept(*this));
storm::dd::Bdd<Type> conditionDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getCondition()->accept(*this));
storm::dd::Add<Type, ValueType> elseDd = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getElseExpression()->accept(*this, data));
storm::dd::Add<Type, ValueType> thenDd = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getThenExpression()->accept(*this, data));
storm::dd::Bdd<Type> conditionDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getCondition()->accept(*this, data));
return conditionDd.ite(thenDd, elseDd);
}
}
template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression) {
storm::dd::Bdd<Type> leftResult = boost::any_cast<storm::dd::Bdd<Type>>(expression.getFirstOperand()->accept(*this));
storm::dd::Bdd<Type> rightResult = boost::any_cast<storm::dd::Bdd<Type>>(expression.getSecondOperand()->accept(*this));
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
storm::dd::Bdd<Type> leftResult = boost::any_cast<storm::dd::Bdd<Type>>(expression.getFirstOperand()->accept(*this, data));
storm::dd::Bdd<Type> rightResult = boost::any_cast<storm::dd::Bdd<Type>>(expression.getSecondOperand()->accept(*this, data));
storm::dd::Bdd<Type> result;
switch (expression.getOperatorType()) {
@ -74,9 +74,9 @@ namespace storm {
}
template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression) {
storm::dd::Add<Type, ValueType> leftResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getFirstOperand()->accept(*this));
storm::dd::Add<Type, ValueType> rightResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getSecondOperand()->accept(*this));
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
storm::dd::Add<Type, ValueType> leftResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getFirstOperand()->accept(*this, data));
storm::dd::Add<Type, ValueType> rightResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getSecondOperand()->accept(*this, data));
storm::dd::Add<Type, ValueType> result;
switch (expression.getOperatorType()) {
@ -109,9 +109,9 @@ namespace storm {
}
template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryRelationExpression const& expression) {
storm::dd::Add<Type, ValueType> leftResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getFirstOperand()->accept(*this));
storm::dd::Add<Type, ValueType> rightResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getSecondOperand()->accept(*this));
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) {
storm::dd::Add<Type, ValueType> leftResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getFirstOperand()->accept(*this, data));
storm::dd::Add<Type, ValueType> rightResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getSecondOperand()->accept(*this, data));
storm::dd::Bdd<Type> result;
switch (expression.getRelationType()) {
@ -139,7 +139,7 @@ namespace storm {
}
template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::VariableExpression const& expression) {
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::VariableExpression const& expression, boost::any const& data) {
auto const& variablePair = variableMapping->find(expression.getVariable());
STORM_LOG_THROW(variablePair != variableMapping->end(), storm::exceptions::InvalidArgumentException, "Cannot translate the given expression, because it contains the variable '" << expression.getVariableName() << "' for which no DD counterpart is known.");
if (expression.hasBooleanType()) {
@ -150,8 +150,8 @@ namespace storm {
}
template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression) {
storm::dd::Bdd<Type> result = boost::any_cast<storm::dd::Bdd<Type>>(expression.getOperand()->accept(*this));
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
storm::dd::Bdd<Type> result = boost::any_cast<storm::dd::Bdd<Type>>(expression.getOperand()->accept(*this, data));
switch (expression.getOperatorType()) {
case storm::expressions::UnaryBooleanFunctionExpression::OperatorType::Not:
@ -163,8 +163,8 @@ namespace storm {
}
template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression) {
storm::dd::Add<Type, ValueType> result = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getOperand()->accept(*this));
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
storm::dd::Add<Type, ValueType> result = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getOperand()->accept(*this, data));
switch (expression.getOperatorType()) {
case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Minus:
@ -184,18 +184,18 @@ namespace storm {
}
template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BooleanLiteralExpression const& expression) {
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data) {
return expression.getValue() ? ddManager->getBddOne() : ddManager->getBddZero();
}
template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::IntegerLiteralExpression const& expression) {
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) {
return ddManager->getConstant(static_cast<ValueType>(expression.getValue()));
}
template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::DoubleLiteralExpression const& expression) {
return ddManager->getConstant(static_cast<ValueType>(expression.getValue()));
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) {
return ddManager->getConstant(static_cast<ValueType>(expression.getValueAsDouble()));
}
// Explicitly instantiate the symbolic expression adapter

20
src/adapters/AddExpressionAdapter.h

@ -22,16 +22,16 @@ namespace storm {
storm::dd::Add<Type, ValueType> translateExpression(storm::expressions::Expression const& expression);
storm::dd::Bdd<Type> translateBooleanExpression(storm::expressions::Expression const& expression);
virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression) override;
virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression) override;
virtual boost::any visit(storm::expressions::VariableExpression const& expression) override;
virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression) override;
virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression) override;
virtual boost::any visit(storm::expressions::DoubleLiteralExpression const& expression) override;
virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) override;
private:
// The manager responsible for the DDs built by this adapter.

46
src/adapters/DereferenceIteratorAdapter.h

@ -0,0 +1,46 @@
#pragma once
#include <type_traits>
#include <boost/iterator/transform_iterator.hpp>
namespace storm {
namespace adapters {
template<typename T>
struct Dereferencer {
decltype((*std::declval<T>())) operator()(T const& t) const {
return *t;
}
};
template<typename ContainerType>
class DereferenceIteratorAdapter {
public:
typedef typename ContainerType::value_type value_type;
typedef typename std::conditional<std::is_const<ContainerType>::value, typename ContainerType::const_iterator, typename ContainerType::iterator>::type input_iterator;
typedef typename boost::transform_iterator<Dereferencer<value_type>, input_iterator> iterator;
DereferenceIteratorAdapter(input_iterator it, input_iterator ite) : it(it), ite(ite) {
// Intentionally left empty.
}
iterator begin() const {
return boost::make_transform_iterator(it, Dereferencer<value_type>());
}
iterator end() const {
return boost::make_transform_iterator(ite, Dereferencer<value_type>());
}
static iterator make_iterator(input_iterator it) {
return boost::make_transform_iterator(it, Dereferencer<value_type>());
}
private:
input_iterator it;
input_iterator ite;
};
}
}

46
src/adapters/MathsatExpressionAdapter.h

@ -57,7 +57,7 @@ namespace storm {
* @return An equivalent term for MathSAT.
*/
msat_term translateExpression(storm::expressions::Expression const& expression) {
msat_term result = boost::any_cast<msat_term>(expression.getBaseExpression().accept(*this));
msat_term result = boost::any_cast<msat_term>(expression.getBaseExpression().accept(*this, boost::none));
STORM_LOG_THROW(!MSAT_ERROR_TERM(result), storm::exceptions::ExpressionEvaluationException, "Could not translate expression to MathSAT's format.");
return result;
}
@ -90,9 +90,9 @@ namespace storm {
return declarationVariablePair->second;
}
virtual boost::any visit(expressions::BinaryBooleanFunctionExpression const& expression) override {
msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this));
msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this));
virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override {
msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this, data));
msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data));
switch (expression.getOperatorType()) {
case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::And:
@ -108,9 +108,9 @@ namespace storm {
}
}
virtual boost::any visit(expressions::BinaryNumericalFunctionExpression const& expression) override {
msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this));
msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this));
virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override {
msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this, data));
msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data));
switch (expression.getOperatorType()) {
case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Plus:
@ -130,9 +130,9 @@ namespace storm {
}
}
virtual boost::any visit(expressions::BinaryRelationExpression const& expression) override {
msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this));
msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this));
virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override {
msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this, data));
msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data));
switch (expression.getRelationType()) {
case storm::expressions::BinaryRelationExpression::RelationType::Equal:
@ -160,27 +160,27 @@ namespace storm {
}
}
virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression) override {
msat_term conditionResult = boost::any_cast<msat_term>(expression.getCondition()->accept(*this));
msat_term thenResult = boost::any_cast<msat_term>(expression.getThenExpression()->accept(*this));
msat_term elseResult = boost::any_cast<msat_term>(expression.getElseExpression()->accept(*this));
virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override {
msat_term conditionResult = boost::any_cast<msat_term>(expression.getCondition()->accept(*this, data));
msat_term thenResult = boost::any_cast<msat_term>(expression.getThenExpression()->accept(*this, data));
msat_term elseResult = boost::any_cast<msat_term>(expression.getElseExpression()->accept(*this, data));
return msat_make_term_ite(env, conditionResult, thenResult, elseResult);
}
virtual boost::any visit(expressions::BooleanLiteralExpression const& expression) override {
virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data) override {
return expression.getValue() ? msat_make_true(env) : msat_make_false(env);
}
virtual boost::any visit(expressions::DoubleLiteralExpression const& expression) override {
return msat_make_number(env, std::to_string(expression.getValue()).c_str());
virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) override {
return msat_make_number(env, std::to_string(expression.getValueAsDouble()).c_str());
}
virtual boost::any visit(expressions::IntegerLiteralExpression const& expression) override {
virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) override {
return msat_make_number(env, std::to_string(static_cast<int>(expression.getValue())).c_str());
}
virtual boost::any visit(expressions::UnaryBooleanFunctionExpression const& expression) override {
msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this));
virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override {
msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this, data));
switch (expression.getOperatorType()) {
case storm::expressions::UnaryBooleanFunctionExpression::OperatorType::Not:
@ -191,8 +191,8 @@ namespace storm {
}
}
virtual boost::any visit(expressions::UnaryNumericalFunctionExpression const& expression) override {
msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this));
virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override {
msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this, data));
switch (expression.getOperatorType()) {
case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Minus:
@ -209,7 +209,7 @@ namespace storm {
}
}
virtual boost::any visit(expressions::VariableExpression const& expression) override {
virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override {
return translateExpression(expression.getVariable());
}

46
src/adapters/Z3ExpressionAdapter.cpp

@ -16,7 +16,7 @@ namespace storm {
z3::expr Z3ExpressionAdapter::translateExpression(storm::expressions::Expression const& expression) {
STORM_LOG_ASSERT(expression.getManager() == this->manager, "Invalid expression for solver.");
z3::expr result = boost::any_cast<z3::expr>(expression.getBaseExpression().accept(*this));
z3::expr result = boost::any_cast<z3::expr>(expression.getBaseExpression().accept(*this, boost::none));
for (z3::expr const& assertion : additionalAssertions) {
result = result && assertion;
@ -139,9 +139,9 @@ namespace storm {
}
}
boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression) {
z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this));
z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this));
boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this, data));
z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this, data));
switch(expression.getOperatorType()) {
case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::And:
@ -160,9 +160,9 @@ namespace storm {
}
boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression) {
z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this));
z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this));
boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this, data));
z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this, data));
switch(expression.getOperatorType()) {
case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Plus:
@ -177,14 +177,16 @@ namespace storm {
return ite(leftResult <= rightResult, leftResult, rightResult);
case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Max:
return ite(leftResult >= rightResult, leftResult, rightResult);
case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Power:
return pw(leftResult,rightResult);
default:
STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression: unknown numerical binary operator '" << static_cast<int>(expression.getOperatorType()) << "' in expression " << expression << ".");
}
}
boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryRelationExpression const& expression) {
z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this));
z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this));
boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) {
z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this, data));
z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this, data));
switch(expression.getRelationType()) {
case storm::expressions::BinaryRelationExpression::RelationType::Equal:
@ -204,22 +206,22 @@ namespace storm {
}
}
boost::any Z3ExpressionAdapter::visit(storm::expressions::BooleanLiteralExpression const& expression) {
boost::any Z3ExpressionAdapter::visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data) {
return context.bool_val(expression.getValue());
}
boost::any Z3ExpressionAdapter::visit(storm::expressions::DoubleLiteralExpression const& expression) {
boost::any Z3ExpressionAdapter::visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) {
std::stringstream fractionStream;
fractionStream << expression.getValue();
return context.real_val(fractionStream.str().c_str());
}
boost::any Z3ExpressionAdapter::visit(storm::expressions::IntegerLiteralExpression const& expression) {
boost::any Z3ExpressionAdapter::visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) {
return context.int_val(static_cast<int>(expression.getValue()));
}
boost::any Z3ExpressionAdapter::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression) {
z3::expr childResult = boost::any_cast<z3::expr>(expression.getOperand()->accept(*this));
boost::any Z3ExpressionAdapter::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
z3::expr childResult = boost::any_cast<z3::expr>(expression.getOperand()->accept(*this, data));
switch (expression.getOperatorType()) {
case storm::expressions::UnaryBooleanFunctionExpression::OperatorType::Not:
@ -229,8 +231,8 @@ namespace storm {
}
}
boost::any Z3ExpressionAdapter::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression) {
z3::expr childResult = boost::any_cast<z3::expr>(expression.getOperand()->accept(*this));
boost::any Z3ExpressionAdapter::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
z3::expr childResult = boost::any_cast<z3::expr>(expression.getOperand()->accept(*this, data));
switch(expression.getOperatorType()) {
case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Minus:
@ -251,14 +253,14 @@ namespace storm {
}
}
boost::any Z3ExpressionAdapter::visit(storm::expressions::IfThenElseExpression const& expression) {
z3::expr conditionResult = boost::any_cast<z3::expr>(expression.getCondition()->accept(*this));
z3::expr thenResult = boost::any_cast<z3::expr>(expression.getThenExpression()->accept(*this));
z3::expr elseResult = boost::any_cast<z3::expr>(expression.getElseExpression()->accept(*this));
boost::any Z3ExpressionAdapter::visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) {
z3::expr conditionResult = boost::any_cast<z3::expr>(expression.getCondition()->accept(*this, data));
z3::expr thenResult = boost::any_cast<z3::expr>(expression.getThenExpression()->accept(*this, data));
z3::expr elseResult = boost::any_cast<z3::expr>(expression.getElseExpression()->accept(*this, data));
return z3::expr(context, Z3_mk_ite(context, conditionResult, thenResult, elseResult));
}
boost::any Z3ExpressionAdapter::visit(storm::expressions::VariableExpression const& expression) {
boost::any Z3ExpressionAdapter::visit(storm::expressions::VariableExpression const& expression, boost::any const& data) {
return this->translateExpression(expression.getVariable());
}

20
src/adapters/Z3ExpressionAdapter.h

@ -55,25 +55,25 @@ namespace storm {
*/
storm::expressions::Variable const& getVariable(z3::func_decl z3Declaration);
virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression) override;
virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression) override;
virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::DoubleLiteralExpression const& expression) override;
virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression) override;
virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression) override;
virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override;
virtual boost::any visit(storm::expressions::VariableExpression const& expression) override;
virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override;
private:
/*!

286
src/builder/DdJaniModelBuilder.cpp

@ -103,19 +103,13 @@ namespace storm {
}
template <storm::dd::DdType Type, typename ValueType>
DdJaniModelBuilder<Type, ValueType>::DdJaniModelBuilder(storm::jani::Model const& model, Options const& options) : model(model), options(options) {
if (this->model->hasUndefinedConstants()) {
std::vector<std::reference_wrapper<storm::jani::Constant const>> undefinedConstants = this->model->getUndefinedConstants();
std::vector<std::string> strings;
for (auto const& constant : undefinedConstants) {
std::stringstream stream;
stream << constant.get().getName() << " (" << constant.get().getType() << ")";
strings.push_back(stream.str());
}
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " << boost::join(strings, ", ") << ".");
}
this->model = this->model->substituteConstants();
std::set<std::string> const& DdJaniModelBuilder<Type, ValueType>::Options::getRewardModelNames() const {
return rewardModelsToBuild;
}
template <storm::dd::DdType Type, typename ValueType>
bool DdJaniModelBuilder<Type, ValueType>::Options::isBuildAllRewardModelsSet() const {
return buildAllRewardModels;
}
template <storm::dd::DdType Type, typename ValueType>
@ -188,11 +182,15 @@ namespace storm {
this->model.getSystemComposition().accept(*this, boost::none);
STORM_LOG_THROW(automata.size() == this->model.getNumberOfAutomata(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model whose system composition refers to a subset of automata.");
// Then, check that the model does not contain unbounded integer variables.
// Then, check that the model does not contain unbounded integer or non-transient real variables.
STORM_LOG_THROW(!this->model.getGlobalVariables().containsUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model that contains global unbounded integer variables.");
for (auto const& automaton : this->model.getAutomata()) {
STORM_LOG_THROW(!automaton.getVariables().containsUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model that contains unbounded integer variables in automaton '" << automaton.getName() << "'.");
}
STORM_LOG_THROW(!this->model.getGlobalVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model that contains global non-transient real variables.");
for (auto const& automaton : this->model.getAutomata()) {
STORM_LOG_THROW(!automaton.getVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model that contains non-transient real variables in automaton '" << automaton.getName() << "'.");
}
// Based on this assumption, we create the variables.
return createVariables();
@ -243,6 +241,7 @@ namespace storm {
// Start by creating a meta variable for the location of the automaton.
std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = result.manager->addMetaVariable("l_" + automaton.getName(), 0, automaton.getNumberOfLocations() - 1);
result.automatonToLocationVariableMap[automaton.getName()] = variablePair;
result.rowColumnMetaVariablePairs.push_back(variablePair);
// Add the location variable to the row/column variables.
result.rowMetaVariables.insert(variablePair.first);
@ -256,6 +255,11 @@ namespace storm {
// Create global variables.
storm::dd::Bdd<Type> globalVariableRanges = result.manager->getBddOne();
for (auto const& variable : this->model.getGlobalVariables()) {
// Only create the variable if it's non-transient.
if (variable.isTransient()) {
continue;
}
createVariable(variable, result);
globalVariableRanges &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable()));
}
@ -274,6 +278,11 @@ namespace storm {
// Then create variables for the variables of the automaton.
for (auto const& variable : automaton.getVariables()) {
// Only create the variable if it's non-transient.
if (variable.isTransient()) {
continue;
}
createVariable(variable, result);
identity &= result.variableToIdentityMap.at(variable.getExpressionVariable()).toBdd();
range &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable()));
@ -345,11 +354,13 @@ namespace storm {
template <storm::dd::DdType Type, typename ValueType>
struct ComposerResult {
ComposerResult(storm::dd::Add<Type, ValueType> const& transitions, storm::dd::Bdd<Type> const& illegalFragment, uint64_t numberOfNondeterminismVariables = 0) : transitions(transitions), illegalFragment(illegalFragment), numberOfNondeterminismVariables(numberOfNondeterminismVariables) {
ComposerResult(storm::dd::Add<Type, ValueType> const& transitions, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientLocationAssignments, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientEdgeAssignments, storm::dd::Bdd<Type> const& illegalFragment, uint64_t numberOfNondeterminismVariables = 0) : transitions(transitions), transientLocationAssignments(transientLocationAssignments), transientEdgeAssignments(transientEdgeAssignments), illegalFragment(illegalFragment), numberOfNondeterminismVariables(numberOfNondeterminismVariables) {
// Intentionally left empty.
}
storm::dd::Add<Type, ValueType> transitions;
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientLocationAssignments;
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
storm::dd::Bdd<Type> illegalFragment;
uint64_t numberOfNondeterminismVariables;
};
@ -358,7 +369,7 @@ namespace storm {
template <storm::dd::DdType Type, typename ValueType>
class SystemComposer : public storm::jani::CompositionVisitor {
public:
SystemComposer(storm::jani::Model const& model, CompositionVariables<Type, ValueType> const& variables) : model(model), variables(variables) {
SystemComposer(storm::jani::Model const& model, CompositionVariables<Type, ValueType> const& variables, std::vector<storm::expressions::Variable> const& transientVariables) : model(model), variables(variables), transientVariables(transientVariables) {
// Intentionally left empty.
}
@ -370,6 +381,9 @@ namespace storm {
// The variable to use when building an automaton.
CompositionVariables<Type, ValueType> const& variables;
// The transient variables to consider during system composition.
std::vector<storm::expressions::Variable> transientVariables;
};
// This structure represents an edge destination.
@ -391,7 +405,7 @@ namespace storm {
// Iterate over all assignments (boolean and integer) and build the DD for it.
std::set<storm::expressions::Variable> assignedVariables;
for (auto const& assignment : destination.getAssignments()) {
for (auto const& assignment : destination.getNonTransientAssignments()) {
// Record the variable as being written.
STORM_LOG_TRACE("Assigning to variable " << variables.variableToRowMetaVariableMap->at(assignment.getExpressionVariable()).getName());
assignedVariables.insert(assignment.getExpressionVariable());
@ -908,7 +922,7 @@ namespace storm {
public:
// This structure represents an edge.
struct EdgeDd {
EdgeDd(storm::dd::Add<Type> const& guard = storm::dd::Add<Type>(), storm::dd::Add<Type, ValueType> const& transitions = storm::dd::Add<Type, ValueType>(), std::set<storm::expressions::Variable> const& writtenGlobalVariables = {}) : guard(guard), transitions(transitions), writtenGlobalVariables(writtenGlobalVariables) {
EdgeDd(storm::dd::Add<Type> const& guard = storm::dd::Add<Type>(), storm::dd::Add<Type, ValueType> const& transitions = storm::dd::Add<Type, ValueType>(), std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientEdgeAssignments = {}, std::set<storm::expressions::Variable> const& writtenGlobalVariables = {}) : guard(guard), transitions(transitions), transientEdgeAssignments(transientEdgeAssignments), writtenGlobalVariables(writtenGlobalVariables) {
// Intentionally left empty.
}
@ -918,13 +932,16 @@ namespace storm {
// A DD that represents the transitions of this edge.
storm::dd::Add<Type, ValueType> transitions;
// A mapping from transient variables to the DDs representing their value assignments.
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
// The set of global variables written by this edge.
std::set<storm::expressions::Variable> writtenGlobalVariables;
};
// This structure represents an edge.
struct ActionDd {
ActionDd(storm::dd::Add<Type> const& guard = storm::dd::Add<Type>(), storm::dd::Add<Type, ValueType> const& transitions = storm::dd::Add<Type, ValueType>(), std::pair<uint64_t, uint64_t> localNondeterminismVariables = std::pair<uint64_t, uint64_t>(0, 0), std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> const& variableToWritingFragment = {}, storm::dd::Bdd<Type> const& illegalFragment = storm::dd::Bdd<Type>()) : guard(guard), transitions(transitions), localNondeterminismVariables(localNondeterminismVariables), variableToWritingFragment(variableToWritingFragment), illegalFragment(illegalFragment) {
ActionDd(storm::dd::Add<Type> const& guard = storm::dd::Add<Type>(), storm::dd::Add<Type, ValueType> const& transitions = storm::dd::Add<Type, ValueType>(), std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientEdgeAssignments = {}, std::pair<uint64_t, uint64_t> localNondeterminismVariables = std::pair<uint64_t, uint64_t>(0, 0), std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> const& variableToWritingFragment = {}, storm::dd::Bdd<Type> const& illegalFragment = storm::dd::Bdd<Type>()) : guard(guard), transitions(transitions), transientEdgeAssignments(transientEdgeAssignments), localNondeterminismVariables(localNondeterminismVariables), variableToWritingFragment(variableToWritingFragment), illegalFragment(illegalFragment) {
// Intentionally left empty.
}
@ -946,6 +963,9 @@ namespace storm {
// A DD that represents the transitions of this edge.
storm::dd::Add<Type, ValueType> transitions;
// A mapping from transient variables to their assignments.
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
// The local nondeterminism variables used by this action DD, given as the lowest
std::pair<uint64_t, uint64_t> localNondeterminismVariables;
@ -960,7 +980,7 @@ namespace storm {
// This structure represents a subcomponent of a composition.
struct AutomatonDd {
AutomatonDd(storm::dd::Add<Type, ValueType> const& identity) : actionIndexToAction(), identity(identity), localNondeterminismVariables(std::make_pair<uint64_t, uint64_t>(0, 0)) {
AutomatonDd(storm::dd::Add<Type, ValueType> const& identity, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientLocationAssignments = {}) : actionIndexToAction(), transientLocationAssignments(transientLocationAssignments), identity(identity), localNondeterminismVariables(std::make_pair<uint64_t, uint64_t>(0, 0)) {
// Intentionally left empty.
}
@ -988,6 +1008,9 @@ namespace storm {
// A mapping from action indices to the action DDs.
std::map<uint64_t, ActionDd> actionIndexToAction;
// A mapping from transient variables to their location-based transient assignment values.
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientLocationAssignments;
// The identity of the automaton's variables.
storm::dd::Add<Type, ValueType> identity;
@ -996,7 +1019,7 @@ namespace storm {
};
CombinedEdgesSystemComposer(storm::jani::Model const& model, CompositionVariables<Type, ValueType> const& variables) : SystemComposer<Type, ValueType>(model, variables) {
CombinedEdgesSystemComposer(storm::jani::Model const& model, CompositionVariables<Type, ValueType> const& variables, std::vector<storm::expressions::Variable> const& transientVariables) : SystemComposer<Type, ValueType>(model, variables, transientVariables) {
// Intentionally left empty.
}
@ -1080,6 +1103,7 @@ namespace storm {
private:
AutomatonDd composeInParallel(AutomatonDd const& automaton1, AutomatonDd const& automaton2, std::set<uint64_t> const& synchronizingActionIndices) {
AutomatonDd result(automaton1);
result.transientLocationAssignments = joinTransientAssignmentMaps(automaton1.transientLocationAssignments, automaton2.transientLocationAssignments);
// Treat all actions of the first automaton.
for (auto const& action1 : automaton1.actionIndexToAction) {
@ -1103,7 +1127,7 @@ namespace storm {
} else {
// If only the first automaton has this action, we only need to apply the identity of the
// second automaton.
result.actionIndexToAction[action1.first] = ActionDd(action1.second.guard, action1.second.transitions * automaton2.identity, action1.second.localNondeterminismVariables, action1.second.variableToWritingFragment, action1.second.illegalFragment);
result.actionIndexToAction[action1.first] = ActionDd(action1.second.guard, action1.second.transitions * automaton2.identity, action1.second.transientEdgeAssignments, action1.second.localNondeterminismVariables, action1.second.variableToWritingFragment, action1.second.illegalFragment);
}
}
}
@ -1116,7 +1140,7 @@ namespace storm {
if (synchronizingActionIndices.find(action2.first) == synchronizingActionIndices.end()) {
// If only the second automaton has this action, we only need to apply the identity of the
// first automaton.
result.actionIndexToAction[action2.first] = ActionDd(action2.second.guard, action2.second.transitions * automaton1.identity, action2.second.localNondeterminismVariables, action2.second.variableToWritingFragment, action2.second.illegalFragment);
result.actionIndexToAction[action2.first] = ActionDd(action2.second.guard, action2.second.transitions * automaton1.identity, action2.second.transientEdgeAssignments, action2.second.localNondeterminismVariables, action2.second.variableToWritingFragment, action2.second.illegalFragment);
}
}
}
@ -1152,7 +1176,7 @@ namespace storm {
}
}
return ActionDd(action1.guard * action2.guard, action1.transitions * action2.transitions, std::make_pair(std::min(action1.getLowestLocalNondeterminismVariable(), action2.getLowestLocalNondeterminismVariable()), std::max(action1.getHighestLocalNondeterminismVariable(), action2.getHighestLocalNondeterminismVariable())), globalVariableToWritingFragment, illegalFragment);
return ActionDd(combinedGuard.template toAdd<ValueType>(), action1.transitions * action2.transitions, joinTransientAssignmentMaps(action1.transientEdgeAssignments, action2.transientEdgeAssignments), std::make_pair(std::min(action1.getLowestLocalNondeterminismVariable(), action2.getLowestLocalNondeterminismVariable()), std::max(action1.getHighestLocalNondeterminismVariable(), action2.getHighestLocalNondeterminismVariable())), globalVariableToWritingFragment, illegalFragment);
}
ActionDd combineUnsynchronizedActions(ActionDd action1, ActionDd action2, storm::dd::Add<Type, ValueType> const& identity1, storm::dd::Add<Type, ValueType> const& identity2) {
@ -1169,7 +1193,7 @@ namespace storm {
STORM_LOG_TRACE("Combining unsynchronized actions.");
if (this->model.getModelType() == storm::jani::ModelType::DTMC || this->model.getModelType() == storm::jani::ModelType::CTMC) {
return ActionDd(action1.guard + action2.guard, action1.transitions + action2.transitions, std::make_pair<uint64_t, uint64_t>(0, 0), joinVariableWritingFragmentMaps(action1.variableToWritingFragment, action2.variableToWritingFragment), this->variables.manager->getBddZero());
return ActionDd(action1.guard + action2.guard, action1.transitions + action2.transitions, joinTransientAssignmentMaps(action1.transientEdgeAssignments, action2.transientEdgeAssignments), std::make_pair<uint64_t, uint64_t>(0, 0), joinVariableWritingFragmentMaps(action1.variableToWritingFragment, action2.variableToWritingFragment), this->variables.manager->getBddZero());
} else if (this->model.getModelType() == storm::jani::ModelType::MDP) {
if (action1.transitions.isZero()) {
return action2;
@ -1178,7 +1202,7 @@ namespace storm {
}
// Bring both choices to the same number of variables that encode the nondeterminism.
assert(action1.getLowestLocalNondeterminismVariable() == action2.getLowestLocalNondeterminismVariable());
STORM_LOG_ASSERT(action1.getLowestLocalNondeterminismVariable() == action2.getLowestLocalNondeterminismVariable(), "Mismatching lowest nondeterminism variable indices.");
uint_fast64_t highestLocalNondeterminismVariable = std::max(action1.getHighestLocalNondeterminismVariable(), action2.getHighestLocalNondeterminismVariable());
if (action1.getHighestLocalNondeterminismVariable() > action2.getHighestLocalNondeterminismVariable()) {
storm::dd::Add<Type, ValueType> nondeterminismEncoding = this->variables.manager->template getAddOne<ValueType>();
@ -1187,6 +1211,10 @@ namespace storm {
nondeterminismEncoding *= this->variables.manager->getEncoding(this->variables.localNondeterminismVariables[i], 0).template toAdd<ValueType>();
}
action2.transitions *= nondeterminismEncoding;
for (auto& transientAssignment : action2.transientEdgeAssignments) {
transientAssignment.second *= nondeterminismEncoding;
}
} else if (action2.getHighestLocalNondeterminismVariable() > action1.getHighestLocalNondeterminismVariable()) {
storm::dd::Add<Type, ValueType> nondeterminismEncoding = this->variables.manager->template getAddOne<ValueType>();
@ -1194,6 +1222,10 @@ namespace storm {
nondeterminismEncoding *= this->variables.manager->getEncoding(this->variables.localNondeterminismVariables[i], 0).template toAdd<ValueType>();
}
action1.transitions *= nondeterminismEncoding;
for (auto& transientAssignment : action1.transientEdgeAssignments) {
transientAssignment.second *= nondeterminismEncoding;
}
}
// Add a new variable that resolves the nondeterminism between the two choices.
@ -1207,14 +1239,14 @@ namespace storm {
entry.second = this->variables.manager->getEncoding(this->variables.localNondeterminismVariables[highestLocalNondeterminismVariable], 1) && entry.second;
}
return ActionDd((action1.guard.toBdd() || action2.guard.toBdd()).template toAdd<ValueType>(), combinedTransitions, std::make_pair(action1.getLowestLocalNondeterminismVariable(), highestLocalNondeterminismVariable + 1), joinVariableWritingFragmentMaps(action1.variableToWritingFragment, action2.variableToWritingFragment), action1.illegalFragment || action2.illegalFragment);
return ActionDd((action1.guard.toBdd() || action2.guard.toBdd()).template toAdd<ValueType>(), combinedTransitions, joinTransientAssignmentMaps(action1.transientEdgeAssignments, action2.transientEdgeAssignments), std::make_pair(action1.getLowestLocalNondeterminismVariable(), highestLocalNondeterminismVariable + 1), joinVariableWritingFragmentMaps(action1.variableToWritingFragment, action2.variableToWritingFragment), action1.illegalFragment || action2.illegalFragment);
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Illegal model type.");
}
}
AutomatonDd rename(AutomatonDd const& automaton, std::map<uint64_t, uint64_t> const& indexToIndex) {
AutomatonDd result(automaton.identity);
AutomatonDd result(automaton.identity, automaton.transientLocationAssignments);
for (auto const& action : automaton.actionIndexToAction) {
auto renamingIt = indexToIndex.find(action.first);
@ -1244,6 +1276,23 @@ namespace storm {
return result;
}
void performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function<void (storm::jani::Assignment const&)> const& callback) {
auto transientVariableIt = this->transientVariables.begin();
auto transientVariableIte = this->transientVariables.end();
for (auto const& assignment : transientAssignments) {
while (transientVariableIt != transientVariableIte && *transientVariableIt < assignment.getExpressionVariable()) {
++transientVariableIt;
}
if (transientVariableIt == transientVariableIte) {
break;
}
if (*transientVariableIt == assignment.getExpressionVariable()) {
callback(assignment);
++transientVariableIt;
}
}
}
EdgeDd buildEdgeDd(storm::jani::Automaton const& automaton, storm::jani::Edge const& edge) {
STORM_LOG_TRACE("Translating guard " << edge.getGuard());
@ -1309,7 +1358,13 @@ namespace storm {
transitions *= this->variables.rowExpressionAdapter->translateExpression(edge.getRate());
}
return EdgeDd(guard, guard * transitions, globalVariablesInSomeDestination);
// Finally treat the transient assignments.
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
if (!this->transientVariables.empty()) {
performTransientAssignments(edge.getAssignments().getTransientAssignments(), [this, &transientEdgeAssignments, &guard] (storm::jani::Assignment const& assignment) { transientEdgeAssignments[assignment.getExpressionVariable()] = guard * this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression()); } );
}
return EdgeDd(guard, guard * transitions, transientEdgeAssignments, globalVariablesInSomeDestination);
} else {
return EdgeDd(this->variables.manager->template getAddZero<ValueType>(), this->variables.manager->template getAddZero<ValueType>());
}
@ -1338,16 +1393,52 @@ namespace storm {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot translate model of this type.");
}
} else {
return ActionDd(this->variables.manager->template getAddZero<ValueType>(), this->variables.manager->template getAddZero<ValueType>(), std::make_pair<uint64_t, uint64_t>(0, 0), {}, this->variables.manager->getBddZero());
return ActionDd(this->variables.manager->template getAddZero<ValueType>(), this->variables.manager->template getAddZero<ValueType>(), {}, std::make_pair<uint64_t, uint64_t>(0, 0), {}, this->variables.manager->getBddZero());
}
}
void addToTransientAssignmentMap(std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>>& transientAssignments, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& assignmentsToAdd) {
for (auto const& entry : assignmentsToAdd) {
auto it = transientAssignments.find(entry.first);
if (it != transientAssignments.end()) {
it->second += entry.second;
} else {
transientAssignments[entry.first] = entry.second;
}
}
}
void addToTransientAssignmentMap(std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>>& transientAssignments, storm::expressions::Variable const& variable, storm::dd::Add<Type, ValueType> const& assignmentToAdd) {
auto it = transientAssignments.find(variable);
if (it != transientAssignments.end()) {
it->second += assignmentToAdd;
} else {
transientAssignments[variable] = assignmentToAdd;
}
}
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> joinTransientAssignmentMaps(std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientAssignments1, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientAssignments2) {
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> result = transientAssignments1;
for (auto const& entry : transientAssignments2) {
auto resultIt = result.find(entry.first);
if (resultIt != result.end()) {
resultIt->second += entry.second;
} else {
result[entry.first] = entry.second;
}
}
return result;
}
ActionDd combineEdgesToActionMarkovChain(std::vector<EdgeDd> const& edgeDds) {
storm::dd::Bdd<Type> allGuards = this->variables.manager->getBddZero();
storm::dd::Add<Type, ValueType> allTransitions = this->variables.manager->template getAddZero<ValueType>();
storm::dd::Bdd<Type> temporary;
std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
for (auto const& edgeDd : edgeDds) {
// Check for overlapping guards.
storm::dd::Bdd<Type> guardBdd = edgeDd.guard.toBdd();
@ -1360,6 +1451,9 @@ namespace storm {
allGuards |= guardBdd;
allTransitions += edgeDd.transitions;
// Add the transient variable assignments to the resulting one.
addToTransientAssignmentMap(transientEdgeAssignments, edgeDd.transientEdgeAssignments);
// Keep track of the fragment that is writing global variables.
for (auto const& variable : edgeDd.writtenGlobalVariables) {
auto it = globalVariableToWritingFragment.find(variable);
@ -1371,7 +1465,7 @@ namespace storm {
}
}
return ActionDd(allGuards.template toAdd<ValueType>(), allTransitions, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment, this->variables.manager->getBddZero());
return ActionDd(allGuards.template toAdd<ValueType>(), allTransitions, transientEdgeAssignments, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment, this->variables.manager->getBddZero());
}
void addToVariableWritingFragmentMap(std::map<storm::expressions::Variable, storm::dd::Bdd<Type>>& globalVariableToWritingFragment, storm::expressions::Variable const& variable, storm::dd::Bdd<Type> const& partToAdd) const {
@ -1401,13 +1495,15 @@ namespace storm {
ActionDd combineEdgesBySummation(storm::dd::Add<Type, ValueType> const& guard, std::vector<EdgeDd> const& edges) {
storm::dd::Add<Type, ValueType> transitions = this->variables.manager->template getAddZero<ValueType>();
std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
for (auto const& edge : edges) {
transitions += edge.transitions;
addToTransientAssignmentMap(transientEdgeAssignments, edge.transientEdgeAssignments);
for (auto const& variable : edge.writtenGlobalVariables) {
addToVariableWritingFragmentMap(globalVariableToWritingFragment, variable, edge.guard.toBdd());
}
}
return ActionDd(guard, transitions, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment, this->variables.manager->getBddZero());
return ActionDd(guard, transitions, transientEdgeAssignments, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment, this->variables.manager->getBddZero());
}
ActionDd combineEdgesToActionMdp(std::vector<EdgeDd> const& edges, uint64_t localNondeterminismVariableOffset) {
@ -1430,6 +1526,7 @@ namespace storm {
storm::dd::Add<Type, ValueType> allEdges = this->variables.manager->template getAddZero<ValueType>();
std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientAssignments;
storm::dd::Bdd<Type> equalsNumberOfChoicesDd;
std::vector<storm::dd::Add<Type, ValueType>> choiceDds(maxChoices, this->variables.manager->template getAddZero<ValueType>());
@ -1480,6 +1577,11 @@ namespace storm {
// Combine the overlapping part of the guard with command updates and add it to the resulting DD.
choiceDds[k] += remainingGuardChoicesIntersection.template toAdd<ValueType>() * currentEdge.transitions;
// Keep track of the fragment of transient assignments.
for (auto const& transientAssignment : currentEdge.transientEdgeAssignments) {
addToTransientAssignmentMap(transientAssignments, transientAssignment.first, remainingGuardChoicesIntersection.template toAdd<ValueType>() * transientAssignment.second * indicesEncodedWithLocalNondeterminismVariables[k].first.template toAdd<ValueType>());
}
// Keep track of the written global variables of the fragment.
for (auto const& variable : currentEdge.writtenGlobalVariables) {
addToVariableWritingFragmentMap(globalVariableToWritingFragment, variable, remainingGuardChoicesIntersection && indicesEncodedWithLocalNondeterminismVariables[k].first);
@ -1505,7 +1607,7 @@ namespace storm {
sumOfGuards = sumOfGuards * (!equalsNumberOfChoicesDd).template toAdd<ValueType>();
}
return ActionDd(allGuards.template toAdd<ValueType>(), allEdges, std::make_pair(localNondeterminismVariableOffset, localNondeterminismVariableOffset + numberOfBinaryVariables), globalVariableToWritingFragment, this->variables.manager->getBddZero());
return ActionDd(allGuards.template toAdd<ValueType>(), allEdges, transientAssignments, std::make_pair(localNondeterminismVariableOffset, localNondeterminismVariableOffset + numberOfBinaryVariables), globalVariableToWritingFragment, this->variables.manager->getBddZero());
}
}
@ -1523,6 +1625,20 @@ namespace storm {
result.setLowestLocalNondeterminismVariable(std::max(result.getLowestLocalNondeterminismVariable(), actionDd.getLowestLocalNondeterminismVariable()));
result.setHighestLocalNondeterminismVariable(std::max(result.getHighestLocalNondeterminismVariable(), actionDd.getHighestLocalNondeterminismVariable()));
}
for (uint64_t locationIndex = 0; locationIndex < automaton.getNumberOfLocations(); ++locationIndex) {
auto const& location = automaton.getLocation(locationIndex);
performTransientAssignments(location.getAssignments().getTransientAssignments(), [this,&automatonName,locationIndex,&result] (storm::jani::Assignment const& assignment) {
storm::dd::Add<Type, ValueType> assignedValues = this->variables.manager->getEncoding(this->variables.automatonToLocationVariableMap.at(automatonName).first, locationIndex).template toAdd<ValueType>() * this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression());
auto it = result.transientLocationAssignments.find(assignment.getExpressionVariable());
if (it != result.transientLocationAssignments.end()) {
it->second += assignedValues;
} else {
result.transientLocationAssignments[assignment.getExpressionVariable()] = assignedValues;
}
});
}
return result;
}
@ -1553,28 +1669,36 @@ namespace storm {
uint64_t numberOfUsedNondeterminismVariables = automaton.getHighestLocalNondeterminismVariable();
// Add missing global variable identities, action and nondeterminism encodings.
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
for (auto& action : automaton.actionIndexToAction) {
illegalFragment |= action.second.illegalFragment;
addMissingGlobalVariableIdentities(action.second);
storm::dd::Add<Type, ValueType> actionEncoding = encodeAction(action.first != this->model.getSilentActionIndex() ? boost::optional<uint64_t>(action.first) : boost::none, this->variables);
storm::dd::Add<Type, ValueType> missingNondeterminismEncoding = encodeIndex(0, action.second.getHighestLocalNondeterminismVariable(), numberOfUsedNondeterminismVariables - action.second.getHighestLocalNondeterminismVariable(), this->variables);
storm::dd::Add<Type, ValueType> extendedTransitions = actionEncoding * missingNondeterminismEncoding * action.second.transitions;
for (auto const& transientAssignment : action.second.transientEdgeAssignments) {
addToTransientAssignmentMap(transientEdgeAssignments, transientAssignment.first, actionEncoding * missingNondeterminismEncoding * transientAssignment.second);
}
result += extendedTransitions;
}
return ComposerResult<Type, ValueType>(result, illegalFragment, numberOfUsedNondeterminismVariables);
return ComposerResult<Type, ValueType>(result, automaton.transientLocationAssignments, transientEdgeAssignments, illegalFragment, numberOfUsedNondeterminismVariables);
} else if (this->model.getModelType() == storm::jani::ModelType::DTMC || this->model.getModelType() == storm::jani::ModelType::CTMC) {
// Simply add all actions, but make sure to include the missing global variable identities.
storm::dd::Add<Type, ValueType> result = this->variables.manager->template getAddZero<ValueType>();
storm::dd::Bdd<Type> illegalFragment = this->variables.manager->getBddZero();
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
for (auto& action : automaton.actionIndexToAction) {
illegalFragment |= action.second.illegalFragment;
addMissingGlobalVariableIdentities(action.second);
addToTransientAssignmentMap(transientEdgeAssignments, action.second.transientEdgeAssignments);
result += action.second.transitions;
}
return ComposerResult<Type, ValueType>(result, illegalFragment, 0);
return ComposerResult<Type, ValueType>(result, automaton.transientLocationAssignments, transientEdgeAssignments, illegalFragment, 0);
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Illegal model type.");
}
@ -1718,31 +1842,100 @@ namespace storm {
}
template <storm::dd::DdType Type, typename ValueType>
std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdJaniModelBuilder<Type, ValueType>::build() {
std::vector<storm::expressions::Variable> selectRewardVariables(storm::jani::Model const& model, typename DdJaniModelBuilder<Type, ValueType>::Options const& options) {
std::vector<storm::expressions::Variable> result;
if (options.isBuildAllRewardModelsSet()) {
for (auto const& variable : model.getGlobalVariables()) {
if (variable.isTransient()) {
result.push_back(variable.getExpressionVariable());
}
}
} else {
auto const& globalVariables = model.getGlobalVariables();
for (auto const& rewardModelName : options.getRewardModelNames()) {
if (globalVariables.hasVariable(rewardModelName)) {
result.push_back(globalVariables.getVariable(rewardModelName).getExpressionVariable());
} else {
STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException, "Cannot build unknown reward model '" << rewardModelName << "'.");
STORM_LOG_THROW(globalVariables.getNumberOfTransientVariables() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous.");
}
}
// If no reward model was yet added, but there was one that was given in the options, we try to build the
// standard reward model.
if (result.empty() && !options.getRewardModelNames().empty()) {
result.push_back(globalVariables.getTransientVariables().front()->getExpressionVariable());
}
}
return result;
}
template <storm::dd::DdType Type, typename ValueType>
std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<Type, ValueType>> buildRewardModels(ComposerResult<Type, ValueType> const& system, std::vector<storm::expressions::Variable> const& rewardVariables) {
std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<Type, ValueType>> result;
for (auto const& variable : rewardVariables) {
boost::optional<storm::dd::Add<Type, ValueType>> stateRewards = boost::none;
boost::optional<storm::dd::Add<Type, ValueType>> stateActionRewards = boost::none;
boost::optional<storm::dd::Add<Type, ValueType>> transitionRewards = boost::none;
auto it = system.transientLocationAssignments.find(variable);
if (it != system.transientLocationAssignments.end()) {
stateRewards = it->second;
}
it = system.transientEdgeAssignments.find(variable);
if (it != system.transientEdgeAssignments.end()) {
stateActionRewards = it->second;
}
result.emplace(variable.getName(), storm::models::symbolic::StandardRewardModel<Type, ValueType>(stateRewards, stateActionRewards, transitionRewards));
}
return result;
}
template <storm::dd::DdType Type, typename ValueType>
std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdJaniModelBuilder<Type, ValueType>::build(storm::jani::Model const& model, Options const& options) {
if (model.hasUndefinedConstants()) {
std::vector<std::reference_wrapper<storm::jani::Constant const>> undefinedConstants = model.getUndefinedConstants();
std::vector<std::string> strings;
for (auto const& constant : undefinedConstants) {
std::stringstream stream;
stream << constant.get().getName() << " (" << constant.get().getType() << ")";
strings.push_back(stream.str());
}
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Model still contains these undefined constants: " << boost::join(strings, ", ") << ".");
}
// Create all necessary variables.
CompositionVariableCreator<Type, ValueType> variableCreator(*this->model);
CompositionVariableCreator<Type, ValueType> variableCreator(model);
CompositionVariables<Type, ValueType> variables = variableCreator.create();
// Determine which transient assignments need to be considered in the building process.
std::vector<storm::expressions::Variable> rewardVariables = selectRewardVariables<Type, ValueType>(model, options);
// Create a builder to compose and build the model.
// SeparateEdgesSystemComposer<Type, ValueType> composer(*this->model, variables);
CombinedEdgesSystemComposer<Type, ValueType> composer(*this->model, variables);
// SeparateEdgesSystemComposer<Type, ValueType> composer(model, variables);
CombinedEdgesSystemComposer<Type, ValueType> composer(model, variables, rewardVariables);
ComposerResult<Type, ValueType> system = composer.compose();
// Postprocess the variables in place.
postprocessVariables(this->model->getModelType(), system, variables);
postprocessVariables(model.getModelType(), system, variables);
// Postprocess the system in place and get the states that were terminal (i.e. whose transitions were cut off).
storm::dd::Bdd<Type> terminalStates = postprocessSystem(*this->model, system, variables, options);
storm::dd::Bdd<Type> terminalStates = postprocessSystem(model, system, variables, options);
// Start creating the model components.
ModelComponents<Type, ValueType> modelComponents;
// Build initial states.
modelComponents.initialStates = computeInitialStates(*this->model, variables);
modelComponents.initialStates = computeInitialStates(model, variables);
// Perform reachability analysis to obtain reachable states.
storm::dd::Bdd<Type> transitionMatrixBdd = system.transitions.notZero();
if (this->model->getModelType() == storm::jani::ModelType::MDP) {
if (model.getModelType() == storm::jani::ModelType::MDP) {
transitionMatrixBdd = transitionMatrixBdd.existsAbstract(variables.allNondeterminismVariables);
}
modelComponents.reachableStates = storm::utility::dd::computeReachableStates(modelComponents.initialStates, transitionMatrixBdd, variables.rowMetaVariables, variables.columnMetaVariables);
@ -1756,13 +1949,16 @@ namespace storm {
modelComponents.transitionMatrix = system.transitions * reachableStatesAdd;
// Fix deadlocks if existing.
modelComponents.deadlockStates = fixDeadlocks(this->model->getModelType(), modelComponents.transitionMatrix, transitionMatrixBdd, modelComponents.reachableStates, variables);
modelComponents.deadlockStates = fixDeadlocks(model.getModelType(), modelComponents.transitionMatrix, transitionMatrixBdd, modelComponents.reachableStates, variables);
// Cut the deadlock states by removing all states that we 'converted' to deadlock states by making them terminal.
modelComponents.deadlockStates = modelComponents.deadlockStates && !terminalStates;
// Build the reward models.
modelComponents.rewardModels = buildRewardModels(system, rewardVariables);
// Finally, create the model.
return createModel(this->model->getModelType(), variables, modelComponents);
return createModel(model.getModelType(), variables, modelComponents);
}
template class DdJaniModelBuilder<storm::dd::DdType::CUDD, double>;

32
src/builder/DdJaniModelBuilder.h

@ -59,6 +59,16 @@ namespace storm {
*/
void setTerminalStatesFromFormula(storm::logic::Formula const& formula);
/*!
* Retrieves the names of the reward models to build.
*/
std::set<std::string> const& getRewardModelNames() const;
/*!
* Retrieves whether the flag to build all reward models is set.
*/
bool isBuildAllRewardModelsSet() const;
// A flag that indicates whether or not all reward models are to be build.
bool buildAllRewardModels;
@ -77,11 +87,6 @@ namespace storm {
boost::optional<storm::expressions::Expression> negatedTerminalStates;
};
/*!
* Creates a builder for the given model that uses the given options.
*/
DdJaniModelBuilder(storm::jani::Model const& model, Options const& options = Options());
/*!
* Translates the given program into a symbolic model (i.e. one that stores the transition relation as a
* decision diagram).
@ -89,22 +94,7 @@ namespace storm {
* @param model The model to translate.
* @return A pointer to the resulting model.
*/
std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> build();
/*!
* Retrieves the model that was actually translated (i.e. including constant substitutions etc.). Note
* that this function may only be called after a succesful translation.
*
* @return The translated model.
*/
storm::jani::Model const& getTranslatedModel() const;
private:
/// The model to translate.
boost::optional<storm::jani::Model> model;
/// The options to use for building the model.
Options options;
std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> build(storm::jani::Model const& model, Options const& options = Options());
};
}

37
src/builder/DdPrismModelBuilder.cpp

@ -1219,20 +1219,15 @@ namespace storm {
}
}
stateActionRewards.get().exportToDot("prismrew.dot");
return storm::models::symbolic::StandardRewardModel<Type, ValueType>(stateRewards, stateActionRewards, transitionRewards);
}
template <storm::dd::DdType Type, typename ValueType>
storm::prism::Program const& DdPrismModelBuilder<Type, ValueType>::getTranslatedProgram() const {
return preparedProgram.get();
}
template <storm::dd::DdType Type, typename ValueType>
std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdPrismModelBuilder<Type, ValueType>::build(storm::prism::Program const& program, Options const& options) {
preparedProgram = program;
if (preparedProgram->hasUndefinedConstants()) {
std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = preparedProgram->getUndefinedConstants();
if (program.hasUndefinedConstants()) {
std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = program.getUndefinedConstants();
std::stringstream stream;
bool printComma = false;
for (auto const& constant : undefinedConstants) {
@ -1247,13 +1242,11 @@ namespace storm {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " + stream.str());
}
preparedProgram = preparedProgram->substituteConstants();
STORM_LOG_DEBUG("Building representation of program:" << std::endl << *preparedProgram << std::endl);
STORM_LOG_DEBUG("Building representation of program:" << std::endl << program << std::endl);
// Start by initializing the structure used for storing all information needed during the model generation.
// In particular, this creates the meta variables used to encode the model.
GenerationInformation generationInfo(*preparedProgram);
GenerationInformation generationInfo(program);
SystemResult system = createSystemDecisionDiagram(generationInfo);
storm::dd::Add<Type, ValueType> transitionMatrix = system.allTransitionsDd;
@ -1264,7 +1257,7 @@ namespace storm {
// If we were asked to treat some states as terminal states, we cut away their transitions now.
storm::dd::Bdd<Type> terminalStatesBdd = generationInfo.manager->getBddZero();
if (options.terminalStates || options.negatedTerminalStates) {
std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = preparedProgram->getConstantsSubstitution();
std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = program.getConstantsSubstitution();
if (options.terminalStates) {
storm::expressions::Expression terminalExpression;
@ -1273,7 +1266,7 @@ namespace storm {
} else {
std::string const& labelName = boost::get<std::string>(options.terminalStates.get());
if (program.hasLabel(labelName)) {
terminalExpression = preparedProgram->getLabelExpression(labelName);
terminalExpression = program.getLabelExpression(labelName);
} else {
STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'.");
}
@ -1294,7 +1287,7 @@ namespace storm {
} else {
std::string const& labelName = boost::get<std::string>(options.negatedTerminalStates.get());
if (program.hasLabel(labelName)) {
negatedTerminalExpression = preparedProgram->getLabelExpression(labelName);
negatedTerminalExpression = program.getLabelExpression(labelName);
} else {
STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'.");
}
@ -1377,18 +1370,18 @@ namespace storm {
// First, we make sure that all selected reward models actually exist.
for (auto const& rewardModelName : options.rewardModelsToBuild) {
STORM_LOG_THROW(rewardModelName.empty() || preparedProgram->hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException, "Model does not possess a reward model with the name '" << rewardModelName << "'.");
STORM_LOG_THROW(rewardModelName.empty() || program.hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException, "Model does not possess a reward model with the name '" << rewardModelName << "'.");
}
for (auto const& rewardModel : preparedProgram->getRewardModels()) {
for (auto const& rewardModel : program.getRewardModels()) {
if (options.buildAllRewardModels || options.rewardModelsToBuild.find(rewardModel.getName()) != options.rewardModelsToBuild.end()) {
selectedRewardModels.push_back(rewardModel);
}
}
// If no reward model was selected until now and a referenced reward model appears to be unique, we build
// the only existing reward model (given that no explicit name was given for the referenced reward model).
if (selectedRewardModels.empty() && preparedProgram->getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") {
selectedRewardModels.push_back(preparedProgram->getRewardModel(0));
if (selectedRewardModels.empty() && program.getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") {
selectedRewardModels.push_back(program.getRewardModel(0));
}
std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<Type, ValueType>> rewardModels;
@ -1398,7 +1391,7 @@ namespace storm {
// Build the labels that can be accessed as a shortcut.
std::map<std::string, storm::expressions::Expression> labelToExpressionMapping;
for (auto const& label : preparedProgram->getLabels()) {
for (auto const& label : program.getLabels()) {
labelToExpressionMapping.emplace(label.getName(), label.getStatePredicateExpression());
}
@ -1415,7 +1408,7 @@ namespace storm {
template <storm::dd::DdType Type, typename ValueType>
storm::dd::Bdd<Type> DdPrismModelBuilder<Type, ValueType>::createInitialStatesDecisionDiagram(GenerationInformation& generationInfo) {
storm::dd::Bdd<Type> initialStates = generationInfo.rowExpressionAdapter->translateExpression(generationInfo.program.getInitialConstruct().getInitialStatesExpression()).toBdd();
storm::dd::Bdd<Type> initialStates = generationInfo.rowExpressionAdapter->translateExpression(generationInfo.program.getInitialStatesExpression()).toBdd();
for (auto const& metaVariable : generationInfo.rowMetaVariables) {
initialStates &= generationInfo.manager->getRange(metaVariable);

11
src/builder/DdPrismModelBuilder.h

@ -98,14 +98,6 @@ namespace storm {
*/
std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> build(storm::prism::Program const& program, Options const& options = Options());
/*!
* Retrieves the program that was actually translated (i.e. including constant substitutions etc.). Note
* that this function may only be called after a succesful translation.
*
* @return The translated program.
*/
storm::prism::Program const& getTranslatedProgram() const;
private:
// This structure can store the decision diagrams representing a particular action.
struct UpdateDecisionDiagram {
@ -243,9 +235,6 @@ namespace storm {
static SystemResult createSystemDecisionDiagram(GenerationInformation& generationInfo);
static storm::dd::Bdd<Type> createInitialStatesDecisionDiagram(GenerationInformation& generationInfo);
// This member holds the program that was most recently translated (if any).
boost::optional<storm::prism::Program> preparedProgram;
};
} // namespace adapters

40
src/cli/cli.cpp

@ -3,6 +3,8 @@
#include "../utility/storm.h"
#include "src/storage/SymbolicModelDescription.h"
#include "src/settings/modules/DebugSettings.h"
#include "src/settings/modules/IOSettings.h"
#include "src/settings/modules/CoreSettings.h"
@ -206,42 +208,46 @@ namespace storm {
storm::utility::initializeFileLogging();
}
if (storm::settings::getModule<storm::settings::modules::IOSettings>().isSymbolicSet()) {
// If we have to build the model from a symbolic representation, we need to parse the representation first.
storm::prism::Program program = storm::parseProgram(storm::settings::getModule<storm::settings::modules::IOSettings>().getSymbolicModelFilename());
auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
if (ioSettings.isPrismOrJaniInputSet()) {
storm::storage::SymbolicModelDescription model;
if (ioSettings.isPrismInputSet()) {
model = storm::parseProgram(ioSettings.getPrismInputFilename());
if (ioSettings.isPrismToJaniSet()) {
model = model.toJani(true);
}
} else if (ioSettings.isJaniInputSet()) {
model = storm::parseJaniModel(ioSettings.getJaniInputFilename()).first;
}
// Get the string that assigns values to the unknown currently undefined constants in the model.
std::string constantDefinitionString = storm::settings::getModule<storm::settings::modules::IOSettings>().getConstantDefinitionString();
storm::prism::Program preprocessedProgram = storm::utility::prism::preprocess(program, constantDefinitionString);
std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = preprocessedProgram.getConstantsSubstitution();
std::string constantDefinitionString = ioSettings.getConstantDefinitionString();
model = model.preprocess(constantDefinitionString);
// Then proceed to parsing the properties (if given), since the model we are building may depend on the property.
std::vector<std::shared_ptr<storm::logic::Formula const>> formulas;
if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isPropertySet()) {
formulas = storm::parseFormulasForProgram(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), preprocessedProgram);
}
// There may be constants of the model appearing in the formulas, so we replace all their occurrences
// by their definitions in the translated program.
std::vector<std::shared_ptr<storm::logic::Formula const>> preprocessedFormulas;
for (auto const& formula : formulas) {
preprocessedFormulas.emplace_back(formula->substitute(constantsSubstitution));
if (model.isJaniModel()) {
formulas = storm::parseFormulasForJaniModel(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), model.asJaniModel());
} else {
formulas = storm::parseFormulasForPrismProgram(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), model.asPrismProgram());
}
}
if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isParametricSet()) {
#ifdef STORM_HAVE_CARL
buildAndCheckSymbolicModel<storm::RationalFunction>(preprocessedProgram, preprocessedFormulas, true);
buildAndCheckSymbolicModel<storm::RationalFunction>(model, formulas, true);
#else
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No parameters are supported in this build.");
#endif
} else if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isExactSet()) {
#ifdef STORM_HAVE_CARL
buildAndCheckSymbolicModel<storm::RationalNumber>(preprocessedProgram, preprocessedFormulas, true);
buildAndCheckSymbolicModel<storm::RationalNumber>(model, formulas, true);
#else
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No exact numbers are supported in this build.");
#endif
} else {
buildAndCheckSymbolicModel<double>(preprocessedProgram, preprocessedFormulas, true);
buildAndCheckSymbolicModel<double>(model, formulas, true);
}
} else if (storm::settings::getModule<storm::settings::modules::IOSettings>().isExplicitSet()) {
STORM_LOG_THROW(storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Only the sparse engine supports explicit model input.");

56
src/cli/entrypoints.h

@ -3,7 +3,10 @@
#include "src/utility/storm.h"
#include "src/storage/SymbolicModelDescription.h"
#include "src/exceptions/NotImplementedException.h"
#include "src/exceptions/InvalidSettingsException.h"
namespace storm {
namespace cli {
@ -49,12 +52,14 @@ namespace storm {
#endif
template<storm::dd::DdType DdType>
void verifySymbolicModelWithAbstractionRefinementEngine(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
void verifySymbolicModelWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Abstraction Refinement is not yet implemented.");
}
template<typename ValueType>
void verifySymbolicModelWithExplorationEngine(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
void verifySymbolicModelWithExplorationEngine(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
STORM_LOG_THROW(model.isPrismProgram(), storm::exceptions::InvalidSettingsException, "Exploration engine is currently only applicable to PRISM models.");
storm::prism::Program const& program = model.asPrismProgram();
STORM_LOG_THROW(program.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::MDP, storm::exceptions::InvalidSettingsException, "Currently exploration-based verification is only available for DTMCs and MDPs.");
for (auto const& formula : formulas) {
@ -98,7 +103,7 @@ namespace storm {
#ifdef STORM_HAVE_CARL
template<>
void verifySymbolicModelWithExplorationEngine<storm::RationalFunction>(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) {
void verifySymbolicModelWithExplorationEngine<storm::RationalFunction>(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Exploration-based verification does currently not support parametric models.");
}
#endif
@ -177,81 +182,80 @@ namespace storm {
}
template<storm::dd::DdType LibraryType>
void buildAndCheckSymbolicModelWithSymbolicEngine(bool hybrid, storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
void buildAndCheckSymbolicModelWithSymbolicEngine(bool hybrid, storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
// Start by building the model.
auto model = buildSymbolicModel<double, LibraryType>(program, formulas);
auto markovModel = buildSymbolicModel<double, LibraryType>(model, formulas);
// Print some information about the model.
model->printModelInformationToStream(std::cout);
markovModel->printModelInformationToStream(std::cout);
// Then select the correct engine.
if (hybrid) {
verifySymbolicModelWithHybridEngine(model, formulas, onlyInitialStatesRelevant);
verifySymbolicModelWithHybridEngine(markovModel, formulas, onlyInitialStatesRelevant);
} else {
verifySymbolicModelWithDdEngine(model, formulas, onlyInitialStatesRelevant);
verifySymbolicModelWithDdEngine(markovModel, formulas, onlyInitialStatesRelevant);
}
}
template<typename ValueType>
void buildAndCheckSymbolicModelWithSparseEngine(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
void buildAndCheckSymbolicModelWithSparseEngine(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
// Start by building the model.
std::shared_ptr<storm::models::ModelBase> model = buildSparseModel<ValueType>(program, formulas);
std::shared_ptr<storm::models::ModelBase> markovModel = buildSparseModel<ValueType>(model, formulas);
// Print some information about the model.
model->printModelInformationToStream(std::cout);
markovModel->printModelInformationToStream(std::cout);
// Preprocess the model.
BRANCH_ON_SPARSE_MODELTYPE(model, model, ValueType, preprocessModel, formulas);
BRANCH_ON_SPARSE_MODELTYPE(markovModel, markovModel, ValueType, preprocessModel, formulas);
std::shared_ptr<storm::models::sparse::Model<ValueType>> sparseModel = model->template as<storm::models::sparse::Model<ValueType>>();
std::shared_ptr<storm::models::sparse::Model<ValueType>> sparseModel = markovModel->template as<storm::models::sparse::Model<ValueType>>();
// Finally, treat the formulas.
if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isCounterexampleSet()) {
generateCounterexamples<ValueType>(program, sparseModel, formulas);
generateCounterexamples<ValueType>(model, sparseModel, formulas);
} else {
verifySparseModel<ValueType>(sparseModel, formulas, onlyInitialStatesRelevant);
}
}
template<typename ValueType>
void buildAndCheckSymbolicModel(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
void buildAndCheckSymbolicModel(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
if (storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::AbstractionRefinement) {
auto ddlib = storm::settings::getModule<storm::settings::modules::CoreSettings>().getDdLibraryType();
if (ddlib == storm::dd::DdType::CUDD) {
verifySymbolicModelWithAbstractionRefinementEngine<storm::dd::DdType::CUDD>(program, formulas, onlyInitialStatesRelevant);
verifySymbolicModelWithAbstractionRefinementEngine<storm::dd::DdType::CUDD>(model, formulas, onlyInitialStatesRelevant);
} else {
verifySymbolicModelWithAbstractionRefinementEngine<storm::dd::DdType::Sylvan>(program, formulas, onlyInitialStatesRelevant);
verifySymbolicModelWithAbstractionRefinementEngine<storm::dd::DdType::Sylvan>(model, formulas, onlyInitialStatesRelevant);
}
} else if (storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::Exploration) {
verifySymbolicModelWithExplorationEngine<ValueType>(program, formulas, onlyInitialStatesRelevant);
verifySymbolicModelWithExplorationEngine<ValueType>(model, formulas, onlyInitialStatesRelevant);
} else {
auto engine = storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine();
if (engine == storm::settings::modules::CoreSettings::Engine::Dd || engine == storm::settings::modules::CoreSettings::Engine::Hybrid) {
auto ddlib = storm::settings::getModule<storm::settings::modules::CoreSettings>().getDdLibraryType();
if (ddlib == storm::dd::DdType::CUDD) {
buildAndCheckSymbolicModelWithSymbolicEngine<storm::dd::DdType::CUDD>(engine == storm::settings::modules::CoreSettings::Engine::Hybrid, program, formulas, onlyInitialStatesRelevant);
buildAndCheckSymbolicModelWithSymbolicEngine<storm::dd::DdType::CUDD>(engine == storm::settings::modules::CoreSettings::Engine::Hybrid, model, formulas, onlyInitialStatesRelevant);
} else {
buildAndCheckSymbolicModelWithSymbolicEngine<storm::dd::DdType::Sylvan>(engine == storm::settings::modules::CoreSettings::Engine::Hybrid, program, formulas, onlyInitialStatesRelevant);
buildAndCheckSymbolicModelWithSymbolicEngine<storm::dd::DdType::Sylvan>(engine == storm::settings::modules::CoreSettings::Engine::Hybrid, model, formulas, onlyInitialStatesRelevant);
}
} else {
STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Illegal engine.");
buildAndCheckSymbolicModelWithSparseEngine<ValueType>(program, formulas, onlyInitialStatesRelevant);
buildAndCheckSymbolicModelWithSparseEngine<ValueType>(model, formulas, onlyInitialStatesRelevant);
}
}
}
#ifdef STORM_HAVE_CARL
template<>
void buildAndCheckSymbolicModel<storm::RationalNumber>(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) {
void buildAndCheckSymbolicModel<storm::RationalNumber>(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) {
STORM_LOG_THROW(storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Cannot use this data type with an engine different than the sparse one.");
buildAndCheckSymbolicModelWithSparseEngine<storm::RationalNumber>(program, formulas, onlyInitialStatesRelevant);
buildAndCheckSymbolicModelWithSparseEngine<storm::RationalNumber>(model, formulas, onlyInitialStatesRelevant);
}
template<>
void buildAndCheckSymbolicModel<storm::RationalFunction>(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) {
void buildAndCheckSymbolicModel<storm::RationalFunction>(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) {
STORM_LOG_THROW(storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Cannot use this data type with an engine different than the sparse one.");
buildAndCheckSymbolicModelWithSparseEngine<storm::RationalFunction>(program, formulas, onlyInitialStatesRelevant);
buildAndCheckSymbolicModelWithSparseEngine<storm::RationalFunction>(model, formulas, onlyInitialStatesRelevant);
}
#endif

2
src/counterexamples/SMTMinimalCommandSetGenerator.h

@ -628,7 +628,7 @@ namespace storm {
}
// Construct an expression that exactly characterizes the initial state.
storm::expressions::Expression initialStateExpression = program.getInitialConstruct().getInitialStatesExpression();
storm::expressions::Expression initialStateExpression = program.getInitialStatesExpression();
// Store the found implications in a container similar to the preceding label sets.
std::map<boost::container::flat_set<uint_fast64_t>, std::set<boost::container::flat_set<uint_fast64_t>>> backwardImplications;

147
src/generator/JaniNextStateGenerator.cpp

@ -11,6 +11,7 @@
#include "src/utility/solver.h"
#include "src/exceptions/InvalidSettingsException.h"
#include "src/exceptions/WrongFormatException.h"
#include "src/exceptions/InvalidArgumentException.h"
namespace storm {
namespace generator {
@ -21,11 +22,39 @@ namespace storm {
}
template<typename ValueType, typename StateType>
JaniNextStateGenerator<ValueType, StateType>::JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options, bool flag) : NextStateGenerator<ValueType, StateType>(model.getExpressionManager(), VariableInformation(model), options), model(model) {
JaniNextStateGenerator<ValueType, StateType>::JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options, bool flag) : NextStateGenerator<ValueType, StateType>(model.getExpressionManager(), VariableInformation(model), options), model(model), rewardVariables() {
STORM_LOG_THROW(model.hasDefaultComposition(), storm::exceptions::WrongFormatException, "The explicit next-state generator currently does not support custom system compositions.");
STORM_LOG_THROW(!this->options.isBuildAllRewardModelsSet() && this->options.getRewardModelNames().empty(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support building reward models.");
STORM_LOG_THROW(!model.hasNonGlobalTransientVariable(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support automata-local transient variables.");
STORM_LOG_THROW(!this->options.isBuildChoiceLabelsSet(), storm::exceptions::InvalidSettingsException, "JANI next-state generator cannot generate choice labels.");
if (this->options.isBuildAllRewardModelsSet()) {
for (auto const& variable : model.getGlobalVariables()) {
if (variable.isTransient()) {
rewardVariables.push_back(variable.getExpressionVariable());
}
}
} else {
// Extract the reward models from the program based on the names we were given.
auto const& globalVariables = model.getGlobalVariables();
for (auto const& rewardModelName : this->options.getRewardModelNames()) {
if (globalVariables.hasVariable(rewardModelName)) {
rewardVariables.push_back(globalVariables.getVariable(rewardModelName).getExpressionVariable());
} else {
STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException, "Cannot build unknown reward model '" << rewardModelName << "'.");
STORM_LOG_THROW(globalVariables.getNumberOfTransientVariables() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous.");
}
}
// If no reward model was yet added, but there was one that was given in the options, we try to build the
// standard reward model.
if (rewardVariables.empty() && !this->options.getRewardModelNames().empty()) {
rewardVariables.push_back(globalVariables.getTransientVariables().front()->getExpressionVariable());
}
}
// Build the information structs for the reward models.
buildRewardModelInformation();
// If there are terminal states we need to handle, we now need to translate all labels to expressions.
if (this->options.hasTerminalStates()) {
for (auto const& expressionOrLabelAndBool : this->options.getTerminalStates()) {
@ -161,6 +190,9 @@ namespace storm {
}
// Block the current initial state to search for the next one.
if (!blockingExpression.isInitialized()) {
break;
}
solver->add(blockingExpression);
}
@ -171,13 +203,8 @@ namespace storm {
CompressedState JaniNextStateGenerator<ValueType, StateType>::applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& destination) {
CompressedState newState(state);
// NOTE: the following process assumes that the assignments of the destination are ordered in such a way
// that the assignments to boolean variables precede the assignments to all integer variables and that
// within the types, the assignments to variables are ordered (in ascending order) by the expression variables.
// This is guaranteed for JANI models, by sorting the assignments as soon as an edge destination is created.
auto assignmentIt = destination.getAssignments().begin();
auto assignmentIte = destination.getAssignments().end();
auto assignmentIt = destination.getNonTransientAssignments().begin();
auto assignmentIte = destination.getNonTransientAssignments().end();
// Iterate over all boolean assignments and carry them out.
auto boolIt = this->variableInformation.booleanVariables.begin();
@ -211,6 +238,22 @@ namespace storm {
// Prepare the result, in case we return early.
StateBehavior<ValueType, StateType> result;
// Retrieve the locations from the state.
std::vector<uint64_t> locations = getLocations(*this->state);
// First, construct the state rewards, as we may return early if there are no choices later and we already
// 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()) {
uint64_t currentLocationIndex = locations[automatonIndex];
storm::jani::Location const& location = automaton.getLocation(currentLocationIndex);
auto valueIt = stateRewards.begin();
performTransientAssignments(location.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } );
++automatonIndex;
}
result.addStateRewards(std::move(stateRewards));
// If a terminal expression was set and we must not expand this state, return now.
if (!this->terminalStates.empty()) {
for (auto const& expressionBool : this->terminalStates) {
@ -220,9 +263,6 @@ namespace storm {
}
}
// Retrieve the locations from the state.
std::vector<uint64_t> locations = getLocations(*this->state);
// Get all choices for the state.
std::vector<Choice<ValueType>> allChoices = getSilentActionChoices(locations, *this->state, stateToIdCallback);
std::vector<Choice<ValueType>> allLabeledChoices = getNonsilentActionChoices(locations, *this->state, stateToIdCallback);
@ -308,6 +348,9 @@ namespace storm {
probabilitySum += probability;
}
// Create the state-action reward for the newly created choice.
performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&choice] (ValueType const& value) { choice.addChoiceReward(value); } );
// 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 << ").");
}
@ -477,13 +520,12 @@ namespace storm {
template<typename ValueType, typename StateType>
std::size_t JaniNextStateGenerator<ValueType, StateType>::getNumberOfRewardModels() const {
return 0;
return rewardVariables.size();
}
template<typename ValueType, typename StateType>
RewardModelInformation JaniNextStateGenerator<ValueType, StateType>::getRewardModelInformation(uint64_t const& index) const {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Cannot retrieve reward model information.");
return RewardModelInformation("", false, false, false);
return rewardModelInformation[index];
}
template<typename ValueType, typename StateType>
@ -491,6 +533,81 @@ namespace storm {
return NextStateGenerator<ValueType, StateType>::label(states, initialStateIndices, deadlockStateIndices, {});
}
template<typename ValueType, typename StateType>
void JaniNextStateGenerator<ValueType, StateType>::performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function<void (ValueType const&)> const& callback) {
// If there are no reward variables, there is no need to iterate at all.
if (rewardVariables.empty()) {
return;
}
// Otherwise, perform the callback for all selected reward variables.
auto rewardVariableIt = rewardVariables.begin();
auto rewardVariableIte = rewardVariables.end();
for (auto const& assignment : transientAssignments) {
while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) {
callback(storm::utility::zero<ValueType>());
++rewardVariableIt;
}
if (rewardVariableIt == rewardVariableIte) {
break;
} else if (*rewardVariableIt == assignment.getExpressionVariable()) {
callback(ValueType(this->evaluator.asRational(assignment.getAssignedExpression())));
++rewardVariableIt;
}
}
// Add a value of zero for all variables that have no assignment.
for (; rewardVariableIt != rewardVariableIte; ++rewardVariableIt) {
callback(storm::utility::zero<ValueType>());
}
}
template<typename ValueType, typename StateType>
void JaniNextStateGenerator<ValueType, StateType>::buildRewardModelInformation() {
// Prepare all reward model information structs.
for (auto const& variable : rewardVariables) {
rewardModelInformation.emplace_back(variable.getName(), false, false, false);
}
// Then fill them.
for (auto const& automaton : model.getAutomata()) {
for (auto const& location : automaton.getLocations()) {
auto rewardVariableIt = rewardVariables.begin();
auto rewardVariableIte = rewardVariables.end();
for (auto const& assignment : location.getAssignments().getTransientAssignments()) {
while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) {
++rewardVariableIt;
}
if (rewardVariableIt == rewardVariableIte) {
break;
}
if (*rewardVariableIt == assignment.getExpressionVariable()) {
rewardModelInformation[std::distance(rewardVariables.begin(), rewardVariableIt)].setHasStateRewards();
++rewardVariableIt;
}
}
}
for (auto const& edge : automaton.getEdges()) {
auto rewardVariableIt = rewardVariables.begin();
auto rewardVariableIte = rewardVariables.end();
for (auto const& assignment : edge.getAssignments().getTransientAssignments()) {
while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) {
++rewardVariableIt;
}
if (rewardVariableIt == rewardVariableIte) {
break;
}
if (*rewardVariableIt == assignment.getExpressionVariable()) {
rewardModelInformation[std::distance(rewardVariables.begin(), rewardVariableIt)].setHasStateActionRewards();
++rewardVariableIt;
}
}
}
}
}
template class JaniNextStateGenerator<double>;
#ifdef STORM_HAVE_CARL

17
src/generator/JaniNextStateGenerator.h

@ -89,8 +89,25 @@ namespace storm {
*/
void checkGlobalVariableWritesValid(std::vector<std::vector<storm::jani::Edge const*>> const& enabledEdges) const;
/*!
* Treats the given transient assignments by calling the callback function whenever a transient assignment
* to one of the reward variables of this generator is performed.
*/
void performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function<void (ValueType const&)> const& callback);
/*!
* Builds the information structs for the reward models.
*/
void buildRewardModelInformation();
/// The model used for the generation of next states.
storm::jani::Model model;
/// The transient variables of reward models that need to be considered.
std::vector<storm::expressions::Variable> rewardVariables;
/// A vector storing information about the corresponding reward models (variables).
std::vector<RewardModelInformation> rewardModelInformation;
};
}

12
src/generator/NextStateGenerator.cpp

@ -211,6 +211,18 @@ namespace storm {
return transitionRewards;
}
void RewardModelInformation::setHasStateRewards() {
stateRewards = true;
}
void RewardModelInformation::setHasStateActionRewards() {
stateActionRewards = true;
}
void RewardModelInformation::setHasTransitionRewards() {
transitionRewards = true;
}
template<typename ValueType, typename StateType>
NextStateGenerator<ValueType, StateType>::NextStateGenerator(storm::expressions::ExpressionManager const& expressionManager, VariableInformation const& variableInformation, NextStateGeneratorOptions const& options) : options(options), expressionManager(expressionManager.getSharedPointer()), variableInformation(variableInformation), evaluator(expressionManager), state(nullptr) {
// Intentionally left empty.

3
src/generator/NextStateGenerator.h

@ -148,6 +148,9 @@ namespace storm {
bool hasStateActionRewards() const;
bool hasTransitionRewards() const;
void setHasStateRewards();
void setHasStateActionRewards();
void setHasTransitionRewards();
private:
std::string name;
bool stateRewards;

14
src/generator/PrismNextStateGenerator.cpp

@ -23,8 +23,9 @@ namespace storm {
template<typename ValueType, typename StateType>
PrismNextStateGenerator<ValueType, StateType>::PrismNextStateGenerator(storm::prism::Program const& program, NextStateGeneratorOptions const& options, bool flag) : NextStateGenerator<ValueType, StateType>(program.getManager(), options), program(program), rewardModels() {
STORM_LOG_TRACE("Creating next-state generator for PRISM program: " << program);
STORM_LOG_THROW(!this->program.specifiesSystemComposition(), storm::exceptions::WrongFormatException, "The explicit next-state generator currently does not support custom system compositions.");
// Only after checking validity of the program, we initialize the variable information.
this->checkValid(program);
this->variableInformation = VariableInformation(program);
@ -41,11 +42,10 @@ namespace storm {
} else {
STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException, "Cannot build unknown reward model '" << rewardModelName << "'.");
STORM_LOG_THROW(this->program.getNumberOfRewardModels() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous.");
STORM_LOG_THROW(this->program.getNumberOfRewardModels() > 0, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is invalid, because there is no reward model.");
}
}
// If no reward model was yet added, but there was one that was given in the options, we try to build
// If no reward model was yet added, but there was one that was given in the options, we try to build the
// standard reward model.
if (rewardModels.empty() && !this->options.getRewardModelNames().empty()) {
rewardModels.push_back(this->program.getRewardModel(0));
@ -136,7 +136,7 @@ namespace storm {
for (auto const& expression : rangeExpressions) {
solver->add(expression);
}
solver->add(program.getInitialConstruct().getInitialStatesExpression());
solver->add(program.getInitialStatesExpression());
// Proceed ss long as the solver can still enumerate initial states.
std::vector<StateType> initialStateIndices;
@ -166,6 +166,9 @@ namespace storm {
initialStateIndices.push_back(id);
// Block the current initial state to search for the next one.
if (!blockingExpression.isInitialized()) {
break;
}
solver->add(blockingExpression);
}
@ -314,7 +317,7 @@ namespace storm {
template<typename ValueType, typename StateType>
boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> PrismNextStateGenerator<ValueType, StateType>::getActiveCommandsByActionIndex(uint_fast64_t const& actionIndex) {
boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> result((std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>()));
// Iterate over all modules.
for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
storm::prism::Module const& module = program.getModule(i);
@ -445,7 +448,6 @@ namespace storm {
for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) {
storm::prism::Command const& command = *iteratorList[i];
for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) {
storm::prism::Update const& update = command.getUpdate(j);

5
src/generator/StateBehavior.cpp

@ -20,6 +20,11 @@ namespace storm {
stateRewards.push_back(stateReward);
}
template<typename ValueType, typename StateType>
void StateBehavior<ValueType, StateType>::addStateRewards(std::vector<ValueType>&& stateRewards) {
this->stateRewards = std::move(stateRewards);
}
template<typename ValueType, typename StateType>
void StateBehavior<ValueType, StateType>::setExpanded(bool newValue) {
this->expanded = newValue;

7
src/generator/StateBehavior.h

@ -25,7 +25,12 @@ namespace storm {
* Adds the given state reward to the behavior of the state.
*/
void addStateReward(ValueType const& stateReward);
/*!
* Adds the given state rewards to the behavior of the state.
*/
void addStateRewards(std::vector<ValueType>&& stateRewards);
/*!
* Sets whether the state was expanded.
*/

1
src/modelchecker/AbstractModelChecker.cpp

@ -17,6 +17,7 @@
#include "src/models/symbolic/Mdp.h"
#include "src/models/sparse/MarkovAutomaton.h"
#include "src/models/sparse/StandardRewardModel.h"
#include "src/models/symbolic/StandardRewardModel.h"
#include "src/storage/dd/Add.h"
#include "src/storage/dd/Bdd.h"

2
src/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp

@ -172,7 +172,7 @@ namespace storm {
// for solving the equation system (i.e. compute (I-A)).
submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs());
submatrix = (model.getRowColumnIdentity() * maybeStatesAdd) - submatrix;
// Solve the equation system.
std::unique_ptr<storm::solver::SymbolicLinearEquationSolver<DdType, ValueType>> solver = linearEquationSolverFactory.create(submatrix, maybeStates, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs());
storm::dd::Add<DdType, ValueType> result = solver->solveEquations(model.getManager().getConstant(0.5) * maybeStatesAdd, subvector);

32
src/parser/ExpressionParser.cpp

@ -3,6 +3,34 @@
#include "src/exceptions/InvalidTypeException.h"
#include "src/exceptions/WrongFormatException.h"
#include "src/utility/constants.h"
namespace boost {
namespace spirit {
namespace traits {
template<>
bool scale(int exp, storm::RationalNumber& r, storm::RationalNumber acc) {
if (exp >= 0) {
r = acc * storm::utility::pow(storm::RationalNumber(10), static_cast<uint_fast64_t>(exp));
} else {
r = acc / storm::utility::pow(storm::RationalNumber(10), static_cast<uint_fast64_t>(-exp));
}
return true;
}
template<>
bool is_equal_to_one(storm::RationalNumber const& value) {
return storm::utility::isOne(value);
}
template<>
storm::RationalNumber negate(bool neg, storm::RationalNumber const& number) {
return neg ? storm::RationalNumber(-number) : number;
}
}
}
}
namespace storm {
namespace parser {
ExpressionParser::ExpressionParser(storm::expressions::ExpressionManager const& manager, qi::symbols<char, uint_fast64_t> const& invalidIdentifiers_, bool enableErrorHandling, bool allowBacktracking) : ExpressionParser::base_type(expression), orOperator_(), andOperator_(), equalityOperator_(), relationalOperator_(), plusOperator_(), multiplicationOperator_(), infixPowerOperator_(), unaryOperator_(), floorCeilOperator_(), minMaxOperator_(), prefixPowerOperator_(), trueFalse_(manager), manager(manager.getSharedPointer()), createExpressions(false), acceptDoubleLiterals(true), identifiers_(nullptr), invalidIdentifiers_(invalidIdentifiers_) {
@ -33,7 +61,7 @@ namespace storm {
identifierExpression = identifier[qi::_val = phoenix::bind(&ExpressionParser::getIdentifierExpression, phoenix::ref(*this), qi::_1, allowBacktracking, qi::_pass)];
identifierExpression.name("identifier expression");
literalExpression = trueFalse_[qi::_val = qi::_1] | strict_double[qi::_val = phoenix::bind(&ExpressionParser::createDoubleLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)] | qi::int_[qi::_val = phoenix::bind(&ExpressionParser::createIntegerLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)];
literalExpression = trueFalse_[qi::_val = qi::_1] | rationalLiteral_[qi::_val = phoenix::bind(&ExpressionParser::createRationalLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)] | qi::int_[qi::_val = phoenix::bind(&ExpressionParser::createIntegerLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)];
literalExpression.name("literal expression");
atomicExpression = floorCeilExpression | prefixPowerExpression | minMaxExpression | (qi::lit("(") >> expression >> qi::lit(")")) | literalExpression | identifierExpression;
@ -295,7 +323,7 @@ namespace storm {
return manager->boolean(false);
}
storm::expressions::Expression ExpressionParser::createDoubleLiteralExpression(double value, bool& pass) const {
storm::expressions::Expression ExpressionParser::createRationalLiteralExpression(storm::RationalNumber const& value, bool& pass) const {
// If we are not supposed to accept double expressions, we reject it by setting pass to false.
if (!this->acceptDoubleLiterals) {
pass = false;

16
src/parser/ExpressionParser.h

@ -8,8 +8,20 @@
#include "src/storage/expressions/Expression.h"
#include "src/storage/expressions/ExpressionManager.h"
#include "src/adapters/CarlAdapter.h"
namespace storm {
namespace parser {
template<typename NumberType>
struct RationalPolicies : boost::spirit::qi::strict_real_policies<NumberType> {
static const bool expect_dot = true;
template <typename It, typename Attr>
static bool parse_nan(It&, It const&, Attr&) { return false; }
template <typename It, typename Attr>
static bool parse_inf(It&, It const&, Attr&) { return false; }
};
class ExpressionParser : public qi::grammar<Iterator, storm::expressions::Expression(), Skipper> {
public:
/*!
@ -236,7 +248,7 @@ namespace storm {
qi::rule<Iterator, std::string(), Skipper> identifier;
// Parser that is used to recognize doubles only (as opposed to Spirit's double_ parser).
boost::spirit::qi::real_parser<double, boost::spirit::qi::strict_real_policies<double>> strict_double;
boost::spirit::qi::real_parser<storm::RationalNumber, RationalPolicies<storm::RationalNumber>> rationalLiteral_;
// Helper functions to create expressions.
storm::expressions::Expression createIteExpression(storm::expressions::Expression e1, storm::expressions::Expression e2, storm::expressions::Expression e3, bool& pass) const;
@ -248,7 +260,7 @@ namespace storm {
storm::expressions::Expression createMultExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const;
storm::expressions::Expression createPowerExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const;
storm::expressions::Expression createUnaryExpression(boost::optional<storm::expressions::OperatorType> const& operatorType, storm::expressions::Expression const& e1, bool& pass) const;
storm::expressions::Expression createDoubleLiteralExpression(double value, bool& pass) const;
storm::expressions::Expression createRationalLiteralExpression(storm::RationalNumber const& value, bool& pass) const;
storm::expressions::Expression createIntegerLiteralExpression(int value, bool& pass) const;
storm::expressions::Expression createMinimumMaximumExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const;
storm::expressions::Expression createFloorCeilExpression(storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e1, bool& pass) const;

5
src/parser/FormulaParser.cpp

@ -4,6 +4,9 @@
#include "src/parser/SpiritErrorHandler.h"
#include "src/storage/prism/Program.h"
#include "src/storage/jani/Model.h"
// If the parser fails due to ill-formed data, this exception is thrown.
#include "src/exceptions/WrongFormatException.h"
@ -176,7 +179,7 @@ namespace storm {
phoenix::function<SpiritErrorHandler> handler;
};
FormulaParser::FormulaParser(std::shared_ptr<storm::expressions::ExpressionManager const> const& manager) : manager(manager->getSharedPointer()), grammar(new FormulaParserGrammar(manager)) {
FormulaParser::FormulaParser(std::shared_ptr<storm::expressions::ExpressionManager const> const& manager) : manager(manager), grammar(new FormulaParserGrammar(manager)) {
// Intentionally left empty.
}

6
src/parser/FormulaParser.h

@ -9,9 +9,11 @@
#include "src/storage/expressions/Expression.h"
#include "src/utility/macros.h"
#include "src/storage/prism/Program.h"
namespace storm {
namespace prism {
class Program;
}
namespace parser {
// Forward-declare grammar.

2
src/parser/JaniParser.cpp

@ -571,7 +571,7 @@ namespace storm {
STORM_LOG_THROW(transientValueEntry.count("ref") == 1, storm::exceptions::InvalidJaniException, "Transient values in location " << locName << " need exactly one ref that is assigned to");
STORM_LOG_THROW(transientValueEntry.count("value") == 1, storm::exceptions::InvalidJaniException, "Transient values in location " << locName << " need exactly one assigned value");
storm::jani::Variable const& lhs = getLValue(transientValueEntry.at("ref"), parentModel.getGlobalVariables(), automaton.getVariables(), "LHS of assignment in location " + locName + " (automaton '" + name + "')");
STORM_LOG_THROW(lhs.isTransientVariable(), storm::exceptions::InvalidJaniException, "Assigned non-transient variable " + lhs.getName() + " in location " + locName + " (automaton: '" + name + "')");
STORM_LOG_THROW(lhs.isTransient(), storm::exceptions::InvalidJaniException, "Assigned non-transient variable " + lhs.getName() + " in location " + locName + " (automaton: '" + name + "')");
storm::expressions::Expression rhs = parseExpression(transientValueEntry.at("value"), "Assignment of variable " + lhs.getName() + " in location " + locName + " (automaton: '" + name + "')");
transientAssignments.emplace_back(lhs, rhs);
}

3
src/parser/JaniParser.h

@ -42,7 +42,8 @@ namespace storm {
storm::jani::Property parseProperty(json const& propertyStructure);
storm::jani::Automaton parseAutomaton(json const& automatonStructure, storm::jani::Model const& parentModel);
std::shared_ptr<storm::jani::Variable> parseVariable(json const& variableStructure, std::string const& scopeDescription, bool prefWithScope = false);
storm::expressions::Expression parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars = {});
storm::expressions::Expression parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars = std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>>());
private:
std::shared_ptr<storm::jani::Constant> parseConstant(json const& constantStructure, std::string const& scopeDescription = "global");

20
src/parser/PrismParser.cpp

@ -65,6 +65,8 @@ namespace storm {
STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << lineNumber << " of file " << filename << ".");
}
STORM_LOG_TRACE("Parsed PRISM input: " << result);
return result;
}
@ -103,10 +105,10 @@ namespace storm {
formulaDefinition = (qi::lit("formula") > identifier > qi::lit("=") > expressionParser > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createFormula, phoenix::ref(*this), qi::_1, qi::_2)];
formulaDefinition.name("formula definition");
booleanVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("bool")) > ((qi::lit("init") > expressionParser) | qi::attr(manager->boolean(false))) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createBooleanVariable, phoenix::ref(*this), qi::_1, qi::_2)];
booleanVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("bool")) > -((qi::lit("init") > expressionParser[qi::_a = qi::_1]) | qi::attr(manager->boolean(false))) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createBooleanVariable, phoenix::ref(*this), qi::_1, qi::_a)];
booleanVariableDefinition.name("boolean variable definition");
integerVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("[")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), false)]) > expressionParser[qi::_a = qi::_1] > qi::lit("..") > expressionParser > qi::lit("]")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), true)] > -(qi::lit("init") > expressionParser[qi::_a = qi::_1]) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createIntegerVariable, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_a)];
integerVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("[")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), false)]) > expressionParser > qi::lit("..") > expressionParser > qi::lit("]")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), true)] > -(qi::lit("init") > expressionParser[qi::_a = qi::_1]) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createIntegerVariable, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_a)];
integerVariableDefinition.name("integer variable definition");
variableDefinition = (booleanVariableDefinition[phoenix::push_back(qi::_r1, qi::_1)] | integerVariableDefinition[phoenix::push_back(qi::_r2, qi::_1)]);
@ -208,7 +210,7 @@ namespace storm {
moduleDefinitionList %= +(moduleRenaming(qi::_r1) | moduleDefinition(qi::_r1))[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::modules, qi::_r1), qi::_1)];
moduleDefinitionList.name("module list");
start = (qi::eps
start = (qi::eps[phoenix::bind(&PrismParser::removeInitialConstruct, phoenix::ref(*this), qi::_a)]
> modelTypeDefinition[phoenix::bind(&GlobalProgramInformation::modelType, qi::_a) = qi::_1]
> *(definedConstantDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::constants, qi::_a), qi::_1)]
| undefinedConstantDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::constants, qi::_a), qi::_1)]
@ -276,7 +278,7 @@ namespace storm {
return true;
}
bool PrismParser::addInitialStatesConstruct(storm::expressions::Expression initialStatesExpression, GlobalProgramInformation& globalProgramInformation) {
bool PrismParser::addInitialStatesConstruct(storm::expressions::Expression const& initialStatesExpression, GlobalProgramInformation& globalProgramInformation) {
STORM_LOG_THROW(!globalProgramInformation.hasInitialConstruct, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": Program must not define two initial constructs.");
if (globalProgramInformation.hasInitialConstruct) {
return false;
@ -585,7 +587,7 @@ namespace storm {
auto const& renamingPair = renaming.find(variable.getName());
STORM_LOG_THROW(renamingPair != renaming.end(), storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": Boolean variable '" << variable.getName() << " was not renamed.");
booleanVariables.push_back(storm::prism::BooleanVariable(manager->getVariable(renamingPair->second), variable.getInitialValueExpression().substitute(expressionRenaming), this->getFilename(), get_line(qi::_1)));
booleanVariables.push_back(storm::prism::BooleanVariable(manager->getVariable(renamingPair->second), variable.hasInitialValue() ? variable.getInitialValueExpression().substitute(expressionRenaming) : variable.getInitialValueExpression(), this->getFilename(), get_line(qi::_1)));
}
// Rename the integer variables.
@ -594,7 +596,7 @@ namespace storm {
auto const& renamingPair = renaming.find(variable.getName());
STORM_LOG_THROW(renamingPair != renaming.end(), storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": Integer variable '" << variable.getName() << " was not renamed.");
integerVariables.push_back(storm::prism::IntegerVariable(manager->getVariable(renamingPair->second), variable.getLowerBoundExpression().substitute(expressionRenaming), variable.getUpperBoundExpression().substitute(expressionRenaming), variable.getInitialValueExpression().substitute(expressionRenaming), this->getFilename(), get_line(qi::_1)));
integerVariables.push_back(storm::prism::IntegerVariable(manager->getVariable(renamingPair->second), variable.getLowerBoundExpression().substitute(expressionRenaming), variable.getUpperBoundExpression().substitute(expressionRenaming), variable.hasInitialValue() ? variable.getInitialValueExpression().substitute(expressionRenaming) : variable.getInitialValueExpression(), this->getFilename(), get_line(qi::_1)));
}
// Rename commands.
@ -640,7 +642,11 @@ namespace storm {
}
storm::prism::Program PrismParser::createProgram(GlobalProgramInformation const& globalProgramInformation) const {
return storm::prism::Program(manager, globalProgramInformation.modelType, globalProgramInformation.constants, globalProgramInformation.globalBooleanVariables, globalProgramInformation.globalIntegerVariables, globalProgramInformation.formulas, globalProgramInformation.modules, globalProgramInformation.actionIndices, globalProgramInformation.rewardModels, globalProgramInformation.labels, secondRun && !globalProgramInformation.hasInitialConstruct ? boost::none : boost::optional<storm::prism::InitialConstruct>(storm::prism::InitialConstruct(manager->boolean(false))), globalProgramInformation.systemCompositionConstruct, this->getFilename(), 1, this->secondRun);
return storm::prism::Program(manager, globalProgramInformation.modelType, globalProgramInformation.constants, globalProgramInformation.globalBooleanVariables, globalProgramInformation.globalIntegerVariables, globalProgramInformation.formulas, globalProgramInformation.modules, globalProgramInformation.actionIndices, globalProgramInformation.rewardModels, globalProgramInformation.labels, secondRun && !globalProgramInformation.hasInitialConstruct ? boost::none : boost::make_optional(globalProgramInformation.initialConstruct), globalProgramInformation.systemCompositionConstruct, this->getFilename(), 1, this->secondRun);
}
void PrismParser::removeInitialConstruct(GlobalProgramInformation& globalProgramInformation) const {
globalProgramInformation.hasInitialConstruct = false;
}
} // namespace parser
} // namespace storm

6
src/parser/PrismParser.h

@ -188,7 +188,7 @@ namespace storm {
// Rules for variable definitions.
qi::rule<Iterator, qi::unused_type(std::vector<storm::prism::BooleanVariable>&, std::vector<storm::prism::IntegerVariable>&), Skipper> variableDefinition;
qi::rule<Iterator, storm::prism::BooleanVariable(), Skipper> booleanVariableDefinition;
qi::rule<Iterator, storm::prism::BooleanVariable(), qi::locals<storm::expressions::Expression>, Skipper> booleanVariableDefinition;
qi::rule<Iterator, storm::prism::IntegerVariable(), qi::locals<storm::expressions::Expression>, Skipper> integerVariableDefinition;
// Rules for command definitions.
@ -241,7 +241,7 @@ namespace storm {
// Helper methods used in the grammar.
bool isValidIdentifier(std::string const& identifier);
bool addInitialStatesConstruct(storm::expressions::Expression initialStatesExpression, GlobalProgramInformation& globalProgramInformation);
bool addInitialStatesConstruct(storm::expressions::Expression const& initialStatesExpression, GlobalProgramInformation& globalProgramInformation);
bool addSystemCompositionConstruct(std::shared_ptr<storm::prism::Composition> const& composition, GlobalProgramInformation& globalProgramInformation);
@ -274,6 +274,8 @@ namespace storm {
storm::prism::Module createRenamedModule(std::string const& newModuleName, std::string const& oldModuleName, std::map<std::string, std::string> const& renaming, GlobalProgramInformation& globalProgramInformation) const;
storm::prism::Program createProgram(GlobalProgramInformation const& globalProgramInformation) const;
void removeInitialConstruct(GlobalProgramInformation& globalProgramInformation) const;
// An error handler function.
phoenix::function<SpiritErrorHandler> handler;
};

5
src/settings/modules/CoreSettings.cpp

@ -30,7 +30,6 @@ namespace storm {
const std::string CoreSettings::engineOptionShortName = "e";
const std::string CoreSettings::ddLibraryOptionName = "ddlib";
const std::string CoreSettings::cudaOptionName = "cuda";
const std::string CoreSettings::minMaxEquationSolvingTechniqueOptionName = "ndmethod";
CoreSettings::CoreSettings() : ModuleSettings(moduleName), engine(CoreSettings::Engine::Sparse) {
this->addOption(storm::settings::OptionBuilder(moduleName, counterexampleOptionName, false, "Generates a counterexample for the given PRCTL formulas if not satisfied by the model")
@ -57,10 +56,6 @@ namespace storm {
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of an SMT solver. Available are: z3 and mathsat.").addValidationFunctionString(storm::settings::ArgumentValidators::stringInListValidator(smtSolvers)).setDefaultValueString("z3").build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, statisticsOptionName, false, "Sets whether to display statistics if available.").setShortName(statisticsOptionShortName).build());
this->addOption(storm::settings::OptionBuilder(moduleName, cudaOptionName, false, "Sets whether to use CUDA to speed up computation time.").build());
std::vector<std::string> minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration"};
this->addOption(storm::settings::OptionBuilder(moduleName, minMaxEquationSolvingTechniqueOptionName, false, "Sets which min/max linear equation solving technique is preferred.")
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a min/max linear equation solving technique. Available are: value-iteration (vi) and policy-iteration (pi).").addValidationFunctionString(storm::settings::ArgumentValidators::stringInListValidator(minMaxSolvingTechniques)).setDefaultValueString("vi").build()).build());
}
bool CoreSettings::isCounterexampleSet() const {

1
src/settings/modules/CoreSettings.h

@ -151,7 +151,6 @@ namespace storm {
static const std::string engineOptionShortName;
static const std::string ddLibraryOptionName;
static const std::string cudaOptionName;
static const std::string minMaxEquationSolvingTechniqueOptionName;
};
} // namespace modules

2
src/settings/modules/CounterexampleGeneratorSettings.cpp

@ -48,7 +48,7 @@ namespace storm {
bool CounterexampleGeneratorSettings::check() const {
// Ensure that the model was given either symbolically or explicitly.
STORM_LOG_THROW(!isMinimalCommandSetGenerationSet() || storm::settings::getModule<storm::settings::modules::IOSettings>().isSymbolicSet(), storm::exceptions::InvalidSettingsException, "For the generation of a minimal command set, the model has to be specified symbolically.");
STORM_LOG_THROW(!isMinimalCommandSetGenerationSet() || storm::settings::getModule<storm::settings::modules::IOSettings>().isPrismInputSet(), storm::exceptions::InvalidSettingsException, "For the generation of a minimal command set, the model has to be specified in the PRISM format.");
if (isMinimalCommandSetGenerationSet()) {
STORM_LOG_WARN_COND(isUseMaxSatBasedMinimalCommandSetGenerationSet() || !isEncodeReachabilitySet(), "Encoding reachability is only available for the MaxSat-based minimal command set generation, so selecting it has no effect.");

47
src/settings/modules/IOSettings.cpp

@ -17,8 +17,9 @@ namespace storm {
const std::string IOSettings::exportMatOptionName = "exportmat";
const std::string IOSettings::explicitOptionName = "explicit";
const std::string IOSettings::explicitOptionShortName = "exp";
const std::string IOSettings::symbolicOptionName = "symbolic";
const std::string IOSettings::symbolicOptionShortName = "s";
const std::string IOSettings::prismInputOptionName = "prism";
const std::string IOSettings::janiInputOptionName = "jani";
const std::string IOSettings::prismToJaniOptionName = "prism2jani";
const std::string IOSettings::explorationOrderOptionName = "explorder";
const std::string IOSettings::explorationOrderOptionShortName = "eo";
const std::string IOSettings::transitionRewardsOptionName = "transrew";
@ -38,8 +39,11 @@ namespace storm {
this->addOption(storm::settings::OptionBuilder(moduleName, explicitOptionName, false, "Parses the model given in an explicit (sparse) representation.").setShortName(explicitOptionShortName)
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("transition filename", "The name of the file from which to read the transitions.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build())
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("labeling filename", "The name of the file from which to read the state labeling.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, symbolicOptionName, false, "Parses the model given in a symbolic representation.").setShortName(symbolicOptionShortName)
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the symbolic model.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, prismInputOptionName, false, "Parses the model given in the PRISM format.")
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the PRISM input.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, janiInputOptionName, false, "Parses the model given in the JANI format.")
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the JANI input.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, prismToJaniOptionName, false, "If set, the input PRISM model is transformed to JANI.").build());
std::vector<std::string> explorationOrders = {"dfs", "bfs"};
this->addOption(storm::settings::OptionBuilder(moduleName, explorationOrderOptionName, false, "Sets which exploration order to use.").setShortName(explorationOrderOptionShortName)
@ -51,7 +55,7 @@ namespace storm {
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The file from which to read the state rewards.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, choiceLabelingOptionName, false, "If given, the choice labels are read from this file and added to the explicit model. Note that this requires the model to be given as an explicit model (i.e., via --" + explicitOptionName + ").")
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The file from which to read the choice labels.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, constantsOptionName, false, "Specifies the constant replacements to use in symbolic models. Note that Note that this requires the model to be given as an symbolic model (i.e., via --" + symbolicOptionName + ").").setShortName(constantsOptionShortName)
this->addOption(storm::settings::OptionBuilder(moduleName, constantsOptionName, false, "Specifies the constant replacements to use in symbolic models. Note that this requires the model to be given as an symbolic model (i.e., via --" + prismInputOptionName + " or --" + janiInputOptionName + ").").setShortName(constantsOptionShortName)
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of constants and their value, e.g. a=1,b=2,c=3.").setDefaultValueString("").build()).build());
}
@ -75,14 +79,30 @@ namespace storm {
return this->getOption(explicitOptionName).getArgumentByName("labeling filename").getValueAsString();
}
bool IOSettings::isSymbolicSet() const {
return this->getOption(symbolicOptionName).getHasOptionBeenSet();
bool IOSettings::isPrismInputSet() const {
return this->getOption(prismInputOptionName).getHasOptionBeenSet();
}
std::string IOSettings::getSymbolicModelFilename() const {
return this->getOption(symbolicOptionName).getArgumentByName("filename").getValueAsString();
bool IOSettings::isPrismOrJaniInputSet() const {
return isJaniInputSet() || isPrismInputSet();
}
bool IOSettings::isPrismToJaniSet() const {
return this->getOption(prismToJaniOptionName).getHasOptionBeenSet();
}
std::string IOSettings::getPrismInputFilename() const {
return this->getOption(prismInputOptionName).getArgumentByName("filename").getValueAsString();
}
bool IOSettings::isJaniInputSet() const {
return this->getOption(janiInputOptionName).getHasOptionBeenSet();
}
std::string IOSettings::getJaniInputFilename() const {
return this->getOption(janiInputOptionName).getArgumentByName("filename").getValueAsString();
}
bool IOSettings::isExplorationOrderSet() const {
return this->getOption(explorationOrderOptionName).getHasOptionBeenSet();
}
@ -141,8 +161,15 @@ namespace storm {
}
bool IOSettings::check() const {
// Ensure that not two symbolic input models were given.
STORM_LOG_THROW(!isJaniInputSet() || !isPrismInputSet(), storm::exceptions::InvalidSettingsException, "Symbolic model ");
// Ensure that the model was given either symbolically or explicitly.
STORM_LOG_THROW(!isSymbolicSet() || !isExplicitSet(), storm::exceptions::InvalidSettingsException, "The model may be either given in an explicit or a symbolic format, but not both.");
STORM_LOG_THROW(!isJaniInputSet() || !isPrismInputSet() || !isExplicitSet(), storm::exceptions::InvalidSettingsException, "The model may be either given in an explicit or a symbolic format (PRISM or JANI), but not both.");
// Make sure PRISM-to-JANI conversion is only set if the actual input is in PRISM format.
STORM_LOG_THROW(!isPrismToJaniSet() || isPrismInputSet(), storm::exceptions::InvalidSettingsException, "For the transformation from PRISM to JANI, the input model must be given in the prism format.");
return true;
}

48
src/settings/modules/IOSettings.h

@ -59,20 +59,49 @@ namespace storm {
std::string getLabelingFilename() const;
/*!
* Retrieves whether the symbolic option was set.
* Retrieves whether the PRISM language option was set.
*
* @return True if the symbolic option was set.
* @return True if the PRISM input option was set.
*/
bool isSymbolicSet() const;
bool isPrismInputSet() const;
/*!
* Retrieves whether the JANI input option was set.
*
* @return True if the JANI input option was set.
*/
bool isJaniInputSet() const;
/*!
* Retrieves the name of the file that contains the symbolic model specification if the model was given
* using the symbolic option.
* Retrieves whether the JANI or PRISM input option was set.
*
* @return True if either of the two options was set.
*/
bool isPrismOrJaniInputSet() const;
/*!
* Retrieves whether the option to convert PRISM to JANI input was set.
*
* @return The name of the file that contains the symbolic model specification.
* @return True if the option was set.
*/
std::string getSymbolicModelFilename() const;
bool isPrismToJaniSet() const;
/*!
* Retrieves the name of the file that contains the PRISM model specification if the model was given
* using the PRISM input option.
*
* @return The name of the file that contains the PRISM model specification.
*/
std::string getPrismInputFilename() const;
/*!
* Retrieves the name of the file that contains the JANI model specification if the model was given
* using the JANI input option.
*
* @return The name of the file that contains the JANI model specification.
*/
std::string getJaniInputFilename() const;
/*!
* Retrieves whether the model exploration order was set.
*
@ -174,8 +203,9 @@ namespace storm {
static const std::string exportMatOptionName;
static const std::string explicitOptionName;
static const std::string explicitOptionShortName;
static const std::string symbolicOptionName;
static const std::string symbolicOptionShortName;
static const std::string prismInputOptionName;
static const std::string janiInputOptionName;
static const std::string prismToJaniOptionName;
static const std::string explorationOrderOptionName;
static const std::string explorationOrderOptionShortName;
static const std::string transitionRewardsOptionName;

83
src/storage/SymbolicModelDescription.cpp

@ -0,0 +1,83 @@
#include "src/storage/SymbolicModelDescription.h"
#include "src/utility/prism.h"
#include "src/utility/jani.h"
#include "src/utility/macros.h"
#include "src/exceptions/InvalidOperationException.h"
namespace storm {
namespace storage {
SymbolicModelDescription::SymbolicModelDescription(storm::jani::Model const& model) : modelDescription(model) {
// Intentionally left empty.
}
SymbolicModelDescription::SymbolicModelDescription(storm::prism::Program const& program) : modelDescription(program) {
// Intentionally left empty.
}
SymbolicModelDescription& SymbolicModelDescription::operator=(storm::jani::Model const& model) {
this->modelDescription = model;
return *this;
}
SymbolicModelDescription& SymbolicModelDescription::operator=(storm::prism::Program const& program) {
this->modelDescription = program;
return *this;
}
bool SymbolicModelDescription::hasModel() const {
return static_cast<bool>(modelDescription);
}
bool SymbolicModelDescription::isJaniModel() const {
return modelDescription.get().which() == 0;
}
bool SymbolicModelDescription::isPrismProgram() const {
return modelDescription.get().which() == 1;
}
void SymbolicModelDescription::setModel(storm::jani::Model const& model) {
modelDescription = model;
}
void SymbolicModelDescription::setModel(storm::prism::Program const& program) {
modelDescription = program;
}
storm::jani::Model const& SymbolicModelDescription::asJaniModel() const {
STORM_LOG_THROW(isJaniModel(), storm::exceptions::InvalidOperationException, "Cannot retrieve JANI model, because the symbolic description has a different type.");
return boost::get<storm::jani::Model>(modelDescription.get());
}
storm::prism::Program const& SymbolicModelDescription::asPrismProgram() const {
STORM_LOG_THROW(isPrismProgram(), storm::exceptions::InvalidOperationException, "Cannot retrieve JANI model, because the symbolic description has a different type.");
return boost::get<storm::prism::Program>(modelDescription.get());
}
SymbolicModelDescription SymbolicModelDescription::toJani(bool makeVariablesGlobal) const {
if (this->isJaniModel()) {
return *this;
}
if (this->isPrismProgram()) {
return SymbolicModelDescription(this->asPrismProgram().toJani(makeVariablesGlobal));
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot transform model description to the JANI format.");
}
}
SymbolicModelDescription SymbolicModelDescription::preprocess(std::string const& constantDefinitionString) const {
if (this->isJaniModel()) {
std::map<storm::expressions::Variable, storm::expressions::Expression> substitution = storm::utility::jani::parseConstantDefinitionString(this->asJaniModel(), constantDefinitionString);
return SymbolicModelDescription(this->asJaniModel().defineUndefinedConstants(substitution).substituteConstants());
} else if (this->isPrismProgram()) {
std::map<storm::expressions::Variable, storm::expressions::Expression> substitution = storm::utility::prism::parseConstantDefinitionString(this->asPrismProgram(), constantDefinitionString);
return SymbolicModelDescription(this->asPrismProgram().defineUndefinedConstants(substitution).substituteConstants());
}
return *this;
}
}
}

39
src/storage/SymbolicModelDescription.h

@ -0,0 +1,39 @@
#pragma once
#include <boost/variant.hpp>
#include "src/storage/jani/Model.h"
#include "src/storage/prism/Program.h"
namespace storm {
namespace storage {
class SymbolicModelDescription {
public:
SymbolicModelDescription() = default;
SymbolicModelDescription(storm::jani::Model const& model);
SymbolicModelDescription(storm::prism::Program const& program);
SymbolicModelDescription& operator=(storm::jani::Model const& model);
SymbolicModelDescription& operator=(storm::prism::Program const& program);
bool hasModel() const;
bool isJaniModel() const;
bool isPrismProgram() const;
void setModel(storm::jani::Model const& model);
void setModel(storm::prism::Program const& program);
storm::jani::Model const& asJaniModel() const;
storm::prism::Program const& asPrismProgram() const;
SymbolicModelDescription toJani(bool makeVariablesGlobal = true) const;
SymbolicModelDescription preprocess(std::string const& constantDefinitionString = "") const;
private:
boost::optional<boost::variant<storm::jani::Model, storm::prism::Program>> modelDescription;
};
}
}

82
src/storage/expressions/BaseExpression.cpp

@ -4,6 +4,8 @@
#include "src/exceptions/InvalidTypeException.h"
#include "src/exceptions/InvalidAccessException.h"
#include "src/storage/expressions/Expressions.h"
namespace storm {
namespace expressions {
BaseExpression::BaseExpression(ExpressionManager const& manager, Type const& type) : manager(manager), type(type) {
@ -94,6 +96,86 @@ namespace storm {
return this->shared_from_this();
}
bool BaseExpression::isIfThenElseExpression() const {
return false;
}
IfThenElseExpression const& BaseExpression::asIfThenElseExpression() const {
return static_cast<IfThenElseExpression const&>(*this);
}
bool BaseExpression::isBinaryBooleanFunctionExpression() const {
return false;
}
BinaryBooleanFunctionExpression const& BaseExpression::asBinaryBooleanFunctionExpression() const {
return static_cast<BinaryBooleanFunctionExpression const&>(*this);
}
bool BaseExpression::isBinaryNumericalFunctionExpression() const {
return false;
}
BinaryNumericalFunctionExpression const& BaseExpression::asBinaryNumericalFunctionExpression() const {
return static_cast<BinaryNumericalFunctionExpression const&>(*this);
}
bool BaseExpression::isBinaryRelationExpression() const {
return false;
}
BinaryRelationExpression const& BaseExpression::asBinaryRelationExpression() const {
return static_cast<BinaryRelationExpression const&>(*this);
}
bool BaseExpression::isBooleanLiteralExpression() const {
return false;
}
BooleanLiteralExpression const& BaseExpression::asBooleanLiteralExpression() const {
return static_cast<BooleanLiteralExpression const&>(*this);
}
bool BaseExpression::isIntegerLiteralExpression() const {
return false;
}
IntegerLiteralExpression const& BaseExpression::asIntegerLiteralExpression() const {
return static_cast<IntegerLiteralExpression const&>(*this);
}
bool BaseExpression::isRationalLiteralExpression() const {
return false;
}
RationalLiteralExpression const& BaseExpression::asRationalLiteralExpression() const {
return static_cast<RationalLiteralExpression const&>(*this);
}
bool BaseExpression::isUnaryBooleanFunctionExpression() const {
return false;
}
UnaryBooleanFunctionExpression const& BaseExpression::asUnaryBooleanFunctionExpression() const {
return static_cast<UnaryBooleanFunctionExpression const&>(*this);
}
bool BaseExpression::isUnaryNumericalFunctionExpression() const {
return false;
}
UnaryNumericalFunctionExpression const& BaseExpression::asUnaryNumericalFunctionExpression() const {
return static_cast<UnaryNumericalFunctionExpression const&>(*this);
}
bool BaseExpression::isVariableExpression() const {
return false;
}
VariableExpression const& BaseExpression::asVariableExpression() const {
return static_cast<VariableExpression const&>(*this);
}
std::ostream& operator<<(std::ostream& stream, BaseExpression const& expression) {
expression.printToStream(stream);
return stream;

46
src/storage/expressions/BaseExpression.h

@ -13,12 +13,24 @@
namespace storm {
namespace expressions {
// Forward-declare expression manager.
// Forward-declare expression classes.
class ExpressionManager;
class Variable;
class Valuation;
class ExpressionVisitor;
enum struct OperatorType;
class IfThenElseExpression;
class BinaryBooleanFunctionExpression;
class BinaryNumericalFunctionExpression;
class BinaryRelationExpression;
class BooleanLiteralExpression;
class IntegerLiteralExpression;
class RationalLiteralExpression;
class UnaryBooleanFunctionExpression;
class UnaryNumericalFunctionExpression;
class VariableExpression;
/*!
* The base class of all expression classes.
*/
@ -164,7 +176,7 @@ namespace storm {
*
* @param visitor The visitor that is to be accepted.
*/
virtual boost::any accept(ExpressionVisitor& visitor) const = 0;
virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const = 0;
/*!
* Retrieves whether the expression has a numerical type, i.e., integer or double.
@ -224,6 +236,36 @@ namespace storm {
friend std::ostream& operator<<(std::ostream& stream, BaseExpression const& expression);
virtual bool isIfThenElseExpression() const;
IfThenElseExpression const& asIfThenElseExpression() const;
virtual bool isBinaryBooleanFunctionExpression() const;
BinaryBooleanFunctionExpression const& asBinaryBooleanFunctionExpression() const;
virtual bool isBinaryNumericalFunctionExpression() const;
BinaryNumericalFunctionExpression const& asBinaryNumericalFunctionExpression() const;
virtual bool isBinaryRelationExpression() const;
BinaryRelationExpression const& asBinaryRelationExpression() const;
virtual bool isBooleanLiteralExpression() const;
BooleanLiteralExpression const& asBooleanLiteralExpression() const;
virtual bool isIntegerLiteralExpression() const;
IntegerLiteralExpression const& asIntegerLiteralExpression() const;
virtual bool isRationalLiteralExpression() const;
RationalLiteralExpression const& asRationalLiteralExpression() const;
virtual bool isUnaryBooleanFunctionExpression() const;
UnaryBooleanFunctionExpression const& asUnaryBooleanFunctionExpression() const;
virtual bool isUnaryNumericalFunctionExpression() const;
UnaryNumericalFunctionExpression const& asUnaryNumericalFunctionExpression() const;
virtual bool isVariableExpression() const;
VariableExpression const& asVariableExpression() const;
protected:
/*!
* Prints the expression to the given stream.

4
src/storage/expressions/BinaryBooleanFunctionExpression.cpp

@ -119,8 +119,8 @@ namespace storm {
}
}
boost::any BinaryBooleanFunctionExpression::accept(ExpressionVisitor& visitor) const {
return visitor.visit(*this);
boost::any BinaryBooleanFunctionExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this, data);
}
void BinaryBooleanFunctionExpression::printToStream(std::ostream& stream) const {

2
src/storage/expressions/BinaryBooleanFunctionExpression.h

@ -37,7 +37,7 @@ namespace storm {
virtual storm::expressions::OperatorType getOperator() const override;
virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual boost::any accept(ExpressionVisitor& visitor) const override;
virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override;
/*!
* Retrieves the operator associated with the expression.

8
src/storage/expressions/BinaryNumericalFunctionExpression.cpp

@ -3,7 +3,7 @@
#include "src/storage/expressions/BinaryNumericalFunctionExpression.h"
#include "src/storage/expressions/IntegerLiteralExpression.h"
#include "src/storage/expressions/DoubleLiteralExpression.h"
#include "src/storage/expressions/RationalLiteralExpression.h"
#include "src/storage/expressions/ExpressionVisitor.h"
#include "src/utility/macros.h"
#include "src/exceptions/InvalidTypeException.h"
@ -102,7 +102,7 @@ namespace storm {
case OperatorType::Power: newValue = static_cast<int_fast64_t>(std::pow(firstOperandEvaluation, secondOperandEvaluation)); break;
case OperatorType::Divide: STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Unable to simplify division."); break;
}
return std::shared_ptr<BaseExpression>(new DoubleLiteralExpression(this->getManager(), newValue));
return std::shared_ptr<BaseExpression>(new RationalLiteralExpression(this->getManager(), newValue));
}
}
@ -113,8 +113,8 @@ namespace storm {
}
}
boost::any BinaryNumericalFunctionExpression::accept(ExpressionVisitor& visitor) const {
return visitor.visit(*this);
boost::any BinaryNumericalFunctionExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this, data);
}
void BinaryNumericalFunctionExpression::printToStream(std::ostream& stream) const {

2
src/storage/expressions/BinaryNumericalFunctionExpression.h

@ -38,7 +38,7 @@ namespace storm {
virtual int_fast64_t evaluateAsInt(Valuation const* valuation = nullptr) const override;
virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual boost::any accept(ExpressionVisitor& visitor) const override;
virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override;
/*!
* Retrieves the operator associated with the expression.

4
src/storage/expressions/BinaryRelationExpression.cpp

@ -81,8 +81,8 @@ namespace storm {
}
}
boost::any BinaryRelationExpression::accept(ExpressionVisitor& visitor) const {
return visitor.visit(*this);
boost::any BinaryRelationExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this, data);
}
BinaryRelationExpression::RelationType BinaryRelationExpression::getRelationType() const {

2
src/storage/expressions/BinaryRelationExpression.h

@ -37,7 +37,7 @@ namespace storm {
virtual storm::expressions::OperatorType getOperator() const override;
virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual boost::any accept(ExpressionVisitor& visitor) const override;
virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override;
/*!
* Retrieves the relation associated with the expression.

4
src/storage/expressions/BooleanLiteralExpression.cpp

@ -32,8 +32,8 @@ namespace storm {
return this->shared_from_this();
}
boost::any BooleanLiteralExpression::accept(ExpressionVisitor& visitor) const {
return visitor.visit(*this);
boost::any BooleanLiteralExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this, data);
}
bool BooleanLiteralExpression::getValue() const {

2
src/storage/expressions/BooleanLiteralExpression.h

@ -32,7 +32,7 @@ namespace storm {
virtual bool isFalse() const override;
virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual boost::any accept(ExpressionVisitor& visitor) const override;
virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override;
/*!
* Retrieves the value of the boolean literal.

39
src/storage/expressions/DoubleLiteralExpression.cpp

@ -1,39 +0,0 @@
#include "src/storage/expressions/DoubleLiteralExpression.h"
#include "src/storage/expressions/ExpressionManager.h"
#include "src/storage/expressions/ExpressionVisitor.h"
namespace storm {
namespace expressions {
DoubleLiteralExpression::DoubleLiteralExpression(ExpressionManager const& manager, double value) : BaseExpression(manager, manager.getRationalType()), value(value) {
// Intentionally left empty.
}
double DoubleLiteralExpression::evaluateAsDouble(Valuation const* valuation) const {
return this->getValue();
}
bool DoubleLiteralExpression::isLiteral() const {
return true;
}
void DoubleLiteralExpression::gatherVariables(std::set<storm::expressions::Variable>& variables) const {
return;
}
std::shared_ptr<BaseExpression const> DoubleLiteralExpression::simplify() const {
return this->shared_from_this();
}
boost::any DoubleLiteralExpression::accept(ExpressionVisitor& visitor) const {
return visitor.visit(*this);
}
double DoubleLiteralExpression::getValue() const {
return this->value;
}
void DoubleLiteralExpression::printToStream(std::ostream& stream) const {
stream << this->getValue();
}
}
}

53
src/storage/expressions/DoubleLiteralExpression.h

@ -1,53 +0,0 @@
#ifndef STORM_STORAGE_EXPRESSIONS_DOUBLELITERALEXPRESSION_H_
#define STORM_STORAGE_EXPRESSIONS_DOUBLELITERALEXPRESSION_H_
#include "src/storage/expressions/BaseExpression.h"
#include "src/utility/OsDetection.h"
namespace storm {
namespace expressions {
class DoubleLiteralExpression : public BaseExpression {
public:
/*!
* Creates an double literal expression with the given value.
*
* @param manager The manager responsible for this expression.
* @param value The value of the double literal.
*/
DoubleLiteralExpression(ExpressionManager const& manager, double value);
// Instantiate constructors and assignments with their default implementations.
DoubleLiteralExpression(DoubleLiteralExpression const& other) = default;
DoubleLiteralExpression& operator=(DoubleLiteralExpression const& other) = delete;
#ifndef WINDOWS
DoubleLiteralExpression(DoubleLiteralExpression&&) = default;
DoubleLiteralExpression& operator=(DoubleLiteralExpression&&) = delete;
#endif
virtual ~DoubleLiteralExpression() = default;
// Override base class methods.
virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override;
virtual bool isLiteral() const override;
virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual boost::any accept(ExpressionVisitor& visitor) const override;
/*!
* Retrieves the value of the double literal.
*
* @return The value of the double literal.
*/
double getValue() const;
protected:
// Override base class method.
virtual void printToStream(std::ostream& stream) const override;
private:
// The value of the double literal.
double value;
};
}
}
#endif /* STORM_STORAGE_EXPRESSIONS_DOUBLELITERALEXPRESSION_H_ */

13
src/storage/expressions/Expression.cpp

@ -5,6 +5,7 @@
#include "src/storage/expressions/ExpressionManager.h"
#include "src/storage/expressions/SubstitutionVisitor.h"
#include "src/storage/expressions/LinearityCheckVisitor.h"
#include "src/storage/expressions/SyntacticalEqualityCheckVisitor.h"
#include "src/storage/expressions/Expressions.h"
#include "src/exceptions/InvalidTypeException.h"
#include "src/exceptions/InvalidArgumentException.h"
@ -158,8 +159,8 @@ namespace storm {
return this->getBaseExpression().hasBitVectorType();
}
boost::any Expression::accept(ExpressionVisitor& visitor) const {
return this->getBaseExpression().accept(visitor);
boost::any Expression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return this->getBaseExpression().accept(visitor, data);
}
bool Expression::isInitialized() const {
@ -168,6 +169,14 @@ namespace storm {
}
return false;
}
bool Expression::isSyntacticallyEqual(storm::expressions::Expression const& other) const {
if (this->getBaseExpressionPointer() == other.getBaseExpressionPointer()) {
return true;
}
SyntacticalEqualityCheckVisitor checker;
return checker.isSyntaticallyEqual(*this, other);
}
std::string Expression::toString() const {
std::stringstream stream;

9
src/storage/expressions/Expression.h

@ -302,7 +302,7 @@ namespace storm {
*
* @param visitor The visitor to accept.
*/
boost::any accept(ExpressionVisitor& visitor) const;
boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const;
/*!
* Converts the expression into a string.
@ -311,11 +311,16 @@ namespace storm {
*/
std::string toString() const;
/**
/*!
* Checks whether the object encapsulates a base-expression.
*/
bool isInitialized() const;
/*!
* Checks whether the two expressions are syntatically the same.
*/
bool isSyntacticallyEqual(storm::expressions::Expression const& other) const;
friend std::ostream& operator<<(std::ostream& stream, Expression const& expression);
private:

6
src/storage/expressions/ExpressionManager.cpp

@ -65,7 +65,11 @@ namespace storm {
}
Expression ExpressionManager::rational(double value) const {
return Expression(std::shared_ptr<BaseExpression>(new DoubleLiteralExpression(*this, value)));
return Expression(std::shared_ptr<BaseExpression>(new RationalLiteralExpression(*this, value)));
}
Expression ExpressionManager::rational(storm::RationalNumber const& value) const {
return Expression(std::shared_ptr<BaseExpression>(new RationalLiteralExpression(*this, value)));
}
bool ExpressionManager::operator==(ExpressionManager const& other) const {

9
src/storage/expressions/ExpressionManager.h

@ -10,6 +10,7 @@
#include "src/storage/expressions/Variable.h"
#include "src/storage/expressions/Expression.h"
#include "src/adapters/CarlAdapter.h"
#include "src/utility/OsDetection.h"
namespace storm {
@ -104,6 +105,14 @@ namespace storm {
* @return The resulting expression.
*/
Expression rational(double value) const;
/*!
* Creates an expression that characterizes the given rational literal.
*
* @param value The value of the rational literal.
* @return The resulting expression.
*/
Expression rational(storm::RationalNumber const& value) const;
/*!
* Compares the two expression managers for equality, which holds iff they are the very same object.

22
src/storage/expressions/ExpressionVisitor.h

@ -15,20 +15,20 @@ namespace storm {
class UnaryNumericalFunctionExpression;
class BooleanLiteralExpression;
class IntegerLiteralExpression;
class DoubleLiteralExpression;
class RationalLiteralExpression;
class ExpressionVisitor {
public:
virtual boost::any visit(IfThenElseExpression const& expression) = 0;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) = 0;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) = 0;
virtual boost::any visit(BinaryRelationExpression const& expression) = 0;
virtual boost::any visit(VariableExpression const& expression) = 0;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) = 0;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) = 0;
virtual boost::any visit(BooleanLiteralExpression const& expression) = 0;
virtual boost::any visit(IntegerLiteralExpression const& expression) = 0;
virtual boost::any visit(DoubleLiteralExpression const& expression) = 0;
virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(VariableExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) = 0;
};
}
}

2
src/storage/expressions/Expressions.h

@ -4,7 +4,7 @@
#include "src/storage/expressions/BinaryRelationExpression.h"
#include "src/storage/expressions/BooleanLiteralExpression.h"
#include "src/storage/expressions/IntegerLiteralExpression.h"
#include "src/storage/expressions/DoubleLiteralExpression.h"
#include "src/storage/expressions/RationalLiteralExpression.h"
#include "src/storage/expressions/UnaryBooleanFunctionExpression.h"
#include "src/storage/expressions/UnaryNumericalFunctionExpression.h"
#include "src/storage/expressions/VariableExpression.h"

4
src/storage/expressions/IfThenElseExpression.cpp

@ -88,8 +88,8 @@ namespace storm {
}
}
boost::any IfThenElseExpression::accept(ExpressionVisitor& visitor) const {
return visitor.visit(*this);
boost::any IfThenElseExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this, data);
}
std::shared_ptr<BaseExpression const> IfThenElseExpression::getCondition() const {

2
src/storage/expressions/IfThenElseExpression.h

@ -38,7 +38,7 @@ namespace storm {
virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override;
virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual boost::any accept(ExpressionVisitor& visitor) const override;
virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override;
/*!
* Retrieves the condition expression of the if-then-else expression.

4
src/storage/expressions/IntegerLiteralExpression.cpp

@ -29,8 +29,8 @@ namespace storm {
return this->shared_from_this();
}
boost::any IntegerLiteralExpression::accept(ExpressionVisitor& visitor) const {
return visitor.visit(*this);
boost::any IntegerLiteralExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this, data);
}
int_fast64_t IntegerLiteralExpression::getValue() const {

2
src/storage/expressions/IntegerLiteralExpression.h

@ -31,7 +31,7 @@ namespace storm {
virtual bool isLiteral() const override;
virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual boost::any accept(ExpressionVisitor& visitor) const override;
virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override;
/*!
* Retrieves the value of the integer literal.

30
src/storage/expressions/LinearCoefficientVisitor.cpp

@ -85,20 +85,20 @@ namespace storm {
}
LinearCoefficientVisitor::VariableCoefficients LinearCoefficientVisitor::getLinearCoefficients(Expression const& expression) {
return boost::any_cast<VariableCoefficients>(expression.getBaseExpression().accept(*this));
return boost::any_cast<VariableCoefficients>(expression.getBaseExpression().accept(*this, boost::none));
}
boost::any LinearCoefficientVisitor::visit(IfThenElseExpression const& expression) {
boost::any LinearCoefficientVisitor::visit(IfThenElseExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
}
boost::any LinearCoefficientVisitor::visit(BinaryBooleanFunctionExpression const& expression) {
boost::any LinearCoefficientVisitor::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
}
boost::any LinearCoefficientVisitor::visit(BinaryNumericalFunctionExpression const& expression) {
VariableCoefficients leftResult = boost::any_cast<VariableCoefficients>(expression.getFirstOperand()->accept(*this));
VariableCoefficients rightResult = boost::any_cast<VariableCoefficients>(expression.getSecondOperand()->accept(*this));
boost::any LinearCoefficientVisitor::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
VariableCoefficients leftResult = boost::any_cast<VariableCoefficients>(expression.getFirstOperand()->accept(*this, data));
VariableCoefficients rightResult = boost::any_cast<VariableCoefficients>(expression.getSecondOperand()->accept(*this, data));
if (expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Plus) {
leftResult += std::move(rightResult);
@ -114,11 +114,11 @@ namespace storm {
return leftResult;
}
boost::any LinearCoefficientVisitor::visit(BinaryRelationExpression const& expression) {
boost::any LinearCoefficientVisitor::visit(BinaryRelationExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
}
boost::any LinearCoefficientVisitor::visit(VariableExpression const& expression) {
boost::any LinearCoefficientVisitor::visit(VariableExpression const& expression, boost::any const& data) {
VariableCoefficients coefficients;
if (expression.getType().isNumericalType()) {
coefficients.setCoefficient(expression.getVariable(), 1);
@ -128,12 +128,12 @@ namespace storm {
return coefficients;
}
boost::any LinearCoefficientVisitor::visit(UnaryBooleanFunctionExpression const& expression) {
boost::any LinearCoefficientVisitor::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
}
boost::any LinearCoefficientVisitor::visit(UnaryNumericalFunctionExpression const& expression) {
VariableCoefficients childResult = boost::any_cast<VariableCoefficients>(expression.getOperand()->accept(*this));
boost::any LinearCoefficientVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
VariableCoefficients childResult = boost::any_cast<VariableCoefficients>(expression.getOperand()->accept(*this, data));
if (expression.getOperatorType() == UnaryNumericalFunctionExpression::OperatorType::Minus) {
childResult.negate();
@ -143,16 +143,16 @@ namespace storm {
}
}
boost::any LinearCoefficientVisitor::visit(BooleanLiteralExpression const& expression) {
boost::any LinearCoefficientVisitor::visit(BooleanLiteralExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
}
boost::any LinearCoefficientVisitor::visit(IntegerLiteralExpression const& expression) {
boost::any LinearCoefficientVisitor::visit(IntegerLiteralExpression const& expression, boost::any const& data) {
return VariableCoefficients(static_cast<double>(expression.getValue()));
}
boost::any LinearCoefficientVisitor::visit(DoubleLiteralExpression const& expression) {
return VariableCoefficients(expression.getValue());
boost::any LinearCoefficientVisitor::visit(RationalLiteralExpression const& expression, boost::any const& data) {
return VariableCoefficients(expression.getValueAsDouble());
}
}
}

20
src/storage/expressions/LinearCoefficientVisitor.h

@ -66,16 +66,16 @@ namespace storm {
*/
VariableCoefficients getLinearCoefficients(Expression const& expression);
virtual boost::any visit(IfThenElseExpression const& expression) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BinaryRelationExpression const& expression) override;
virtual boost::any visit(VariableExpression const& expression) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override;
virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
};
}
}

28
src/storage/expressions/LinearityCheckVisitor.cpp

@ -12,27 +12,27 @@ namespace storm {
}
bool LinearityCheckVisitor::check(Expression const& expression) {
LinearityStatus result = boost::any_cast<LinearityStatus>(expression.getBaseExpression().accept(*this));
LinearityStatus result = boost::any_cast<LinearityStatus>(expression.getBaseExpression().accept(*this, boost::none));
return result == LinearityStatus::LinearWithoutVariables || result == LinearityStatus::LinearContainsVariables;
}
boost::any LinearityCheckVisitor::visit(IfThenElseExpression const& expression) {
boost::any LinearityCheckVisitor::visit(IfThenElseExpression const& expression, boost::any const& data) {
// An if-then-else expression is never linear.
return LinearityStatus::NonLinear;
}
boost::any LinearityCheckVisitor::visit(BinaryBooleanFunctionExpression const& expression) {
boost::any LinearityCheckVisitor::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
// Boolean function applications are not allowed in linear expressions.
return LinearityStatus::NonLinear;
}
boost::any LinearityCheckVisitor::visit(BinaryNumericalFunctionExpression const& expression) {
LinearityStatus leftResult = boost::any_cast<LinearityStatus>(expression.getFirstOperand()->accept(*this));
boost::any LinearityCheckVisitor::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
LinearityStatus leftResult = boost::any_cast<LinearityStatus>(expression.getFirstOperand()->accept(*this, data));
if (leftResult == LinearityStatus::NonLinear) {
return LinearityStatus::NonLinear;
}
LinearityStatus rightResult = boost::any_cast<LinearityStatus>(expression.getSecondOperand()->accept(*this));
LinearityStatus rightResult = boost::any_cast<LinearityStatus>(expression.getSecondOperand()->accept(*this, data));
if (rightResult == LinearityStatus::NonLinear) {
return LinearityStatus::NonLinear;
}
@ -55,37 +55,37 @@ namespace storm {
STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Illegal binary numerical expression operator.");
}
boost::any LinearityCheckVisitor::visit(BinaryRelationExpression const& expression) {
boost::any LinearityCheckVisitor::visit(BinaryRelationExpression const& expression, boost::any const& data) {
return LinearityStatus::NonLinear;
}
boost::any LinearityCheckVisitor::visit(VariableExpression const& expression) {
boost::any LinearityCheckVisitor::visit(VariableExpression const& expression, boost::any const& data) {
return LinearityStatus::LinearContainsVariables;
}
boost::any LinearityCheckVisitor::visit(UnaryBooleanFunctionExpression const& expression) {
boost::any LinearityCheckVisitor::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
// Boolean function applications are not allowed in linear expressions.
return LinearityStatus::NonLinear;
}
boost::any LinearityCheckVisitor::visit(UnaryNumericalFunctionExpression const& expression) {
boost::any LinearityCheckVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
switch (expression.getOperatorType()) {
case UnaryNumericalFunctionExpression::OperatorType::Minus: return expression.getOperand()->accept(*this);
case UnaryNumericalFunctionExpression::OperatorType::Minus: return expression.getOperand()->accept(*this, data);
case UnaryNumericalFunctionExpression::OperatorType::Floor:
case UnaryNumericalFunctionExpression::OperatorType::Ceil: return LinearityStatus::NonLinear;
}
STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Illegal unary numerical expression operator.");
}
boost::any LinearityCheckVisitor::visit(BooleanLiteralExpression const& expression) {
boost::any LinearityCheckVisitor::visit(BooleanLiteralExpression const& expression, boost::any const& data) {
return LinearityStatus::NonLinear;
}
boost::any LinearityCheckVisitor::visit(IntegerLiteralExpression const& expression) {
boost::any LinearityCheckVisitor::visit(IntegerLiteralExpression const& expression, boost::any const& data) {
return LinearityStatus::LinearWithoutVariables;
}
boost::any LinearityCheckVisitor::visit(DoubleLiteralExpression const& expression) {
boost::any LinearityCheckVisitor::visit(RationalLiteralExpression const& expression, boost::any const& data) {
return LinearityStatus::LinearWithoutVariables;
}
}

20
src/storage/expressions/LinearityCheckVisitor.h

@ -20,16 +20,16 @@ namespace storm {
*/
bool check(Expression const& expression);
virtual boost::any visit(IfThenElseExpression const& expression) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BinaryRelationExpression const& expression) override;
virtual boost::any visit(VariableExpression const& expression) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override;
virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
private:
enum class LinearityStatus { NonLinear, LinearContainsVariables, LinearWithoutVariables };

53
src/storage/expressions/RationalLiteralExpression.cpp

@ -0,0 +1,53 @@
#include "src/storage/expressions/RationalLiteralExpression.h"
#include "src/storage/expressions/ExpressionManager.h"
#include "src/storage/expressions/ExpressionVisitor.h"
#include "src/utility/constants.h"
namespace storm {
namespace expressions {
RationalLiteralExpression::RationalLiteralExpression(ExpressionManager const& manager, double value) : BaseExpression(manager, manager.getRationalType()), value(storm::utility::convertNumber<storm::RationalNumber>(value)) {
// Intentionally left empty.
}
RationalLiteralExpression::RationalLiteralExpression(ExpressionManager const& manager, std::string const& valueAsString) : BaseExpression(manager, manager.getRationalType()), value(storm::utility::convertNumber<storm::RationalNumber>(valueAsString)) {
// Intentionally left empty.
}
RationalLiteralExpression::RationalLiteralExpression(ExpressionManager const& manager, storm::RationalNumber const& value) : BaseExpression(manager, manager.getRationalType()), value(value) {
// Intentionally left empty.
}
double RationalLiteralExpression::evaluateAsDouble(Valuation const* valuation) const {
return this->getValueAsDouble();
}
bool RationalLiteralExpression::isLiteral() const {
return true;
}
void RationalLiteralExpression::gatherVariables(std::set<storm::expressions::Variable>& variables) const {
return;
}
std::shared_ptr<BaseExpression const> RationalLiteralExpression::simplify() const {
return this->shared_from_this();
}
boost::any RationalLiteralExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this, data);
}
double RationalLiteralExpression::getValueAsDouble() const {
return storm::utility::convertNumber<double>(this->value);
}
storm::RationalNumber RationalLiteralExpression::getValue() const {
return this->value;
}
void RationalLiteralExpression::printToStream(std::ostream& stream) const {
stream << this->getValue();
}
}
}

78
src/storage/expressions/RationalLiteralExpression.h

@ -0,0 +1,78 @@
#ifndef STORM_STORAGE_EXPRESSIONS_RationalLiteralExpression_H_
#define STORM_STORAGE_EXPRESSIONS_RationalLiteralExpression_H_
#include "src/storage/expressions/BaseExpression.h"
#include "src/utility/OsDetection.h"
#include "src/adapters/CarlAdapter.h"
namespace storm {
namespace expressions {
class RationalLiteralExpression : public BaseExpression {
public:
/*!
* Creates an double literal expression with the given value.
*
* @param manager The manager responsible for this expression.
* @param value The value of the double literal.
*/
RationalLiteralExpression(ExpressionManager const& manager, double value);
/*!
* Creates an double literal expression with the value given as a string.
*
* @param manager The manager responsible for this expression.
* @param value The string representation of the value of the literal.
*/
RationalLiteralExpression(ExpressionManager const& manager, std::string const& valueAsString);
/*!
* Creates an double literal expression with the rational value.
*
* @param manager The manager responsible for this expression.
* @param value The rational number that is the value of this literal expression.
*/
RationalLiteralExpression(ExpressionManager const& manager, storm::RationalNumber const& value);
// Instantiate constructors and assignments with their default implementations.
RationalLiteralExpression(RationalLiteralExpression const& other) = default;
RationalLiteralExpression& operator=(RationalLiteralExpression const& other) = delete;
#ifndef WINDOWS
RationalLiteralExpression(RationalLiteralExpression&&) = default;
RationalLiteralExpression& operator=(RationalLiteralExpression&&) = delete;
#endif
virtual ~RationalLiteralExpression() = default;
// Override base class methods.
virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override;
virtual bool isLiteral() const override;
virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override;
/*!
* Retrieves the value of the double literal.
*
* @return The value of the double literal.
*/
double getValueAsDouble() const;
/*!
* Retrieves the value of the double literal.
*
* @return The value of the double literal.
*/
storm::RationalNumber getValue() const;
protected:
// Override base class method.
virtual void printToStream(std::ostream& stream) const override;
private:
// The value of the literal.
storm::RationalNumber value;
};
}
}
#endif /* STORM_STORAGE_EXPRESSIONS_RationalLiteralExpression_H_ */

44
src/storage/expressions/SubstitutionVisitor.cpp

@ -14,14 +14,14 @@ namespace storm {
template<typename MapType>
Expression SubstitutionVisitor<MapType>::substitute(Expression const& expression) {
return Expression(boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getBaseExpression().accept(*this)));
return Expression(boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getBaseExpression().accept(*this, boost::none)));
}
template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(IfThenElseExpression const& expression) {
std::shared_ptr<BaseExpression const> conditionExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getCondition()->accept(*this));
std::shared_ptr<BaseExpression const> thenExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getThenExpression()->accept(*this));
std::shared_ptr<BaseExpression const> elseExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getElseExpression()->accept(*this));
boost::any SubstitutionVisitor<MapType>::visit(IfThenElseExpression const& expression, boost::any const& data) {
std::shared_ptr<BaseExpression const> conditionExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getCondition()->accept(*this, data));
std::shared_ptr<BaseExpression const> thenExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getThenExpression()->accept(*this, data));
std::shared_ptr<BaseExpression const> elseExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getElseExpression()->accept(*this, data));
// If the arguments did not change, we simply push the expression itself.
if (conditionExpression.get() == expression.getCondition().get() && thenExpression.get() == expression.getThenExpression().get() && elseExpression.get() == expression.getElseExpression().get()) {
@ -32,9 +32,9 @@ namespace storm {
}
template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(BinaryBooleanFunctionExpression const& expression) {
std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this));
std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this));
boost::any SubstitutionVisitor<MapType>::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this, data));
std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this, data));
// If the arguments did not change, we simply push the expression itself.
if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) {
@ -45,9 +45,9 @@ namespace storm {
}
template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(BinaryNumericalFunctionExpression const& expression) {
std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this));
std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this));
boost::any SubstitutionVisitor<MapType>::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this, data));
std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this, data));
// If the arguments did not change, we simply push the expression itself.
if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) {
@ -58,9 +58,9 @@ namespace storm {
}
template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(BinaryRelationExpression const& expression) {
std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this));
std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this));
boost::any SubstitutionVisitor<MapType>::visit(BinaryRelationExpression const& expression, boost::any const& data) {
std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this, data));
std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this, data));
// If the arguments did not change, we simply push the expression itself.
if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) {
@ -71,7 +71,7 @@ namespace storm {
}
template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(VariableExpression const& expression) {
boost::any SubstitutionVisitor<MapType>::visit(VariableExpression const& expression, boost::any const& data) {
// If the variable is in the key set of the substitution, we need to replace it.
auto const& nameExpressionPair = this->variableToExpressionMapping.find(expression.getVariable());
if (nameExpressionPair != this->variableToExpressionMapping.end()) {
@ -82,8 +82,8 @@ namespace storm {
}
template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(UnaryBooleanFunctionExpression const& expression) {
std::shared_ptr<BaseExpression const> operandExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getOperand()->accept(*this));
boost::any SubstitutionVisitor<MapType>::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
std::shared_ptr<BaseExpression const> operandExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getOperand()->accept(*this, data));
// If the argument did not change, we simply push the expression itself.
if (operandExpression.get() == expression.getOperand().get()) {
@ -94,8 +94,8 @@ namespace storm {
}
template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(UnaryNumericalFunctionExpression const& expression) {
std::shared_ptr<BaseExpression const> operandExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getOperand()->accept(*this));
boost::any SubstitutionVisitor<MapType>::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
std::shared_ptr<BaseExpression const> operandExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getOperand()->accept(*this, data));
// If the argument did not change, we simply push the expression itself.
if (operandExpression.get() == expression.getOperand().get()) {
@ -106,17 +106,17 @@ namespace storm {
}
template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(BooleanLiteralExpression const& expression) {
boost::any SubstitutionVisitor<MapType>::visit(BooleanLiteralExpression const& expression, boost::any const& data) {
return expression.getSharedPointer();
}
template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(IntegerLiteralExpression const& expression) {
boost::any SubstitutionVisitor<MapType>::visit(IntegerLiteralExpression const& expression, boost::any const& data) {
return expression.getSharedPointer();
}
template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(DoubleLiteralExpression const& expression) {
boost::any SubstitutionVisitor<MapType>::visit(RationalLiteralExpression const& expression, boost::any const& data) {
return expression.getSharedPointer();
}

20
src/storage/expressions/SubstitutionVisitor.h

@ -28,16 +28,16 @@ namespace storm {
*/
Expression substitute(Expression const& expression);
virtual boost::any visit(IfThenElseExpression const& expression) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BinaryRelationExpression const& expression) override;
virtual boost::any visit(VariableExpression const& expression) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override;
virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
private:
// A mapping of variables to expressions with which they shall be replaced.

155
src/storage/expressions/SyntacticalEqualityCheckVisitor.cpp

@ -0,0 +1,155 @@
#include "src/storage/expressions/SyntacticalEqualityCheckVisitor.h"
#include "src/storage/expressions/Expressions.h"
namespace storm {
namespace expressions {
bool SyntacticalEqualityCheckVisitor::isSyntaticallyEqual(storm::expressions::Expression const& expression1, storm::expressions::Expression const& expression2) {
return boost::any_cast<bool>(expression1.accept(*this, std::ref(expression2.getBaseExpression())));
}
boost::any SyntacticalEqualityCheckVisitor::visit(IfThenElseExpression const& expression, boost::any const& data) {
BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get();
if (otherBaseExpression.isIfThenElseExpression()) {
IfThenElseExpression const& otherExpression = otherBaseExpression.asIfThenElseExpression();
bool result = boost::any_cast<bool>(expression.getCondition()->accept(*this, std::ref(*otherExpression.getCondition())));
if (result) {
result = boost::any_cast<bool>(expression.getThenExpression()->accept(*this, std::ref(*otherExpression.getThenExpression())));
}
if (result) {
result = boost::any_cast<bool>(expression.getElseExpression()->accept(*this, std::ref(*otherExpression.getElseExpression())));
}
return result;
} else {
return false;
}
}
boost::any SyntacticalEqualityCheckVisitor::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get();
if (otherBaseExpression.isBinaryBooleanFunctionExpression()) {
BinaryBooleanFunctionExpression const& otherExpression = otherBaseExpression.asBinaryBooleanFunctionExpression();
bool result = expression.getOperatorType() == otherExpression.getOperatorType();
if (result) {
result = boost::any_cast<bool>(expression.getFirstOperand()->accept(*this, std::ref(*otherExpression.getFirstOperand())));
}
if (result) {
result = boost::any_cast<bool>(expression.getSecondOperand()->accept(*this, std::ref(*otherExpression.getSecondOperand())));
}
return result;
} else {
return false;
}
}
boost::any SyntacticalEqualityCheckVisitor::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get();
if (otherBaseExpression.isBinaryNumericalFunctionExpression()) {
BinaryNumericalFunctionExpression const& otherExpression = otherBaseExpression.asBinaryNumericalFunctionExpression();
bool result = expression.getOperatorType() == otherExpression.getOperatorType();
if (result) {
result = boost::any_cast<bool>(expression.getFirstOperand()->accept(*this, std::ref(*otherExpression.getFirstOperand())));
}
if (result) {
result = boost::any_cast<bool>(expression.getSecondOperand()->accept(*this, std::ref(*otherExpression.getSecondOperand())));
}
return result;
} else {
return false;
}
}
boost::any SyntacticalEqualityCheckVisitor::visit(BinaryRelationExpression const& expression, boost::any const& data) {
BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get();
if (otherBaseExpression.isBinaryRelationExpression()) {
BinaryRelationExpression const& otherExpression = otherBaseExpression.asBinaryRelationExpression();
bool result = expression.getRelationType() == otherExpression.getRelationType();
if (result) {
result = boost::any_cast<bool>(expression.getFirstOperand()->accept(*this, std::ref(*otherExpression.getFirstOperand())));
}
if (result) {
result = boost::any_cast<bool>(expression.getSecondOperand()->accept(*this, std::ref(*otherExpression.getSecondOperand())));
}
return result;
} else {
return false;
}
}
boost::any SyntacticalEqualityCheckVisitor::visit(VariableExpression const& expression, boost::any const& data) {
BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get();
if (otherBaseExpression.isVariableExpression()) {
VariableExpression const& otherExpression = otherBaseExpression.asVariableExpression();
return expression.getVariable() == otherExpression.getVariable();
} else {
return false;
}
}
boost::any SyntacticalEqualityCheckVisitor::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get();
if (otherBaseExpression.isBinaryBooleanFunctionExpression()) {
UnaryBooleanFunctionExpression const& otherExpression = otherBaseExpression.asUnaryBooleanFunctionExpression();
bool result = expression.getOperatorType() == otherExpression.getOperatorType();
if (result) {
result = boost::any_cast<bool>(expression.getOperand()->accept(*this, std::ref(*otherExpression.getOperand())));
}
return result;
} else {
return false;
}
}
boost::any SyntacticalEqualityCheckVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get();
if (otherBaseExpression.isBinaryBooleanFunctionExpression()) {
UnaryNumericalFunctionExpression const& otherExpression = otherBaseExpression.asUnaryNumericalFunctionExpression();
bool result = expression.getOperatorType() == otherExpression.getOperatorType();
if (result) {
result = boost::any_cast<bool>(expression.getOperand()->accept(*this, std::ref(*otherExpression.getOperand())));
}
return result;
} else {
return false;
}
}
boost::any SyntacticalEqualityCheckVisitor::visit(BooleanLiteralExpression const& expression, boost::any const& data) {
BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get();
if (otherBaseExpression.isBooleanLiteralExpression()) {
BooleanLiteralExpression const& otherExpression = otherBaseExpression.asBooleanLiteralExpression();
return expression.getValue() == otherExpression.getValue();
} else {
return false;
}
}
boost::any SyntacticalEqualityCheckVisitor::visit(IntegerLiteralExpression const& expression, boost::any const& data) {
BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get();
if (otherBaseExpression.isIntegerLiteralExpression()) {
IntegerLiteralExpression const& otherExpression = otherBaseExpression.asIntegerLiteralExpression();
return expression.getValue() == otherExpression.getValue();
} else {
return false;
}
}
boost::any SyntacticalEqualityCheckVisitor::visit(RationalLiteralExpression const& expression, boost::any const& data) {
BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get();
if (otherBaseExpression.isRationalLiteralExpression()) {
RationalLiteralExpression const& otherExpression = otherBaseExpression.asRationalLiteralExpression();
return expression.getValue() == otherExpression.getValue();
} else {
return false;
}
}
}
}

27
src/storage/expressions/SyntacticalEqualityCheckVisitor.h

@ -0,0 +1,27 @@
#pragma once
#include "src/storage/expressions/ExpressionVisitor.h"
namespace storm {
namespace expressions {
class Expression;
class SyntacticalEqualityCheckVisitor : public ExpressionVisitor {
public:
bool isSyntaticallyEqual(storm::expressions::Expression const& expression1, storm::expressions::Expression const& expression2);
virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
};
}
}

108
src/storage/expressions/ToExprtkStringVisitor.cpp

@ -9,210 +9,210 @@ namespace storm {
std::string ToExprtkStringVisitor::toString(BaseExpression const* expression) {
stream.str("");
stream.clear();
expression->accept(*this);
expression->accept(*this, boost::none);
return stream.str();
}
boost::any ToExprtkStringVisitor::visit(IfThenElseExpression const& expression) {
boost::any ToExprtkStringVisitor::visit(IfThenElseExpression const& expression, boost::any const& data) {
stream << "if(";
expression.getCondition()->accept(*this);
expression.getCondition()->accept(*this, data);
stream << ",";
expression.getThenExpression()->accept(*this);
expression.getThenExpression()->accept(*this, data);
stream << ",";
expression.getElseExpression()->accept(*this);
expression.getElseExpression()->accept(*this, data);
stream << ")";
return boost::any();
}
boost::any ToExprtkStringVisitor::visit(BinaryBooleanFunctionExpression const& expression) {
boost::any ToExprtkStringVisitor::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
switch (expression.getOperatorType()) {
case BinaryBooleanFunctionExpression::OperatorType::And:
stream << "(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << " and ";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryBooleanFunctionExpression::OperatorType::Or:
stream << "(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << " or ";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryBooleanFunctionExpression::OperatorType::Xor:
stream << "(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << " xor ";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryBooleanFunctionExpression::OperatorType::Implies:
stream << "(not(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << ") or ";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryBooleanFunctionExpression::OperatorType::Iff:
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << "==";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
break;
}
return boost::any();
}
boost::any ToExprtkStringVisitor::visit(BinaryNumericalFunctionExpression const& expression) {
boost::any ToExprtkStringVisitor::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
switch (expression.getOperatorType()) {
case BinaryNumericalFunctionExpression::OperatorType::Plus:
stream << "(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << "+";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryNumericalFunctionExpression::OperatorType::Minus:
stream << "(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << "-";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryNumericalFunctionExpression::OperatorType::Times:
stream << "(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << "*";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryNumericalFunctionExpression::OperatorType::Divide:
stream << "(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << "/";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryNumericalFunctionExpression::OperatorType::Power:
stream << "(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << "^";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryNumericalFunctionExpression::OperatorType::Max:
stream << "max(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << ",";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryNumericalFunctionExpression::OperatorType::Min:
stream << "min(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << ",";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
}
return boost::any();
}
boost::any ToExprtkStringVisitor::visit(BinaryRelationExpression const& expression) {
boost::any ToExprtkStringVisitor::visit(BinaryRelationExpression const& expression, boost::any const& data) {
switch (expression.getRelationType()) {
case BinaryRelationExpression::RelationType::Equal:
stream << "(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << "==";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryRelationExpression::RelationType::NotEqual:
stream << "(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << "!=";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryRelationExpression::RelationType::Less:
stream << "(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << "<";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryRelationExpression::RelationType::LessOrEqual:
stream << "(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << "<=";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryRelationExpression::RelationType::Greater:
stream << "(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << ">";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
case BinaryRelationExpression::RelationType::GreaterOrEqual:
stream << "(";
expression.getFirstOperand()->accept(*this);
expression.getFirstOperand()->accept(*this, data);
stream << ">=";
expression.getSecondOperand()->accept(*this);
expression.getSecondOperand()->accept(*this, data);
stream << ")";
break;
}
return boost::any();
}
boost::any ToExprtkStringVisitor::visit(VariableExpression const& expression) {
boost::any ToExprtkStringVisitor::visit(VariableExpression const& expression, boost::any const& data) {
stream << expression.getVariableName();
return boost::any();
}
boost::any ToExprtkStringVisitor::visit(UnaryBooleanFunctionExpression const& expression) {
boost::any ToExprtkStringVisitor::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
switch (expression.getOperatorType()) {
case UnaryBooleanFunctionExpression::OperatorType::Not:
stream << "not(";
expression.getOperand()->accept(*this);
expression.getOperand()->accept(*this, data);
stream << ")";
}
return boost::any();
}
boost::any ToExprtkStringVisitor::visit(UnaryNumericalFunctionExpression const& expression) {
boost::any ToExprtkStringVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
switch (expression.getOperatorType()) {
case UnaryNumericalFunctionExpression::OperatorType::Minus:
stream << "-(";
expression.getOperand()->accept(*this);
expression.getOperand()->accept(*this, data);
stream << ")";
break;
case UnaryNumericalFunctionExpression::OperatorType::Floor:
stream << "floor(";
expression.getOperand()->accept(*this);
expression.getOperand()->accept(*this, data);
stream << ")";
break;
case UnaryNumericalFunctionExpression::OperatorType::Ceil:
stream << "ceil(";
expression.getOperand()->accept(*this);
expression.getOperand()->accept(*this, data);
stream << ")";
break;
}
return boost::any();
}
boost::any ToExprtkStringVisitor::visit(BooleanLiteralExpression const& expression) {
boost::any ToExprtkStringVisitor::visit(BooleanLiteralExpression const& expression, boost::any const& data) {
stream << expression.getValue();
return boost::any();
}
boost::any ToExprtkStringVisitor::visit(IntegerLiteralExpression const& expression) {
boost::any ToExprtkStringVisitor::visit(IntegerLiteralExpression const& expression, boost::any const& data) {
stream << expression.getValue();
return boost::any();
}
boost::any ToExprtkStringVisitor::visit(DoubleLiteralExpression const& expression) {
boost::any ToExprtkStringVisitor::visit(RationalLiteralExpression const& expression, boost::any const& data) {
stream << expression.getValue();
return boost::any();
}

20
src/storage/expressions/ToExprtkStringVisitor.h

@ -16,16 +16,16 @@ namespace storm {
std::string toString(Expression const& expression);
std::string toString(BaseExpression const* expression);
virtual boost::any visit(IfThenElseExpression const& expression) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BinaryRelationExpression const& expression) override;
virtual boost::any visit(VariableExpression const& expression) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override;
virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
private:
std::stringstream stream;

35
src/storage/expressions/ToRationalFunctionVisitor.cpp

@ -2,6 +2,7 @@
#include <sstream>
#include "src/utility/constants.h"
#include "src/utility/macros.h"
#include "src/exceptions/InvalidArgumentException.h"
@ -16,23 +17,24 @@ namespace storm {
template<typename RationalFunctionType>
RationalFunctionType ToRationalFunctionVisitor<RationalFunctionType>::toRationalFunction(Expression const& expression) {
return boost::any_cast<RationalFunctionType>(expression.accept(*this));
return boost::any_cast<RationalFunctionType>(expression.accept(*this, boost::none));
}
template<typename RationalFunctionType>
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(IfThenElseExpression const& expression) {
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(IfThenElseExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function.");
}
template<typename RationalFunctionType>
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryBooleanFunctionExpression const& expression) {
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function.");
}
template<typename RationalFunctionType>
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryNumericalFunctionExpression const& expression) {
RationalFunctionType firstOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getFirstOperand()->accept(*this));
RationalFunctionType secondOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getSecondOperand()->accept(*this));
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
RationalFunctionType firstOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getFirstOperand()->accept(*this, data));
RationalFunctionType secondOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getSecondOperand()->accept(*this, data));
uint_fast64_t exponentAsInteger = 0;
switch(expression.getOperatorType()) {
case BinaryNumericalFunctionExpression::OperatorType::Plus:
return firstOperandAsRationalFunction + secondOperandAsRationalFunction;
@ -46,6 +48,11 @@ namespace storm {
case BinaryNumericalFunctionExpression::OperatorType::Divide:
return firstOperandAsRationalFunction / secondOperandAsRationalFunction;
break;
case BinaryNumericalFunctionExpression::OperatorType::Power:
STORM_LOG_THROW(storm::utility::isInteger(secondOperandAsRationalFunction), storm::exceptions::InvalidArgumentException, "Exponent of power operator must be a positive integer.");
exponentAsInteger = storm::utility::convertNumber<uint_fast64_t>(secondOperandAsRationalFunction);
return storm::utility::pow(firstOperandAsRationalFunction, exponentAsInteger);
break;
default:
STORM_LOG_ASSERT(false, "Illegal operator type.");
}
@ -55,12 +62,12 @@ namespace storm {
}
template<typename RationalFunctionType>
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryRelationExpression const& expression) {
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryRelationExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function.");
}
template<typename RationalFunctionType>
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(VariableExpression const& expression) {
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(VariableExpression const& expression, boost::any const& data) {
auto variablePair = variableToVariableMap.find(expression.getVariable());
if (variablePair != variableToVariableMap.end()) {
return convertVariableToPolynomial(variablePair->second);
@ -72,28 +79,28 @@ namespace storm {
}
template<typename RationalFunctionType>
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(UnaryBooleanFunctionExpression const& expression) {
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function.");
}
template<typename RationalFunctionType>
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(UnaryNumericalFunctionExpression const& expression) {
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function.");
}
template<typename RationalFunctionType>
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BooleanLiteralExpression const& expression) {
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BooleanLiteralExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function.");
}
template<typename RationalFunctionType>
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(IntegerLiteralExpression const& expression) {
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(IntegerLiteralExpression const& expression, boost::any const& data) {
return RationalFunctionType(carl::rationalize<storm::RationalNumber>(static_cast<size_t>(expression.getValue())));
}
template<typename RationalFunctionType>
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(DoubleLiteralExpression const& expression) {
return RationalFunctionType(carl::rationalize<storm::RationalNumber>(expression.getValue()));
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(RationalLiteralExpression const& expression, boost::any const& data) {
return storm::utility::convertNumber<storm::RationalFunction>(expression.getValue());
}
template class ToRationalFunctionVisitor<storm::RationalFunction>;

20
src/storage/expressions/ToRationalFunctionVisitor.h

@ -18,16 +18,16 @@ namespace storm {
RationalFunctionType toRationalFunction(Expression const& expression);
virtual boost::any visit(IfThenElseExpression const& expression) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BinaryRelationExpression const& expression) override;
virtual boost::any visit(VariableExpression const& expression) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override;
virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
private:
template<typename TP = typename RationalFunctionType::PolyType, carl::EnableIf<carl::needs_cache<TP>> = carl::dummy>

51
src/storage/expressions/ToRationalNumberVisitor.cpp

@ -1,6 +1,7 @@
#include "src/storage/expressions/ToRationalNumberVisitor.h"
#include "src/utility/macros.h"
#include "src/utility/constants.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "src/exceptions/NotSupportedException.h"
@ -13,71 +14,81 @@ namespace storm {
template<typename RationalNumberType>
RationalNumberType ToRationalNumberVisitor<RationalNumberType>::toRationalNumber(Expression const& expression) {
return boost::any_cast<RationalNumberType>(expression.accept(*this));
return boost::any_cast<RationalNumberType>(expression.accept(*this, boost::none));
}
template<typename RationalNumberType>
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(IfThenElseExpression const& expression) {
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(IfThenElseExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
}
template<typename RationalNumberType>
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryBooleanFunctionExpression const& expression) {
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
}
template<typename RationalNumberType>
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryNumericalFunctionExpression const& expression) {
RationalNumberType firstOperandAsRationalFunction = boost::any_cast<RationalNumberType>(expression.getFirstOperand()->accept(*this));
RationalNumberType secondOperandAsRationalFunction = boost::any_cast<RationalNumberType>(expression.getSecondOperand()->accept(*this));
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
RationalNumberType firstOperandAsRationalNumber = boost::any_cast<RationalNumberType>(expression.getFirstOperand()->accept(*this, data));
RationalNumberType secondOperandAsRationalNumber = boost::any_cast<RationalNumberType>(expression.getSecondOperand()->accept(*this, data));
switch(expression.getOperatorType()) {
case BinaryNumericalFunctionExpression::OperatorType::Plus:
return firstOperandAsRationalFunction + secondOperandAsRationalFunction;
return firstOperandAsRationalNumber + secondOperandAsRationalNumber;
break;
case BinaryNumericalFunctionExpression::OperatorType::Minus:
return firstOperandAsRationalFunction - secondOperandAsRationalFunction;
return firstOperandAsRationalNumber - secondOperandAsRationalNumber;
break;
case BinaryNumericalFunctionExpression::OperatorType::Times:
return firstOperandAsRationalFunction * secondOperandAsRationalFunction;
return firstOperandAsRationalNumber * secondOperandAsRationalNumber;
break;
case BinaryNumericalFunctionExpression::OperatorType::Divide:
return firstOperandAsRationalFunction / secondOperandAsRationalFunction;
return firstOperandAsRationalNumber / secondOperandAsRationalNumber;
break;
case BinaryNumericalFunctionExpression::OperatorType::Min:
return std::min(firstOperandAsRationalNumber, secondOperandAsRationalNumber);
break;
case BinaryNumericalFunctionExpression::OperatorType::Max:
return std::max(firstOperandAsRationalNumber, secondOperandAsRationalNumber);
break;
case BinaryNumericalFunctionExpression::OperatorType::Power:
STORM_LOG_THROW(storm::utility::isInteger(secondOperandAsRationalNumber), storm::exceptions::InvalidArgumentException, "Exponent of power operator must be a positive integer.");
uint_fast64_t exponentAsInteger = storm::utility::convertNumber<uint_fast64_t>(secondOperandAsRationalNumber);
return storm::utility::pow(firstOperandAsRationalNumber, exponentAsInteger);
break;
default:
STORM_LOG_ASSERT(false, "Illegal operator type.");
}
// Return a dummy. This point must, however, never be reached.
STORM_LOG_ASSERT(false, "Illegal operator type.");
return boost::any();
}
template<typename RationalNumberType>
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryRelationExpression const& expression) {
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryRelationExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
}
template<typename RationalNumberType>
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(VariableExpression const& expression) {
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(VariableExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot transform expressions containing variables to a rational number.");
}
template<typename RationalNumberType>
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(UnaryBooleanFunctionExpression const& expression) {
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
}
template<typename RationalNumberType>
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(UnaryNumericalFunctionExpression const& expression) {
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
}
template<typename RationalNumberType>
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BooleanLiteralExpression const& expression) {
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BooleanLiteralExpression const& expression, boost::any const& data) {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
}
template<typename RationalNumberType>
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(IntegerLiteralExpression const& expression) {
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(IntegerLiteralExpression const& expression, boost::any const& data) {
#ifdef STORM_HAVE_CARL
return RationalNumberType(carl::rationalize<storm::RationalNumber>(static_cast<size_t>(expression.getValue())));
#else
@ -86,9 +97,9 @@ namespace storm {
}
template<typename RationalNumberType>
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(DoubleLiteralExpression const& expression) {
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(RationalLiteralExpression const& expression, boost::any const& data) {
#ifdef STORM_HAVE_CARL
return RationalNumberType(carl::rationalize<storm::RationalNumber>(expression.getValue()));
return expression.getValue();
#else
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Rational numbers are not supported in this build.");
#endif

20
src/storage/expressions/ToRationalNumberVisitor.h

@ -16,16 +16,16 @@ namespace storm {
RationalNumberType toRationalNumber(Expression const& expression);
virtual boost::any visit(IfThenElseExpression const& expression) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BinaryRelationExpression const& expression) override;
virtual boost::any visit(VariableExpression const& expression) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override;
virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
};
}
}

4
src/storage/expressions/UnaryBooleanFunctionExpression.cpp

@ -49,8 +49,8 @@ namespace storm {
}
}
boost::any UnaryBooleanFunctionExpression::accept(ExpressionVisitor& visitor) const {
return visitor.visit(*this);
boost::any UnaryBooleanFunctionExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this, data);
}
void UnaryBooleanFunctionExpression::printToStream(std::ostream& stream) const {

2
src/storage/expressions/UnaryBooleanFunctionExpression.h

@ -36,7 +36,7 @@ namespace storm {
virtual storm::expressions::OperatorType getOperator() const override;
virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual boost::any accept(ExpressionVisitor& visitor) const override;
virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override;
/*!
* Retrieves the operator associated with this expression.

8
src/storage/expressions/UnaryNumericalFunctionExpression.cpp

@ -4,7 +4,7 @@
#include "src/storage/expressions/UnaryNumericalFunctionExpression.h"
#include "src/storage/expressions/IntegerLiteralExpression.h"
#include "src/storage/expressions/DoubleLiteralExpression.h"
#include "src/storage/expressions/RationalLiteralExpression.h"
#include "ExpressionVisitor.h"
#include "src/utility/macros.h"
#include "src/exceptions/InvalidTypeException.h"
@ -87,7 +87,7 @@ namespace storm {
case OperatorType::Floor: value = std::floor(boost::get<double>(operandEvaluation)); break;
case OperatorType::Ceil: value = std::ceil(boost::get<double>(operandEvaluation)); break;
}
return std::shared_ptr<BaseExpression>(new DoubleLiteralExpression(this->getManager(), value));
return std::shared_ptr<BaseExpression>(new RationalLiteralExpression(this->getManager(), value));
}
}
@ -98,8 +98,8 @@ namespace storm {
}
}
boost::any UnaryNumericalFunctionExpression::accept(ExpressionVisitor& visitor) const {
return visitor.visit(*this);
boost::any UnaryNumericalFunctionExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this, data);
}
void UnaryNumericalFunctionExpression::printToStream(std::ostream& stream) const {

2
src/storage/expressions/UnaryNumericalFunctionExpression.h

@ -37,7 +37,7 @@ namespace storm {
virtual int_fast64_t evaluateAsInt(Valuation const* valuation = nullptr) const override;
virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual boost::any accept(ExpressionVisitor& visitor) const override;
virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override;
/*!
* Retrieves the operator associated with this expression.

4
src/storage/expressions/VariableExpression.cpp

@ -63,8 +63,8 @@ namespace storm {
return this->shared_from_this();
}
boost::any VariableExpression::accept(ExpressionVisitor& visitor) const {
return visitor.visit(*this);
boost::any VariableExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this, data);
}
void VariableExpression::printToStream(std::ostream& stream) const {

2
src/storage/expressions/VariableExpression.h

@ -35,7 +35,7 @@ namespace storm {
virtual bool isVariable() const override;
virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual boost::any accept(ExpressionVisitor& visitor) const override;
virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override;
/*!
* Retrieves the name of the variable associated with this expression.

39
src/storage/jani/Assignment.cpp

@ -1,10 +1,18 @@
#include "src/storage/jani/Assignment.h"
#include "src/utility/macros.h"
#include "src/exceptions/NotImplementedException.h"
namespace storm {
namespace jani {
Assignment::Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression) : variable(variable), expression(expression) {
// Intentionally left empty.
Assignment::Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression, uint64_t level) : variable(variable), expression(expression), level(level) {
STORM_LOG_THROW(level == 0, storm::exceptions::NotImplementedException, "Assignment levels other than 0 are currently not supported.");
}
bool Assignment::operator==(Assignment const& other) const {
// FIXME: the level is currently ignored as we do not support it
return this->isTransient() == other.isTransient() && this->getExpressionVariable() == other.getExpressionVariable() && this->getAssignedExpression().isSyntacticallyEqual(other.getAssignedExpression());
}
storm::jani::Variable const& Assignment::getVariable() const {
@ -23,8 +31,16 @@ namespace storm {
this->expression = expression;
}
bool Assignment::isTransientAssignment() const {
return this->variable.get().isTransientVariable();
bool Assignment::isTransient() const {
return this->variable.get().isTransient();
}
void Assignment::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) {
this->setAssignedExpression(this->getAssignedExpression().substitute(substitution));
}
uint64_t Assignment::getLevel() const {
return level;
}
std::ostream& operator<<(std::ostream& stream, Assignment const& assignment) {
@ -32,5 +48,20 @@ namespace storm {
return stream;
}
bool AssignmentPartialOrderByVariable::operator()(Assignment const& left, Assignment const& right) const {
return left.getExpressionVariable() < right.getExpressionVariable();
}
bool AssignmentPartialOrderByVariable::operator()(Assignment const& left, std::shared_ptr<Assignment> const& right) const {
return left.getExpressionVariable() < right->getExpressionVariable();
}
bool AssignmentPartialOrderByVariable::operator()(std::shared_ptr<Assignment> const& left, std::shared_ptr<Assignment> const& right) const {
return left->getExpressionVariable() < right->getExpressionVariable();
}
bool AssignmentPartialOrderByVariable::operator()(std::shared_ptr<Assignment> const& left, Assignment const& right) const {
return left->getExpressionVariable() < right.getExpressionVariable();
}
}
}

29
src/storage/jani/Assignment.h

@ -13,7 +13,9 @@ namespace storm {
/*!
* Creates an assignment of the given expression to the given variable.
*/
Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression);
Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression, uint64_t index = 0);
bool operator==(Assignment const& other) const;
/*!
* Retrieves the expression variable that is written in this assignment.
@ -35,10 +37,20 @@ namespace storm {
*/
void setAssignedExpression(storm::expressions::Expression const& expression);
/*!
* Substitutes all variables in all expressions according to the given substitution.
*/
void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution);
/**
* Retrieves whether the assignment assigns to a transient variable.
*/
bool isTransientAssignment() const;
bool isTransient() const;
/*!
* Retrieves the level of the assignment.
*/
uint64_t getLevel() const;
friend std::ostream& operator<<(std::ostream& stream, Assignment const& assignment);
@ -48,7 +60,20 @@ namespace storm {
// The expression that is being assigned to the variable.
storm::expressions::Expression expression;
// The level of the assignment.
uint64_t level;
};
/*!
* This functor enables ordering the assignments by variable. Note that this is a partial order.
*/
struct AssignmentPartialOrderByVariable {
bool operator()(Assignment const& left, Assignment const& right) const;
bool operator()(Assignment const& left, std::shared_ptr<Assignment> const& right) const;
bool operator()(std::shared_ptr<Assignment> const& left, std::shared_ptr<Assignment> const& right) const;
bool operator()(std::shared_ptr<Assignment> const& left, Assignment const& right) const;
};
}
}

56
src/storage/jani/Automaton.cpp

@ -61,26 +61,32 @@ namespace storm {
Variable const& Automaton::addVariable(Variable const &variable) {
if (variable.isBooleanVariable()) {
return addBooleanVariable(variable.asBooleanVariable());
return addVariable(variable.asBooleanVariable());
} else if (variable.isBoundedIntegerVariable()) {
return addBoundedIntegerVariable(variable.asBoundedIntegerVariable());
return addVariable(variable.asBoundedIntegerVariable());
} else if (variable.isUnboundedIntegerVariable()) {
return addUnboundedIntegerVariable(variable.asUnboundedIntegerVariable());
return addVariable(variable.asUnboundedIntegerVariable());
} else if (variable.isRealVariable()) {
return addVariable(variable.asRealVariable());
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Variable has invalid type.");
}
}
BooleanVariable const& Automaton::addBooleanVariable(BooleanVariable const& variable) {
return variables.addBooleanVariable(variable);
BooleanVariable const& Automaton::addVariable(BooleanVariable const& variable) {
return variables.addVariable(variable);
}
BoundedIntegerVariable const& Automaton::addBoundedIntegerVariable(BoundedIntegerVariable const& variable) {
return variables.addBoundedIntegerVariable(variable);
BoundedIntegerVariable const& Automaton::addVariable(BoundedIntegerVariable const& variable) {
return variables.addVariable(variable);
}
UnboundedIntegerVariable const& Automaton::addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable) {
return variables.addUnboundedIntegerVariable(variable);
UnboundedIntegerVariable const& Automaton::addVariable(UnboundedIntegerVariable const& variable) {
return variables.addVariable(variable);
}
RealVariable const& Automaton::addVariable(RealVariable const& variable) {
return variables.addVariable(variable);
}
VariableSet& Automaton::getVariables() {
@ -91,6 +97,10 @@ namespace storm {
return variables;
}
bool Automaton::hasTransientVariable() const {
return variables.hasTransientVariable();
}
bool Automaton::hasLocation(std::string const& name) const {
return locationToIndex.find(name) != locationToIndex.end();
}
@ -98,11 +108,19 @@ namespace storm {
std::vector<Location> const& Automaton::getLocations() const {
return locations;
}
std::vector<Location>& Automaton::getLocations() {
return locations;
}
Location const& Automaton::getLocation(uint64_t index) const {
return locations[index];
}
Location& Automaton::getLocation(uint64_t index) {
return locations[index];
}
uint64_t Automaton::addLocation(Location const& location) {
STORM_LOG_THROW(!this->hasLocation(location.getName()), storm::exceptions::WrongFormatException, "Cannot add location with name '" << location.getName() << "', because a location with this name already exists.");
locationToIndex.emplace(location.getName(), locations.size());
@ -352,6 +370,22 @@ namespace storm {
return result;
}
void Automaton::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) {
for (auto& variable : this->getVariables().getBoundedIntegerVariables()) {
variable.substitute(substitution);
}
for (auto& location : this->getLocations()) {
location.substitute(substitution);
}
this->setInitialStatesRestriction(this->getInitialStatesRestriction().substitute(substitution));
for (auto& edge : this->getEdges()) {
edge.substitute(substitution);
}
}
void Automaton::finalize(Model const& containingModel) {
for (auto& edge : edges) {
edge.finalize(containingModel);

33
src/storage/jani/Automaton.h

@ -108,17 +108,22 @@ namespace storm {
/*!
* Adds the given Boolean variable to this automaton.
*/
BooleanVariable const& addBooleanVariable(BooleanVariable const& variable);
BooleanVariable const& addVariable(BooleanVariable const& variable);
/*!
* Adds the given bounded integer variable to this automaton.
*/
BoundedIntegerVariable const& addBoundedIntegerVariable(BoundedIntegerVariable const& variable);
BoundedIntegerVariable const& addVariable(BoundedIntegerVariable const& variable);
/*!
* Adds the given unbounded integer variable to this automaton.
*/
UnboundedIntegerVariable const& addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable);
UnboundedIntegerVariable const& addVariable(UnboundedIntegerVariable const& variable);
/*!
* Adds the given real variable to this automaton.
*/
RealVariable const& addVariable(RealVariable const& variable);
/*!
* Retrieves the variables of this automaton.
@ -130,6 +135,11 @@ namespace storm {
*/
VariableSet const& getVariables() const;
/*!
* Retrieves whether this automaton has a transient variable.
*/
bool hasTransientVariable() const;
/*!
* Retrieves whether the automaton has a location with the given name.
*/
@ -147,12 +157,22 @@ namespace storm {
* Retrieves the locations of the automaton.
*/
std::vector<Location> const& getLocations() const;
/*!
* Retrieves the locations of the automaton.
*/
std::vector<Location>& getLocations();
/*!
* Retrieves the location with the given index.
*/
Location const& getLocation(uint64_t index) const;
/*!
* Retrieves the location with the given index.
*/
Location& getLocation(uint64_t index);
/*!
* Adds the given location to the automaton.
*/
@ -263,6 +283,11 @@ namespace storm {
*/
std::vector<storm::expressions::Expression> getAllRangeExpressions() const;
/*!
* Substitutes all variables in all expressions according to the given substitution.
*/
void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution);
/*!
* Finalizes the building of this automaton. Subsequent changes to the automaton require another call to this
* method. Note that this method is invoked by a call to <code>finalize</code> to the containing model.

9
src/storage/jani/BooleanVariable.cpp

@ -11,10 +11,17 @@ namespace storm {
// Intentionally left empty.
}
bool BooleanVariable::isBooleanVariable() const {
return true;
}
std::shared_ptr<BooleanVariable> makeBooleanVariable(std::string const& name, storm::expressions::Variable const& variable, boost::optional<storm::expressions::Expression> initValue, bool transient) {
if (initValue) {
return std::make_shared<BooleanVariable>(name, variable, initValue.get(), transient);
} else {
return std::make_shared<BooleanVariable>(name, variable, transient);
}
}
}
}

5
src/storage/jani/BooleanVariable.h

@ -21,5 +21,10 @@ namespace storm {
virtual bool isBooleanVariable() const override;
};
/**
* Convenience function to call the appropriate constructor and return a shared pointer to the variable.
*/
std::shared_ptr<BooleanVariable> makeBooleanVariable(std::string const& name, storm::expressions::Variable const& variable, boost::optional<storm::expressions::Expression> initValue, bool transient);
}
}

13
src/storage/jani/BoundedIntegerVariable.cpp

@ -21,7 +21,6 @@ namespace storm {
// Intentionally left empty.
}
storm::expressions::Expression const& BoundedIntegerVariable::getLowerBound() const {
return lowerBound;
}
@ -46,11 +45,15 @@ namespace storm {
return true;
}
void BoundedIntegerVariable::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) {
Variable::substitute(substitution);
this->setLowerBound(this->getLowerBound().substitute(substitution));
this->setUpperBound(this->getUpperBound().substitute(substitution));
}
std::shared_ptr<BoundedIntegerVariable> makeBoundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, boost::optional<storm::expressions::Expression> initValue, bool transient, boost::optional<storm::expressions::Expression> lowerBound, boost::optional<storm::expressions::Expression> upperBound) {
if(!lowerBound || !upperBound) {
STORM_LOG_THROW(lowerBound && upperBound, storm::exceptions::NotImplementedException, "Jani Bounded Integer variables (for now) have to be bounded from both sides");
}
if(initValue) {
STORM_LOG_THROW(lowerBound && upperBound, storm::exceptions::NotImplementedException, "Jani Bounded Integer variables (for now) have to be bounded from both sides");
if (initValue) {
return std::make_shared<BoundedIntegerVariable>(name, variable, initValue.get(), transient, lowerBound.get(), upperBound.get());
} else {
return std::make_shared<BoundedIntegerVariable>(name, variable, transient, lowerBound.get(), upperBound.get());

7
src/storage/jani/BoundedIntegerVariable.h

@ -52,6 +52,11 @@ namespace storm {
virtual bool isBoundedIntegerVariable() const override;
/*!
* Substitutes all variables in all expressions according to the given substitution.
*/
virtual void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) override;
private:
// The expression defining the lower bound of the variable.
storm::expressions::Expression lowerBound;
@ -61,7 +66,7 @@ namespace storm {
};
/**
* Convenience function to call the appropriate constructor and retur a shared pointer to the variable.
* Convenience function to call the appropriate constructor and return a shared pointer to the variable.
*/
std::shared_ptr<BoundedIntegerVariable> makeBoundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, boost::optional<storm::expressions::Expression> initValue, bool transient, boost::optional<storm::expressions::Expression> lowerBound, boost::optional<storm::expressions::Expression> upperBound);
}

52
src/storage/jani/Edge.cpp

@ -2,10 +2,13 @@
#include "src/storage/jani/Model.h"
#include "src/utility/macros.h"
#include "src/exceptions/InvalidArgumentException.h"
namespace storm {
namespace jani {
Edge::Edge(uint64_t sourceLocationIndex, uint64_t actionIndex, boost::optional<storm::expressions::Expression> const& rate, storm::expressions::Expression const& guard, std::vector<EdgeDestination> destinations) : sourceLocationIndex(sourceLocationIndex), actionIndex(actionIndex), rate(rate), guard(guard), destinations(destinations) {
Edge::Edge(uint64_t sourceLocationIndex, uint64_t actionIndex, boost::optional<storm::expressions::Expression> const& rate, storm::expressions::Expression const& guard, std::vector<EdgeDestination> destinations) : sourceLocationIndex(sourceLocationIndex), actionIndex(actionIndex), rate(rate), guard(guard), destinations(destinations), assignments(), writtenGlobalVariables() {
// Intentionally left empty.
}
@ -49,6 +52,23 @@ namespace storm {
destinations.push_back(destination);
}
OrderedAssignments const& Edge::getAssignments() const {
return assignments;
}
void Edge::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) {
this->setGuard(this->getGuard().substitute(substitution));
if (this->hasRate()) {
this->setRate(this->getRate().substitute(substitution));
}
for (auto& assignment : this->getAssignments()) {
assignment.substitute(substitution);
}
for (auto& destination : this->getDestinations()) {
destination.substitute(substitution);
}
}
void Edge::finalize(Model const& containingModel) {
for (auto const& destination : getDestinations()) {
for (auto const& assignment : destination.getAssignments()) {
@ -59,6 +79,36 @@ namespace storm {
}
}
bool Edge::addTransientAssignment(Assignment const& assignment) {
STORM_LOG_THROW(assignment.isTransient(), storm::exceptions::InvalidArgumentException, "Must not add non-transient assignment to location.");
return assignments.add(assignment);
}
void Edge::liftTransientDestinationAssignments() {
if (!destinations.empty()) {
auto const& destination = *destinations.begin();
for (auto const& assignment : destination.getTransientAssignments()) {
// Check if we can lift the assignment to the edge.
bool canBeLifted = true;
for (auto const& destination : destinations) {
if (!destination.hasAssignment(assignment)) {
canBeLifted = false;
break;
}
}
// If so, remove the assignment from all destinations.
if (canBeLifted) {
this->addTransientAssignment(assignment);
for (auto& destination : destinations) {
destination.removeAssignment(assignment);
}
}
}
}
}
boost::container::flat_set<storm::expressions::Variable> const& Edge::getWrittenGlobalVariables() const {
return writtenGlobalVariables;
}

28
src/storage/jani/Edge.h

@ -4,6 +4,7 @@
#include <boost/container/flat_set.hpp>
#include "src/storage/jani/EdgeDestination.h"
#include "src/storage/jani/OrderedAssignments.h"
namespace storm {
namespace jani {
@ -64,6 +65,11 @@ namespace storm {
*/
void addDestination(EdgeDestination const& destination);
/*!
* Substitutes all variables in all expressions according to the given substitution.
*/
void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution);
/*!
* Finalizes the building of this edge. Subsequent changes to the edge require another call to this
* method. Note that this method is invoked by a call to <code>finalize</code> to the containing model.
@ -75,6 +81,25 @@ namespace storm {
* that prior to calling this, the edge has to be finalized.
*/
boost::container::flat_set<storm::expressions::Variable> const& getWrittenGlobalVariables() const;
/*!
* Adds a transient assignment to this edge.
*
* @param assignment The transient assignment to add.
* @return True if the assignment was added.
*/
bool addTransientAssignment(Assignment const& assignment);
/*!
* Retrieves the assignments of this edge.
*/
OrderedAssignments const& getAssignments() const;
/*!
* Finds the transient assignments common to all destinations and lifts them to the edge. Afterwards, these
* assignments are no longer contained in the destination.
*/
void liftTransientDestinationAssignments();
private:
/// The index of the source location.
@ -93,6 +118,9 @@ namespace storm {
/// The destinations of this edge.
std::vector<EdgeDestination> destinations;
/// The assignments made when taking this edge.
OrderedAssignments assignments;
/// A set of global variables that is written by at least one of the edge's destinations. This set is
/// initialized by the call to <code>finalize</code>.
boost::container::flat_set<storm::expressions::Variable> writtenGlobalVariables;

63
src/storage/jani/EdgeDestination.cpp

@ -7,33 +7,11 @@ namespace storm {
namespace jani {
EdgeDestination::EdgeDestination(uint64_t locationIndex, storm::expressions::Expression const& probability, std::vector<Assignment> const& assignments) : locationIndex(locationIndex), probability(probability), assignments(assignments) {
for (auto const& assignment : assignments) {
if (assignment.isTransientAssignment()) {
transientAssignments.push_back(assignment);
} else {
nonTransientAssignments.push_back(assignment);
}
}
sortAssignments(this->assignments);
sortAssignments(transientAssignments);
sortAssignments(nonTransientAssignments);
// Intentionally left empty.
}
void EdgeDestination::addAssignment(Assignment const& assignment) {
// We make sure that there are no two assignments to the same variable.
for (auto const& oldAssignment : assignments) {
STORM_LOG_THROW(oldAssignment.getExpressionVariable() != assignment.getExpressionVariable(), storm::exceptions::WrongFormatException, "Cannot add assignment '" << assignment << "', because another assignment '" << assignment << "' writes to the same target variable.");
}
assignments.push_back(assignment);
sortAssignments(assignments);
if (assignment.isTransientAssignment()) {
transientAssignments.push_back(assignment);
sortAssignments(transientAssignments);
} else {
nonTransientAssignments.push_back(assignment);
sortAssignments(nonTransientAssignments);
}
assignments.add(assignment);
}
uint64_t EdgeDestination::getLocationIndex() const {
@ -48,38 +26,29 @@ namespace storm {
this->probability = probability;
}
std::vector<Assignment>& EdgeDestination::getAssignments() {
return assignments;
storm::jani::detail::ConstAssignments EdgeDestination::getAssignments() const {
return assignments.getAllAssignments();
}
std::vector<Assignment> const& EdgeDestination::getAssignments() const {
return assignments;
}
std::vector<Assignment>& EdgeDestination::getNonTransientAssignments() {
return nonTransientAssignments;
storm::jani::detail::ConstAssignments EdgeDestination::getTransientAssignments() const {
return assignments.getTransientAssignments();
}
std::vector<Assignment> const& EdgeDestination::getNonTransientAssignments() const {
return nonTransientAssignments;
storm::jani::detail::ConstAssignments EdgeDestination::getNonTransientAssignments() const {
return assignments.getNonTransientAssignments();
}
std::vector<Assignment>& EdgeDestination::getTransientAssignments() {
return transientAssignments;
void EdgeDestination::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) {
this->setProbability(this->getProbability().substitute(substitution));
assignments.substitute(substitution);
}
std::vector<Assignment> const& EdgeDestination::getTransientAssignments() const {
return transientAssignments;
bool EdgeDestination::hasAssignment(Assignment const& assignment) const {
return assignments.contains(assignment);
}
void EdgeDestination::sortAssignments(std::vector<Assignment>& assignments) {
std::sort(assignments.begin(), assignments.end(), [] (storm::jani::Assignment const& assignment1, storm::jani::Assignment const& assignment2) {
bool smaller = assignment1.getExpressionVariable().getType().isBooleanType() && !assignment2.getExpressionVariable().getType().isBooleanType();
if (!smaller) {
smaller = assignment1.getExpressionVariable() < assignment2.getExpressionVariable();
}
return smaller;
});
bool EdgeDestination::removeAssignment(Assignment const& assignment) {
return assignments.remove(assignment);
}
}

45
src/storage/jani/EdgeDestination.h

@ -4,7 +4,7 @@
#include "src/storage/expressions/Expression.h"
#include "src/storage/jani/Assignment.h"
#include "src/storage/jani/OrderedAssignments.h"
namespace storm {
namespace jani {
@ -39,55 +39,36 @@ namespace storm {
/*!
* Retrieves the assignments to make when choosing this destination.
*/
std::vector<Assignment>& getAssignments();
storm::jani::detail::ConstAssignments getAssignments() const;
/*!
* Retrieves the assignments to make when choosing this destination.
*/
std::vector<Assignment> const& getAssignments() const;
/*!
* Retrieves the non-transient assignments to make when choosing this destination.
* Retrieves the transient assignments to make when choosing this destination.
*/
std::vector<Assignment>& getNonTransientAssignments();
storm::jani::detail::ConstAssignments getTransientAssignments() const;
/*!
* Retrieves the non-transient assignments to make when choosing this destination.
*/
std::vector<Assignment> const& getNonTransientAssignments() const;
storm::jani::detail::ConstAssignments getNonTransientAssignments() const;
/*!
* Retrieves the non-transient assignments to make when choosing this destination.
* Substitutes all variables in all expressions according to the given substitution.
*/
std::vector<Assignment>& getTransientAssignments();
void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution);
/*!
* Retrieves the non-transient assignments to make when choosing this destination.
*/
std::vector<Assignment> const& getTransientAssignments() const;
private:
/*!
* Sorts the assignments to make all assignments to boolean variables precede all others and order the
* assignments within one variable group by the expression variables.
*/
static void sortAssignments(std::vector<Assignment>& assignments);
// Convenience methods to access the assignments.
bool hasAssignment(Assignment const& assignment) const;
bool removeAssignment(Assignment const& assignment);
private:
// The index of the destination location.
uint64_t locationIndex;
// The probability to go to the destination.
storm::expressions::Expression probability;
// The assignments to make when choosing this destination.
std::vector<Assignment> assignments;
// The assignments to make when choosing this destination.
std::vector<Assignment> nonTransientAssignments;
// The assignments to make when choosing this destination.
std::vector<Assignment> transientAssignments;
// The (ordered) assignments to make when choosing this destination.
OrderedAssignments assignments;
};
}

438
src/storage/jani/Exporter.cpp

@ -1,438 +0,0 @@
#include "src/storage/jani/Exporter.h"
#include <iostream>
namespace storm {
namespace jani {
void appendIndent(std::stringstream& out, uint64_t indent) {
for (uint64_t i = 0; i < indent; ++i) {
out << "\t";
}
}
void appendField(std::stringstream& out, std::string const& name) {
out << "\"" << name << "\": ";
}
void appendValue(std::stringstream& out, std::string const& value) {
out << "\"" << value << "\"";
}
void clearLine(std::stringstream& out) {
out << std::endl;
}
std::string expressionToString(storm::expressions::Expression const& expression) {
std::stringstream s;
s << expression;
return s.str();
}
void Exporter::appendVersion(std::stringstream& out, uint64_t janiVersion, uint64_t indent) const {
appendIndent(out, indent);
appendField(out, "jani-version");
}
void Exporter::appendModelName(std::stringstream& out, std::string const& name, uint64_t indent) const {
appendIndent(out, indent);
appendField(out, "name");
appendValue(out, name);
}
void Exporter::appendModelType(std::stringstream& out, storm::jani::ModelType const& modelType, uint64_t indent) const {
appendIndent(out, indent);
appendField(out, "type");
}
void Exporter::appendAction(std::stringstream& out, storm::jani::Action const& action, uint64_t indent) const {
appendIndent(out, indent);
out << "{" << std::endl;
appendIndent(out, indent + 1);
appendField(out, "name");
appendValue(out, action.getName());
clearLine(out);
appendIndent(out, indent);
out << "}";
}
void Exporter::appendActions(std::stringstream& out, storm::jani::Model const& model, uint64_t indent) const {
appendIndent(out, indent);
appendField(out, "actions");
out << " [" << std::endl;
for (uint64_t index = 0; index < model.actions.size(); ++index) {
appendAction(out, model.actions[index], indent + 1);
if (index < model.actions.size() - 1) {
out << ",";
}
clearLine(out);
}
appendIndent(out, indent);
out << "]";
}
void Exporter::appendVariable(std::stringstream& out, storm::jani::BooleanVariable const& variable, uint64_t indent) const {
appendIndent(out, indent);
out << "{";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "name");
appendValue(out, variable.getName());
out << ",";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "type");
appendValue(out, "bool");
out << ",";
clearLine(out);
appendIndent(out, indent);
out << "}";
}
void Exporter::appendBoundedIntegerVariableType(std::stringstream& out, storm::jani::BoundedIntegerVariable const& variable, uint64_t indent) const {
out << " {";
clearLine(out);
appendIndent(out, indent);
appendField(out, "kind");
appendValue(out, "bounded");
clearLine(out);
appendIndent(out, indent);
appendField(out, "base");
appendValue(out, "int");
clearLine(out);
appendIndent(out, indent);
appendField(out, "lower-bound");
appendValue(out, expressionToString(variable.getLowerBound()));
clearLine(out);
appendIndent(out, indent);
appendField(out, "upper-bound");
appendValue(out, expressionToString(variable.getLowerBound()));
clearLine(out);
appendIndent(out, indent - 1);
out << "}";
}
void Exporter::appendVariable(std::stringstream& out, storm::jani::BoundedIntegerVariable const& variable, uint64_t indent) const {
appendIndent(out, indent);
out << "{";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "name");
appendValue(out, variable.getName());
out << ",";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "type");
appendBoundedIntegerVariableType(out, variable, indent + 2);
out << ",";
clearLine(out);
appendIndent(out, indent);
out << "}";
}
void Exporter::appendVariable(std::stringstream& out, storm::jani::UnboundedIntegerVariable const& variable, uint64_t indent) const {
appendIndent(out, indent);
out << "{";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "name");
appendValue(out, variable.getName());
out << ",";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "type");
appendValue(out, "int");
out << ",";
clearLine(out);
appendIndent(out, indent);
out << "}";
}
void Exporter::appendVariables(std::stringstream& out, storm::jani::VariableSet const& variables, uint64_t indent) const {
appendIndent(out, indent);
appendField(out, "variables");
out << " [";
clearLine(out);
for (auto const& variable : variables.getBooleanVariables()) {
appendVariable(out, variable, indent + 1);
clearLine(out);
}
for (auto const& variable : variables.getBoundedIntegerVariables()) {
appendVariable(out, variable, indent + 1);
clearLine(out);
}
for (auto const& variable : variables.getUnboundedIntegerVariables()) {
appendVariable(out, variable, indent + 1);
clearLine(out);
}
appendIndent(out, indent);
out << "]";
}
void Exporter::appendLocation(std::stringstream& out, storm::jani::Location const& location, uint64_t indent) const {
appendIndent(out, indent);
out << "{";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "name");
appendValue(out, location.getName());
clearLine(out);
appendIndent(out, indent);
out << "}";
}
void Exporter::appendLocations(std::stringstream& out, storm::jani::Automaton const& automaton, uint64_t indent) const {
appendIndent(out, indent);
appendField(out, "locations");
out << " [";
clearLine(out);
for (auto const& location : automaton.getLocations()) {
appendLocation(out, location, indent + 1);
out << ",";
clearLine(out);
}
appendIndent(out, indent);
out << "]";
}
void Exporter::appendAssignment(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, storm::jani::Assignment const& assignment, uint64_t indent) const {
appendIndent(out, indent);
out << "{";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "ref");
storm::jani::Variable const& variable = model.getGlobalVariables().hasVariable(assignment.getExpressionVariable()) ? model.getGlobalVariables().getVariable(assignment.getExpressionVariable()) : automaton.getVariables().getVariable(assignment.getExpressionVariable());
appendValue(out, variable.getName());
out << ",";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "value");
appendValue(out, expressionToString(assignment.getAssignedExpression()));
clearLine(out);
appendIndent(out, indent);
out << "}";
}
void Exporter::appendEdgeDestination(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, storm::jani::EdgeDestination const& destination, uint64_t indent) const {
appendIndent(out, indent);
out << "{";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "probability");
appendValue(out, expressionToString(destination.getProbability()));
out << ",";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "location");
appendValue(out, automaton.getLocation(destination.getLocationIndex()).getName());
out << ",";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "assignments");
out << " [";
clearLine(out);
for (uint64_t index = 0; index < destination.getAssignments().size(); ++index) {
appendAssignment(out, model, automaton, destination.getAssignments()[index], indent + 2);
if (index < destination.getAssignments().size() - 1) {
out << ",";
}
clearLine(out);
}
appendIndent(out, indent + 1);
out << "]";
clearLine(out);
appendIndent(out, indent);
out << "}";
clearLine(out);
}
void Exporter::appendEdge(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, storm::jani::Edge const& edge, uint64_t indent) const {
appendIndent(out, indent);
out << "{";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "location");
appendValue(out, automaton.getLocation(edge.getSourceLocationIndex()).getName());
out << ",";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "action");
appendValue(out, model.getAction(edge.getActionIndex()).getName());
out << ",";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "guard");
appendValue(out, expressionToString(edge.getGuard()));
out << ",";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "destinations");
out << " [";
clearLine(out);
for (auto const& destination : edge.getDestinations()) {
appendEdgeDestination(out, model, automaton, destination, indent + 2);
}
appendIndent(out, indent + 1);
out << "]";
clearLine(out);
appendIndent(out, indent);
out << "}";
}
void Exporter::appendEdges(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, uint64_t indent) const {
appendIndent(out, indent);
appendField(out, "edges");
out << " [";
clearLine(out);
for (uint64_t location = 0; location < automaton.getNumberOfLocations(); ++location) {
for (auto const& edge : automaton.getEdgesFromLocation(location)) {
appendEdge(out, model, automaton, edge, indent + 1);
out << ",";
clearLine(out);
}
}
appendIndent(out, indent);
out << "]";
clearLine(out);
}
void Exporter::appendAutomaton(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, uint64_t indent) const {
appendIndent(out, indent);
out << "{";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "name");
appendValue(out, automaton.getName());
clearLine(out);
appendVariables(out, automaton.getVariables(), indent + 1);
out << ",";
clearLine(out);
appendLocations(out, automaton, indent + 1);
out << ",";
clearLine(out);
appendIndent(out, indent + 1);
appendField(out, "initial-locations");
out << " [";
clearLine(out);
for (auto const& index : automaton.getInitialLocationIndices()) {
appendIndent(out, indent + 2);
appendValue(out, automaton.getLocation(index).getName());
clearLine(out);
}
appendIndent(out, indent + 1);
out << "]";
clearLine(out);
if (automaton.hasInitialStatesRestriction()) {
appendIndent(out, indent + 1);
appendField(out, "initial-states");
clearLine(out);
appendIndent(out, indent + 2);
out << "{";
clearLine(out);
appendIndent(out, indent + 3);
appendField(out, "exp");
appendValue(out, expressionToString(automaton.getInitialStatesExpression()));
clearLine(out);
appendIndent(out, indent + 2);
out << "}";
clearLine(out);
}
appendEdges(out, model, automaton, indent + 1);
appendIndent(out, indent);
out << "}";
}
void Exporter::appendAutomata(std::stringstream& out, storm::jani::Model const& model, uint64_t indent) const {
appendIndent(out, indent);
appendField(out, "automata");
out << " [";
clearLine(out);
for (uint64_t index = 0; index < model.automata.size(); ++index) {
appendAutomaton(out, model, model.automata[index], indent + 1);
if (index < model.automata.size() - 1) {
out << ",";
}
clearLine(out);
}
appendIndent(out, indent);
out << "]";
}
std::string Exporter::toJaniString(storm::jani::Model const& model) const {
std::stringstream out;
out << "{" << std::endl;
appendVersion(out, model.getJaniVersion(), 1);
out << ",";
clearLine(out);
appendModelName(out, model.getName(), 1);
out << ",";
clearLine(out);
appendModelType(out, model.getModelType(), 1);
out << ",";
clearLine(out);
appendActions(out, model, 1);
clearLine(out);
appendVariables(out, model.getGlobalVariables(), 1);
clearLine(out);
appendIndent(out, 1);
appendField(out, "initial-states");
clearLine(out);
appendIndent(out, 2);
out << "{";
clearLine(out);
appendIndent(out, 3);
appendField(out, "exp");
appendValue(out, expressionToString(model.getInitialStatesRestriction()));
clearLine(out);
appendIndent(out, 2);
out << "}";
clearLine(out);
appendAutomata(out, model, 1);
clearLine(out);
out << "}" << std::endl;
return out.str();
}
}
}

48
src/storage/jani/Exporter.h

@ -1,48 +0,0 @@
#pragma once
#include <sstream>
#include <cstdint>
#include "src/storage/jani/Model.h"
namespace storm {
namespace jani {
class Exporter {
public:
Exporter() = default;
std::string toJaniString(storm::jani::Model const& model) const;
private:
void appendVersion(std::stringstream& out, uint64_t janiVersion, uint64_t indent) const;
void appendModelName(std::stringstream& out, std::string const& name, uint64_t indent) const;
void appendModelType(std::stringstream& out, storm::jani::ModelType const& modelType, uint64_t indent) const;
void appendAction(std::stringstream& out, storm::jani::Action const& action, uint64_t indent) const;
void appendActions(std::stringstream& out, storm::jani::Model const& model, uint64_t indent) const;
void appendVariables(std::stringstream& out, storm::jani::VariableSet const& variables, uint64_t indent) const;
void appendVariable(std::stringstream& out, storm::jani::BooleanVariable const& variable, uint64_t indent) const;
void appendVariable(std::stringstream& out, storm::jani::BoundedIntegerVariable const& variable, uint64_t indent) const;
void appendBoundedIntegerVariableType(std::stringstream& out, storm::jani::BoundedIntegerVariable const& variable, uint64_t indent) const;
void appendVariable(std::stringstream& out, storm::jani::UnboundedIntegerVariable const& variable, uint64_t indent) const;
void appendAutomata(std::stringstream& out, storm::jani::Model const& model, uint64_t indent) const;
void appendAutomaton(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, uint64_t indent) const;
void appendLocation(std::stringstream& out, storm::jani::Location const& location, uint64_t indent) const;
void appendLocations(std::stringstream& out, storm::jani::Automaton const& automaton, uint64_t indent) const;
void appendAssignment(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, storm::jani::Assignment const& assignment, uint64_t indent) const;
void appendEdgeDestination(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, storm::jani::EdgeDestination const& destination, uint64_t indent) const;
void appendEdge(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, storm::jani::Edge const& edge, uint64_t indent) const;
void appendEdges(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, uint64_t indent) const;
};
}
}

26
src/storage/jani/Location.cpp

@ -1,12 +1,13 @@
#include "src/storage/jani/Location.h"
#include "src/storage/jani/Assignment.h"
#include "src/exceptions/InvalidJaniException.h"
#include "src/utility/macros.h"
#include "src/exceptions/InvalidJaniException.h"
#include "src/exceptions/InvalidArgumentException.h"
namespace storm {
namespace jani {
Location::Location(std::string const& name, std::vector<Assignment> const& transientAssignments) : name(name), transientAssignments(transientAssignments) {
Location::Location(std::string const& name, std::vector<Assignment> const& transientAssignments) : name(name), assignments(transientAssignments) {
// Intentionally left empty.
}
@ -14,15 +15,24 @@ namespace storm {
return name;
}
std::vector<Assignment> const& Location::getTransientAssignments() const {
return transientAssignments;
OrderedAssignments const& Location::getAssignments() const {
return assignments;
}
void Location::checkValid() const {
for(auto const& assignment : transientAssignments) {
STORM_LOG_THROW(assignment.isTransientAssignment(), storm::exceptions::InvalidJaniException, "Only transient assignments are allowed in locations.");
void Location::addTransientAssignment(storm::jani::Assignment const& assignment) {
STORM_LOG_THROW(assignment.isTransient(), storm::exceptions::InvalidArgumentException, "Must not add non-transient assignment to location.");
assignments.add(assignment);
}
void Location::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) {
for (auto& assignment : assignments) {
assignment.substitute(substitution);
}
}
void Location::checkValid() const {
// Intentionally left empty.
}
}
}

20
src/storage/jani/Location.h

@ -1,8 +1,8 @@
#pragma once
#include <string>
#include <vector>
#include "src/storage/jani/Assignment.h"
#include "src/storage/jani/OrderedAssignments.h"
namespace storm {
namespace jani {
@ -25,9 +25,19 @@ namespace storm {
std::string const& getName() const;
/*!
* Retrieves the transient assignments of this location.
* Retrieves the assignments of this location.
*/
OrderedAssignments const& getAssignments() const;
/*!
* Adds the given transient assignment to this location.
*/
void addTransientAssignment(storm::jani::Assignment const& assignment);
/*!
* Substitutes all variables in all expressions according to the given substitution.
*/
std::vector<Assignment> const& getTransientAssignments() const;
void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution);
/*!
* Checks whether the location is valid, that is, whether the assignments are indeed all transient assignments.
@ -39,7 +49,7 @@ namespace storm {
std::string name;
/// The transient assignments made in this location.
std::vector<Assignment> transientAssignments;
OrderedAssignments assignments;
};
}

78
src/storage/jani/Model.cpp

@ -34,6 +34,10 @@ namespace storm {
silentActionIndex = addAction(storm::jani::Action(SILENT_ACTION_NAME));
}
storm::expressions::ExpressionManager& Model::getManager() const {
return *expressionManager;
}
uint64_t Model::getJaniVersion() const {
return version;
}
@ -104,29 +108,35 @@ namespace storm {
std::vector<Constant>& Model::getConstants() {
return constants;
}
Variable const& Model::addVariable(Variable const& variable) {
if (variable.isBooleanVariable()) {
return addBooleanVariable(variable.asBooleanVariable());
return addVariable(variable.asBooleanVariable());
} else if (variable.isBoundedIntegerVariable()) {
return addBoundedIntegerVariable(variable.asBoundedIntegerVariable());
return addVariable(variable.asBoundedIntegerVariable());
} else if (variable.isUnboundedIntegerVariable()) {
return addUnboundedIntegerVariable(variable.asUnboundedIntegerVariable());
return addVariable(variable.asUnboundedIntegerVariable());
} else if (variable.isRealVariable()) {
return addVariable(variable.asRealVariable());
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Variable has invalid type.");
}
}
BooleanVariable const& Model::addBooleanVariable(BooleanVariable const& variable) {
return globalVariables.addBooleanVariable(variable);
BooleanVariable const& Model::addVariable(BooleanVariable const& variable) {
return globalVariables.addVariable(variable);
}
BoundedIntegerVariable const& Model::addBoundedIntegerVariable(BoundedIntegerVariable const& variable) {
return globalVariables.addBoundedIntegerVariable(variable);
BoundedIntegerVariable const& Model::addVariable(BoundedIntegerVariable const& variable) {
return globalVariables.addVariable(variable);
}
UnboundedIntegerVariable const& Model::addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable) {
return globalVariables.addUnboundedIntegerVariable(variable);
UnboundedIntegerVariable const& Model::addVariable(UnboundedIntegerVariable const& variable) {
return globalVariables.addVariable(variable);
}
RealVariable const& Model::addVariable(RealVariable const& variable) {
return globalVariables.addVariable(variable);
}
VariableSet& Model::getGlobalVariables() {
@ -137,6 +147,23 @@ namespace storm {
return globalVariables;
}
bool Model::hasGlobalVariable(std::string const& name) const {
return globalVariables.hasVariable(name);
}
Variable const& Model::getGlobalVariable(std::string const& name) const {
return globalVariables.getVariable(name);
}
bool Model::hasNonGlobalTransientVariable() const {
for (auto const& automaton : automata) {
if (automaton.hasTransientVariable()) {
return true;
}
}
return false;
}
storm::expressions::ExpressionManager& Model::getExpressionManager() {
return *expressionManager;
}
@ -173,6 +200,12 @@ namespace storm {
return automata[it->second];
}
uint64_t Model::getAutomatonIndex(std::string const& name) const {
auto it = automatonToIndex.find(name);
STORM_LOG_THROW(it != automatonToIndex.end(), storm::exceptions::InvalidOperationException, "Unable to retrieve unknown automaton '" << name << "'.");
return it->second;
}
std::size_t Model::getNumberOfAutomata() const {
return automata.size();
}
@ -304,9 +337,7 @@ namespace storm {
// Substitute constants in all global variables.
for (auto& variable : result.getGlobalVariables().getBoundedIntegerVariables()) {
variable.setInitExpression(variable.getInitExpression().substitute(constantSubstitution));
variable.setLowerBound(variable.getLowerBound().substitute(constantSubstitution));
variable.setUpperBound(variable.getUpperBound().substitute(constantSubstitution));
variable.substitute(constantSubstitution);
}
// Substitute constants in initial states expression.
@ -314,26 +345,7 @@ namespace storm {
// Substitute constants in variables of automata and their edges.
for (auto& automaton : result.getAutomata()) {
for (auto& variable : automaton.getVariables().getBoundedIntegerVariables()) {
variable.setInitExpression(variable.getInitExpression().substitute(constantSubstitution));
variable.setLowerBound(variable.getLowerBound().substitute(constantSubstitution));
variable.setUpperBound(variable.getUpperBound().substitute(constantSubstitution));
}
automaton.setInitialStatesRestriction(automaton.getInitialStatesExpression().substitute(constantSubstitution));
for (auto& edge : automaton.getEdges()) {
edge.setGuard(edge.getGuard().substitute(constantSubstitution));
if (edge.hasRate()) {
edge.setRate(edge.getRate().substitute(constantSubstitution));
}
for (auto& destination : edge.getDestinations()) {
destination.setProbability(destination.getProbability().substitute(constantSubstitution));
for (auto& assignment : destination.getAssignments()) {
assignment.setAssignedExpression(assignment.getAssignedExpression().substitute(constantSubstitution));
}
}
}
automaton.substitute(constantSubstitution);
}
return result;

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

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