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 "four" = s=7&d=4;
label "five" = s=7&d=5; label "five" = s=7&d=5;
label "six" = s=7&d=6; 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 LOG_INSTALL ON
) )
add_dependencies(resources xercesc) add_dependencies(resources carl)
include_directories(${STORM_3RDPARTY_BINARY_DIR}/carl/include) include_directories(${STORM_3RDPARTY_BINARY_DIR}/carl/include)
list(APPEND STORM_LINK_LIBRARIES ${STORM_3RDPARTY_BINARY_DIR}/carl/lib/libcarl${DYNAMIC_EXT}) list(APPEND STORM_LINK_LIBRARIES ${STORM_3RDPARTY_BINARY_DIR}/carl/lib/libcarl${DYNAMIC_EXT})
set(STORM_HAVE_CARL ON) set(STORM_HAVE_CARL ON)

56
src/adapters/AddExpressionAdapter.cpp

@ -19,37 +19,37 @@ namespace storm {
template<storm::dd::DdType Type, typename ValueType> template<storm::dd::DdType Type, typename ValueType>
storm::dd::Add<Type, ValueType> AddExpressionAdapter<Type, ValueType>::translateExpression(storm::expressions::Expression const& expression) { storm::dd::Add<Type, ValueType> AddExpressionAdapter<Type, ValueType>::translateExpression(storm::expressions::Expression const& expression) {
if (expression.hasBooleanType()) { 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 { } 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> template<storm::dd::DdType Type, typename ValueType>
storm::dd::Bdd<Type> AddExpressionAdapter<Type, ValueType>::translateBooleanExpression(storm::expressions::Expression const& expression) { 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."); 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> 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()) { if (expression.hasBooleanType()) {
storm::dd::Bdd<Type> elseDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getElseExpression()->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)); 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)); storm::dd::Bdd<Type> conditionDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getCondition()->accept(*this, data));
return conditionDd.ite(thenDd, elseDd); return conditionDd.ite(thenDd, elseDd);
} else { } else {
storm::dd::Add<Type, ValueType> elseDd = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getElseExpression()->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)); 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)); storm::dd::Bdd<Type> conditionDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getCondition()->accept(*this, data));
return conditionDd.ite(thenDd, elseDd); return conditionDd.ite(thenDd, elseDd);
} }
} }
template<storm::dd::DdType Type, typename ValueType> template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression) { 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)); 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)); storm::dd::Bdd<Type> rightResult = boost::any_cast<storm::dd::Bdd<Type>>(expression.getSecondOperand()->accept(*this, data));
storm::dd::Bdd<Type> result; storm::dd::Bdd<Type> result;
switch (expression.getOperatorType()) { switch (expression.getOperatorType()) {
@ -74,9 +74,9 @@ namespace storm {
} }
template<storm::dd::DdType Type, typename ValueType> template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression) { 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)); 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)); 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; storm::dd::Add<Type, ValueType> result;
switch (expression.getOperatorType()) { switch (expression.getOperatorType()) {
@ -109,9 +109,9 @@ namespace storm {
} }
template<storm::dd::DdType Type, typename ValueType> template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryRelationExpression const& expression) { 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)); 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)); storm::dd::Add<Type, ValueType> rightResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getSecondOperand()->accept(*this, data));
storm::dd::Bdd<Type> result; storm::dd::Bdd<Type> result;
switch (expression.getRelationType()) { switch (expression.getRelationType()) {
@ -139,7 +139,7 @@ namespace storm {
} }
template<storm::dd::DdType Type, typename ValueType> 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()); 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."); 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()) { if (expression.hasBooleanType()) {
@ -150,8 +150,8 @@ namespace storm {
} }
template<storm::dd::DdType Type, typename ValueType> template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression) { 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)); storm::dd::Bdd<Type> result = boost::any_cast<storm::dd::Bdd<Type>>(expression.getOperand()->accept(*this, data));
switch (expression.getOperatorType()) { switch (expression.getOperatorType()) {
case storm::expressions::UnaryBooleanFunctionExpression::OperatorType::Not: case storm::expressions::UnaryBooleanFunctionExpression::OperatorType::Not:
@ -163,8 +163,8 @@ namespace storm {
} }
template<storm::dd::DdType Type, typename ValueType> template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression) { 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)); storm::dd::Add<Type, ValueType> result = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getOperand()->accept(*this, data));
switch (expression.getOperatorType()) { switch (expression.getOperatorType()) {
case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Minus: case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Minus:
@ -184,18 +184,18 @@ namespace storm {
} }
template<storm::dd::DdType Type, typename ValueType> 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(); return expression.getValue() ? ddManager->getBddOne() : ddManager->getBddZero();
} }
template<storm::dd::DdType Type, typename ValueType> 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())); return ddManager->getConstant(static_cast<ValueType>(expression.getValue()));
} }
template<storm::dd::DdType Type, typename ValueType> template<storm::dd::DdType Type, typename ValueType>
boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::DoubleLiteralExpression const& expression) { boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) {
return ddManager->getConstant(static_cast<ValueType>(expression.getValue())); return ddManager->getConstant(static_cast<ValueType>(expression.getValueAsDouble()));
} }
// Explicitly instantiate the symbolic expression adapter // 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::Add<Type, ValueType> translateExpression(storm::expressions::Expression const& expression);
storm::dd::Bdd<Type> translateBooleanExpression(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::IfThenElseExpression const& expression, boost::any const& data) override;
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::VariableExpression const& expression) override; virtual boost::any visit(storm::expressions::VariableExpression 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::BooleanLiteralExpression const& expression) override; virtual boost::any visit(storm::expressions::BooleanLiteralExpression 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::DoubleLiteralExpression const& expression) override; virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) override;
private: private:
// The manager responsible for the DDs built by this adapter. // 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. * @return An equivalent term for MathSAT.
*/ */
msat_term translateExpression(storm::expressions::Expression const& expression) { 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."); STORM_LOG_THROW(!MSAT_ERROR_TERM(result), storm::exceptions::ExpressionEvaluationException, "Could not translate expression to MathSAT's format.");
return result; return result;
} }
@ -90,9 +90,9 @@ namespace storm {
return declarationVariablePair->second; return declarationVariablePair->second;
} }
virtual boost::any visit(expressions::BinaryBooleanFunctionExpression const& expression) override { 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)); 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)); msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data));
switch (expression.getOperatorType()) { switch (expression.getOperatorType()) {
case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::And: case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::And:
@ -108,9 +108,9 @@ namespace storm {
} }
} }
virtual boost::any visit(expressions::BinaryNumericalFunctionExpression const& expression) override { 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)); 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)); msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data));
switch (expression.getOperatorType()) { switch (expression.getOperatorType()) {
case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Plus: case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Plus:
@ -130,9 +130,9 @@ namespace storm {
} }
} }
virtual boost::any visit(expressions::BinaryRelationExpression const& expression) override { 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)); 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)); msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data));
switch (expression.getRelationType()) { switch (expression.getRelationType()) {
case storm::expressions::BinaryRelationExpression::RelationType::Equal: case storm::expressions::BinaryRelationExpression::RelationType::Equal:
@ -160,27 +160,27 @@ namespace storm {
} }
} }
virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression) override { 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)); 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)); 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)); msat_term elseResult = boost::any_cast<msat_term>(expression.getElseExpression()->accept(*this, data));
return msat_make_term_ite(env, conditionResult, thenResult, elseResult); 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); return expression.getValue() ? msat_make_true(env) : msat_make_false(env);
} }
virtual boost::any visit(expressions::DoubleLiteralExpression const& expression) override { virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) override {
return msat_make_number(env, std::to_string(expression.getValue()).c_str()); 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()); return msat_make_number(env, std::to_string(static_cast<int>(expression.getValue())).c_str());
} }
virtual boost::any visit(expressions::UnaryBooleanFunctionExpression const& expression) override { 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)); msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this, data));
switch (expression.getOperatorType()) { switch (expression.getOperatorType()) {
case storm::expressions::UnaryBooleanFunctionExpression::OperatorType::Not: case storm::expressions::UnaryBooleanFunctionExpression::OperatorType::Not:
@ -191,8 +191,8 @@ namespace storm {
} }
} }
virtual boost::any visit(expressions::UnaryNumericalFunctionExpression const& expression) override { 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)); msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this, data));
switch (expression.getOperatorType()) { switch (expression.getOperatorType()) {
case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Minus: 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()); return translateExpression(expression.getVariable());
} }

46
src/adapters/Z3ExpressionAdapter.cpp

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

286
src/builder/DdJaniModelBuilder.cpp

@ -103,19 +103,13 @@ namespace storm {
} }
template <storm::dd::DdType Type, typename ValueType> template <storm::dd::DdType Type, typename ValueType>
DdJaniModelBuilder<Type, ValueType>::DdJaniModelBuilder(storm::jani::Model const& model, Options const& options) : model(model), options(options) { std::set<std::string> const& DdJaniModelBuilder<Type, ValueType>::Options::getRewardModelNames() const {
if (this->model->hasUndefinedConstants()) { return rewardModelsToBuild;
std::vector<std::reference_wrapper<storm::jani::Constant const>> undefinedConstants = this->model->getUndefinedConstants(); }
std::vector<std::string> strings; template <storm::dd::DdType Type, typename ValueType>
for (auto const& constant : undefinedConstants) { bool DdJaniModelBuilder<Type, ValueType>::Options::isBuildAllRewardModelsSet() const {
std::stringstream stream; return buildAllRewardModels;
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();
} }
template <storm::dd::DdType Type, typename ValueType> template <storm::dd::DdType Type, typename ValueType>
@ -188,11 +182,15 @@ namespace storm {
this->model.getSystemComposition().accept(*this, boost::none); 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."); 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."); 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()) { 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(!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. // Based on this assumption, we create the variables.
return createVariables(); return createVariables();
@ -243,6 +241,7 @@ namespace storm {
// Start by creating a meta variable for the location of the automaton. // 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); 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.automatonToLocationVariableMap[automaton.getName()] = variablePair;
result.rowColumnMetaVariablePairs.push_back(variablePair);
// Add the location variable to the row/column variables. // Add the location variable to the row/column variables.
result.rowMetaVariables.insert(variablePair.first); result.rowMetaVariables.insert(variablePair.first);
@ -256,6 +255,11 @@ namespace storm {
// Create global variables. // Create global variables.
storm::dd::Bdd<Type> globalVariableRanges = result.manager->getBddOne(); storm::dd::Bdd<Type> globalVariableRanges = result.manager->getBddOne();
for (auto const& variable : this->model.getGlobalVariables()) { for (auto const& variable : this->model.getGlobalVariables()) {
// Only create the variable if it's non-transient.
if (variable.isTransient()) {
continue;
}
createVariable(variable, result); createVariable(variable, result);
globalVariableRanges &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable())); globalVariableRanges &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable()));
} }
@ -274,6 +278,11 @@ namespace storm {
// Then create variables for the variables of the automaton. // Then create variables for the variables of the automaton.
for (auto const& variable : automaton.getVariables()) { for (auto const& variable : automaton.getVariables()) {
// Only create the variable if it's non-transient.
if (variable.isTransient()) {
continue;
}
createVariable(variable, result); createVariable(variable, result);
identity &= result.variableToIdentityMap.at(variable.getExpressionVariable()).toBdd(); identity &= result.variableToIdentityMap.at(variable.getExpressionVariable()).toBdd();
range &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable())); range &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable()));
@ -345,11 +354,13 @@ namespace storm {
template <storm::dd::DdType Type, typename ValueType> template <storm::dd::DdType Type, typename ValueType>
struct ComposerResult { 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. // Intentionally left empty.
} }
storm::dd::Add<Type, ValueType> transitions; 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; storm::dd::Bdd<Type> illegalFragment;
uint64_t numberOfNondeterminismVariables; uint64_t numberOfNondeterminismVariables;
}; };
@ -358,7 +369,7 @@ namespace storm {
template <storm::dd::DdType Type, typename ValueType> template <storm::dd::DdType Type, typename ValueType>
class SystemComposer : public storm::jani::CompositionVisitor { class SystemComposer : public storm::jani::CompositionVisitor {
public: 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. // Intentionally left empty.
} }
@ -370,6 +381,9 @@ namespace storm {
// The variable to use when building an automaton. // The variable to use when building an automaton.
CompositionVariables<Type, ValueType> const& variables; 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. // 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. // Iterate over all assignments (boolean and integer) and build the DD for it.
std::set<storm::expressions::Variable> assignedVariables; std::set<storm::expressions::Variable> assignedVariables;
for (auto const& assignment : destination.getAssignments()) { for (auto const& assignment : destination.getNonTransientAssignments()) {
// Record the variable as being written. // Record the variable as being written.
STORM_LOG_TRACE("Assigning to variable " << variables.variableToRowMetaVariableMap->at(assignment.getExpressionVariable()).getName()); STORM_LOG_TRACE("Assigning to variable " << variables.variableToRowMetaVariableMap->at(assignment.getExpressionVariable()).getName());
assignedVariables.insert(assignment.getExpressionVariable()); assignedVariables.insert(assignment.getExpressionVariable());
@ -908,7 +922,7 @@ namespace storm {
public: public:
// This structure represents an edge. // This structure represents an edge.
struct EdgeDd { 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. // Intentionally left empty.
} }
@ -918,13 +932,16 @@ namespace storm {
// A DD that represents the transitions of this edge. // A DD that represents the transitions of this edge.
storm::dd::Add<Type, ValueType> transitions; 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. // The set of global variables written by this edge.
std::set<storm::expressions::Variable> writtenGlobalVariables; std::set<storm::expressions::Variable> writtenGlobalVariables;
}; };
// This structure represents an edge. // This structure represents an edge.
struct ActionDd { 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. // Intentionally left empty.
} }
@ -946,6 +963,9 @@ namespace storm {
// A DD that represents the transitions of this edge. // A DD that represents the transitions of this edge.
storm::dd::Add<Type, ValueType> transitions; 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 // The local nondeterminism variables used by this action DD, given as the lowest
std::pair<uint64_t, uint64_t> localNondeterminismVariables; std::pair<uint64_t, uint64_t> localNondeterminismVariables;
@ -960,7 +980,7 @@ namespace storm {
// This structure represents a subcomponent of a composition. // This structure represents a subcomponent of a composition.
struct AutomatonDd { 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. // Intentionally left empty.
} }
@ -988,6 +1008,9 @@ namespace storm {
// A mapping from action indices to the action DDs. // A mapping from action indices to the action DDs.
std::map<uint64_t, ActionDd> actionIndexToAction; 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. // The identity of the automaton's variables.
storm::dd::Add<Type, ValueType> identity; 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. // Intentionally left empty.
} }
@ -1080,6 +1103,7 @@ namespace storm {
private: private:
AutomatonDd composeInParallel(AutomatonDd const& automaton1, AutomatonDd const& automaton2, std::set<uint64_t> const& synchronizingActionIndices) { AutomatonDd composeInParallel(AutomatonDd const& automaton1, AutomatonDd const& automaton2, std::set<uint64_t> const& synchronizingActionIndices) {
AutomatonDd result(automaton1); AutomatonDd result(automaton1);
result.transientLocationAssignments = joinTransientAssignmentMaps(automaton1.transientLocationAssignments, automaton2.transientLocationAssignments);
// Treat all actions of the first automaton. // Treat all actions of the first automaton.
for (auto const& action1 : automaton1.actionIndexToAction) { for (auto const& action1 : automaton1.actionIndexToAction) {
@ -1103,7 +1127,7 @@ namespace storm {
} else { } else {
// If only the first automaton has this action, we only need to apply the identity of the // If only the first automaton has this action, we only need to apply the identity of the
// second automaton. // 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 (synchronizingActionIndices.find(action2.first) == synchronizingActionIndices.end()) {
// If only the second automaton has this action, we only need to apply the identity of the // If only the second automaton has this action, we only need to apply the identity of the
// first automaton. // 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) { 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."); STORM_LOG_TRACE("Combining unsynchronized actions.");
if (this->model.getModelType() == storm::jani::ModelType::DTMC || this->model.getModelType() == storm::jani::ModelType::CTMC) { 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) { } else if (this->model.getModelType() == storm::jani::ModelType::MDP) {
if (action1.transitions.isZero()) { if (action1.transitions.isZero()) {
return action2; return action2;
@ -1178,7 +1202,7 @@ namespace storm {
} }
// Bring both choices to the same number of variables that encode the nondeterminism. // 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()); uint_fast64_t highestLocalNondeterminismVariable = std::max(action1.getHighestLocalNondeterminismVariable(), action2.getHighestLocalNondeterminismVariable());
if (action1.getHighestLocalNondeterminismVariable() > action2.getHighestLocalNondeterminismVariable()) { if (action1.getHighestLocalNondeterminismVariable() > action2.getHighestLocalNondeterminismVariable()) {
storm::dd::Add<Type, ValueType> nondeterminismEncoding = this->variables.manager->template getAddOne<ValueType>(); 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>(); nondeterminismEncoding *= this->variables.manager->getEncoding(this->variables.localNondeterminismVariables[i], 0).template toAdd<ValueType>();
} }
action2.transitions *= nondeterminismEncoding; action2.transitions *= nondeterminismEncoding;
for (auto& transientAssignment : action2.transientEdgeAssignments) {
transientAssignment.second *= nondeterminismEncoding;
}
} else if (action2.getHighestLocalNondeterminismVariable() > action1.getHighestLocalNondeterminismVariable()) { } else if (action2.getHighestLocalNondeterminismVariable() > action1.getHighestLocalNondeterminismVariable()) {
storm::dd::Add<Type, ValueType> nondeterminismEncoding = this->variables.manager->template getAddOne<ValueType>(); 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>(); nondeterminismEncoding *= this->variables.manager->getEncoding(this->variables.localNondeterminismVariables[i], 0).template toAdd<ValueType>();
} }
action1.transitions *= nondeterminismEncoding; action1.transitions *= nondeterminismEncoding;
for (auto& transientAssignment : action1.transientEdgeAssignments) {
transientAssignment.second *= nondeterminismEncoding;
}
} }
// Add a new variable that resolves the nondeterminism between the two choices. // 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; 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 { } else {
STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Illegal model type."); STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Illegal model type.");
} }
} }
AutomatonDd rename(AutomatonDd const& automaton, std::map<uint64_t, uint64_t> const& indexToIndex) { 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) { for (auto const& action : automaton.actionIndexToAction) {
auto renamingIt = indexToIndex.find(action.first); auto renamingIt = indexToIndex.find(action.first);
@ -1244,6 +1276,23 @@ namespace storm {
return result; 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) { EdgeDd buildEdgeDd(storm::jani::Automaton const& automaton, storm::jani::Edge const& edge) {
STORM_LOG_TRACE("Translating guard " << edge.getGuard()); STORM_LOG_TRACE("Translating guard " << edge.getGuard());
@ -1309,7 +1358,13 @@ namespace storm {
transitions *= this->variables.rowExpressionAdapter->translateExpression(edge.getRate()); 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 { } else {
return EdgeDd(this->variables.manager->template getAddZero<ValueType>(), this->variables.manager->template getAddZero<ValueType>()); 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."); STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot translate model of this type.");
} }
} else { } 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) { ActionDd combineEdgesToActionMarkovChain(std::vector<EdgeDd> const& edgeDds) {
storm::dd::Bdd<Type> allGuards = this->variables.manager->getBddZero(); storm::dd::Bdd<Type> allGuards = this->variables.manager->getBddZero();
storm::dd::Add<Type, ValueType> allTransitions = this->variables.manager->template getAddZero<ValueType>(); storm::dd::Add<Type, ValueType> allTransitions = this->variables.manager->template getAddZero<ValueType>();
storm::dd::Bdd<Type> temporary; storm::dd::Bdd<Type> temporary;
std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment; 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) { for (auto const& edgeDd : edgeDds) {
// Check for overlapping guards. // Check for overlapping guards.
storm::dd::Bdd<Type> guardBdd = edgeDd.guard.toBdd(); storm::dd::Bdd<Type> guardBdd = edgeDd.guard.toBdd();
@ -1360,6 +1451,9 @@ namespace storm {
allGuards |= guardBdd; allGuards |= guardBdd;
allTransitions += edgeDd.transitions; 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. // Keep track of the fragment that is writing global variables.
for (auto const& variable : edgeDd.writtenGlobalVariables) { for (auto const& variable : edgeDd.writtenGlobalVariables) {
auto it = globalVariableToWritingFragment.find(variable); 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 { 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) { 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>(); 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::Bdd<Type>> globalVariableToWritingFragment;
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
for (auto const& edge : edges) { for (auto const& edge : edges) {
transitions += edge.transitions; transitions += edge.transitions;
addToTransientAssignmentMap(transientEdgeAssignments, edge.transientEdgeAssignments);
for (auto const& variable : edge.writtenGlobalVariables) { for (auto const& variable : edge.writtenGlobalVariables) {
addToVariableWritingFragmentMap(globalVariableToWritingFragment, variable, edge.guard.toBdd()); 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) { 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>(); 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::Bdd<Type>> globalVariableToWritingFragment;
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientAssignments;
storm::dd::Bdd<Type> equalsNumberOfChoicesDd; storm::dd::Bdd<Type> equalsNumberOfChoicesDd;
std::vector<storm::dd::Add<Type, ValueType>> choiceDds(maxChoices, this->variables.manager->template getAddZero<ValueType>()); 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. // 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; 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. // Keep track of the written global variables of the fragment.
for (auto const& variable : currentEdge.writtenGlobalVariables) { for (auto const& variable : currentEdge.writtenGlobalVariables) {
addToVariableWritingFragmentMap(globalVariableToWritingFragment, variable, remainingGuardChoicesIntersection && indicesEncodedWithLocalNondeterminismVariables[k].first); addToVariableWritingFragmentMap(globalVariableToWritingFragment, variable, remainingGuardChoicesIntersection && indicesEncodedWithLocalNondeterminismVariables[k].first);
@ -1505,7 +1607,7 @@ namespace storm {
sumOfGuards = sumOfGuards * (!equalsNumberOfChoicesDd).template toAdd<ValueType>(); 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.setLowestLocalNondeterminismVariable(std::max(result.getLowestLocalNondeterminismVariable(), actionDd.getLowestLocalNondeterminismVariable()));
result.setHighestLocalNondeterminismVariable(std::max(result.getHighestLocalNondeterminismVariable(), actionDd.getHighestLocalNondeterminismVariable())); 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; return result;
} }
@ -1553,28 +1669,36 @@ namespace storm {
uint64_t numberOfUsedNondeterminismVariables = automaton.getHighestLocalNondeterminismVariable(); uint64_t numberOfUsedNondeterminismVariables = automaton.getHighestLocalNondeterminismVariable();
// Add missing global variable identities, action and nondeterminism encodings. // 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) { for (auto& action : automaton.actionIndexToAction) {
illegalFragment |= action.second.illegalFragment; illegalFragment |= action.second.illegalFragment;
addMissingGlobalVariableIdentities(action.second); 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> 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> missingNondeterminismEncoding = encodeIndex(0, action.second.getHighestLocalNondeterminismVariable(), numberOfUsedNondeterminismVariables - action.second.getHighestLocalNondeterminismVariable(), this->variables);
storm::dd::Add<Type, ValueType> extendedTransitions = actionEncoding * missingNondeterminismEncoding * action.second.transitions; 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; 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) { } 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. // 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::Add<Type, ValueType> result = this->variables.manager->template getAddZero<ValueType>();
storm::dd::Bdd<Type> illegalFragment = this->variables.manager->getBddZero(); 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) { for (auto& action : automaton.actionIndexToAction) {
illegalFragment |= action.second.illegalFragment; illegalFragment |= action.second.illegalFragment;
addMissingGlobalVariableIdentities(action.second); addMissingGlobalVariableIdentities(action.second);
addToTransientAssignmentMap(transientEdgeAssignments, action.second.transientEdgeAssignments);
result += action.second.transitions; result += action.second.transitions;
} }
return ComposerResult<Type, ValueType>(result, illegalFragment, 0); return ComposerResult<Type, ValueType>(result, automaton.transientLocationAssignments, transientEdgeAssignments, illegalFragment, 0);
} else { } else {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Illegal model type."); STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Illegal model type.");
} }
@ -1718,31 +1842,100 @@ namespace storm {
} }
template <storm::dd::DdType Type, typename ValueType> 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. // Create all necessary variables.
CompositionVariableCreator<Type, ValueType> variableCreator(*this->model); CompositionVariableCreator<Type, ValueType> variableCreator(model);
CompositionVariables<Type, ValueType> variables = variableCreator.create(); 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. // Create a builder to compose and build the model.
// SeparateEdgesSystemComposer<Type, ValueType> composer(*this->model, variables); // SeparateEdgesSystemComposer<Type, ValueType> composer(model, variables);
CombinedEdgesSystemComposer<Type, ValueType> composer(*this->model, variables); CombinedEdgesSystemComposer<Type, ValueType> composer(model, variables, rewardVariables);
ComposerResult<Type, ValueType> system = composer.compose(); ComposerResult<Type, ValueType> system = composer.compose();
// Postprocess the variables in place. // 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). // 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. // Start creating the model components.
ModelComponents<Type, ValueType> modelComponents; ModelComponents<Type, ValueType> modelComponents;
// Build initial states. // Build initial states.
modelComponents.initialStates = computeInitialStates(*this->model, variables); modelComponents.initialStates = computeInitialStates(model, variables);
// Perform reachability analysis to obtain reachable states. // Perform reachability analysis to obtain reachable states.
storm::dd::Bdd<Type> transitionMatrixBdd = system.transitions.notZero(); 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); transitionMatrixBdd = transitionMatrixBdd.existsAbstract(variables.allNondeterminismVariables);
} }
modelComponents.reachableStates = storm::utility::dd::computeReachableStates(modelComponents.initialStates, transitionMatrixBdd, variables.rowMetaVariables, variables.columnMetaVariables); modelComponents.reachableStates = storm::utility::dd::computeReachableStates(modelComponents.initialStates, transitionMatrixBdd, variables.rowMetaVariables, variables.columnMetaVariables);
@ -1756,13 +1949,16 @@ namespace storm {
modelComponents.transitionMatrix = system.transitions * reachableStatesAdd; modelComponents.transitionMatrix = system.transitions * reachableStatesAdd;
// Fix deadlocks if existing. // 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. // Cut the deadlock states by removing all states that we 'converted' to deadlock states by making them terminal.
modelComponents.deadlockStates = modelComponents.deadlockStates && !terminalStates; modelComponents.deadlockStates = modelComponents.deadlockStates && !terminalStates;
// Build the reward models.
modelComponents.rewardModels = buildRewardModels(system, rewardVariables);
// Finally, create the model. // 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>; 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); 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. // A flag that indicates whether or not all reward models are to be build.
bool buildAllRewardModels; bool buildAllRewardModels;
@ -77,11 +87,6 @@ namespace storm {
boost::optional<storm::expressions::Expression> negatedTerminalStates; 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 * Translates the given program into a symbolic model (i.e. one that stores the transition relation as a
* decision diagram). * decision diagram).
@ -89,22 +94,7 @@ namespace storm {
* @param model The model to translate. * @param model The model to translate.
* @return A pointer to the resulting model. * @return A pointer to the resulting model.
*/ */
std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> build(); std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> build(storm::jani::Model const& model, Options const& options = Options());
/*!
* 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;
}; };
} }

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); 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> 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) { std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdPrismModelBuilder<Type, ValueType>::build(storm::prism::Program const& program, Options const& options) {
preparedProgram = program; if (program.hasUndefinedConstants()) {
std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = program.getUndefinedConstants();
if (preparedProgram->hasUndefinedConstants()) {
std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = preparedProgram->getUndefinedConstants();
std::stringstream stream; std::stringstream stream;
bool printComma = false; bool printComma = false;
for (auto const& constant : undefinedConstants) { 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()); 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 << program << std::endl);
STORM_LOG_DEBUG("Building representation of program:" << std::endl << *preparedProgram << std::endl);
// Start by initializing the structure used for storing all information needed during the model generation. // 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. // In particular, this creates the meta variables used to encode the model.
GenerationInformation generationInfo(*preparedProgram); GenerationInformation generationInfo(program);
SystemResult system = createSystemDecisionDiagram(generationInfo); SystemResult system = createSystemDecisionDiagram(generationInfo);
storm::dd::Add<Type, ValueType> transitionMatrix = system.allTransitionsDd; 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. // 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(); storm::dd::Bdd<Type> terminalStatesBdd = generationInfo.manager->getBddZero();
if (options.terminalStates || options.negatedTerminalStates) { 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) { if (options.terminalStates) {
storm::expressions::Expression terminalExpression; storm::expressions::Expression terminalExpression;
@ -1273,7 +1266,7 @@ namespace storm {
} else { } else {
std::string const& labelName = boost::get<std::string>(options.terminalStates.get()); std::string const& labelName = boost::get<std::string>(options.terminalStates.get());
if (program.hasLabel(labelName)) { if (program.hasLabel(labelName)) {
terminalExpression = preparedProgram->getLabelExpression(labelName); terminalExpression = program.getLabelExpression(labelName);
} else { } else {
STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'."); STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'.");
} }
@ -1294,7 +1287,7 @@ namespace storm {
} else { } else {
std::string const& labelName = boost::get<std::string>(options.negatedTerminalStates.get()); std::string const& labelName = boost::get<std::string>(options.negatedTerminalStates.get());
if (program.hasLabel(labelName)) { if (program.hasLabel(labelName)) {
negatedTerminalExpression = preparedProgram->getLabelExpression(labelName); negatedTerminalExpression = program.getLabelExpression(labelName);
} else { } else {
STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'."); 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. // First, we make sure that all selected reward models actually exist.
for (auto const& rewardModelName : options.rewardModelsToBuild) { 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()) { if (options.buildAllRewardModels || options.rewardModelsToBuild.find(rewardModel.getName()) != options.rewardModelsToBuild.end()) {
selectedRewardModels.push_back(rewardModel); selectedRewardModels.push_back(rewardModel);
} }
} }
// If no reward model was selected until now and a referenced reward model appears to be unique, we build // 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). // 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() == "") { if (selectedRewardModels.empty() && program.getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") {
selectedRewardModels.push_back(preparedProgram->getRewardModel(0)); selectedRewardModels.push_back(program.getRewardModel(0));
} }
std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<Type, ValueType>> rewardModels; 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. // Build the labels that can be accessed as a shortcut.
std::map<std::string, storm::expressions::Expression> labelToExpressionMapping; 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()); labelToExpressionMapping.emplace(label.getName(), label.getStatePredicateExpression());
} }
@ -1415,7 +1408,7 @@ namespace storm {
template <storm::dd::DdType Type, typename ValueType> template <storm::dd::DdType Type, typename ValueType>
storm::dd::Bdd<Type> DdPrismModelBuilder<Type, ValueType>::createInitialStatesDecisionDiagram(GenerationInformation& generationInfo) { 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) { for (auto const& metaVariable : generationInfo.rowMetaVariables) {
initialStates &= generationInfo.manager->getRange(metaVariable); 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()); 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: private:
// This structure can store the decision diagrams representing a particular action. // This structure can store the decision diagrams representing a particular action.
struct UpdateDecisionDiagram { struct UpdateDecisionDiagram {
@ -243,9 +235,6 @@ namespace storm {
static SystemResult createSystemDecisionDiagram(GenerationInformation& generationInfo); static SystemResult createSystemDecisionDiagram(GenerationInformation& generationInfo);
static storm::dd::Bdd<Type> createInitialStatesDecisionDiagram(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 } // namespace adapters

40
src/cli/cli.cpp

@ -3,6 +3,8 @@
#include "../utility/storm.h" #include "../utility/storm.h"
#include "src/storage/SymbolicModelDescription.h"
#include "src/settings/modules/DebugSettings.h" #include "src/settings/modules/DebugSettings.h"
#include "src/settings/modules/IOSettings.h" #include "src/settings/modules/IOSettings.h"
#include "src/settings/modules/CoreSettings.h" #include "src/settings/modules/CoreSettings.h"
@ -206,42 +208,46 @@ namespace storm {
storm::utility::initializeFileLogging(); storm::utility::initializeFileLogging();
} }
if (storm::settings::getModule<storm::settings::modules::IOSettings>().isSymbolicSet()) { auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
// If we have to build the model from a symbolic representation, we need to parse the representation first. if (ioSettings.isPrismOrJaniInputSet()) {
storm::prism::Program program = storm::parseProgram(storm::settings::getModule<storm::settings::modules::IOSettings>().getSymbolicModelFilename()); 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. // 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(); std::string constantDefinitionString = ioSettings.getConstantDefinitionString();
storm::prism::Program preprocessedProgram = storm::utility::prism::preprocess(program, constantDefinitionString); model = model.preprocess(constantDefinitionString);
std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = preprocessedProgram.getConstantsSubstitution();
// Then proceed to parsing the properties (if given), since the model we are building may depend on the property. // 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; std::vector<std::shared_ptr<storm::logic::Formula const>> formulas;
if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isPropertySet()) { if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isPropertySet()) {
formulas = storm::parseFormulasForProgram(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), preprocessedProgram); if (model.isJaniModel()) {
} formulas = storm::parseFormulasForJaniModel(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), model.asJaniModel());
} else {
// There may be constants of the model appearing in the formulas, so we replace all their occurrences formulas = storm::parseFormulasForPrismProgram(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), model.asPrismProgram());
// 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 (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isParametricSet()) { if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isParametricSet()) {
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
buildAndCheckSymbolicModel<storm::RationalFunction>(preprocessedProgram, preprocessedFormulas, true); buildAndCheckSymbolicModel<storm::RationalFunction>(model, formulas, true);
#else #else
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No parameters are supported in this build."); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No parameters are supported in this build.");
#endif #endif
} else if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isExactSet()) { } else if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isExactSet()) {
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
buildAndCheckSymbolicModel<storm::RationalNumber>(preprocessedProgram, preprocessedFormulas, true); buildAndCheckSymbolicModel<storm::RationalNumber>(model, formulas, true);
#else #else
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No exact numbers are supported in this build."); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No exact numbers are supported in this build.");
#endif #endif
} else { } else {
buildAndCheckSymbolicModel<double>(preprocessedProgram, preprocessedFormulas, true); buildAndCheckSymbolicModel<double>(model, formulas, true);
} }
} else if (storm::settings::getModule<storm::settings::modules::IOSettings>().isExplicitSet()) { } 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."); 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/utility/storm.h"
#include "src/storage/SymbolicModelDescription.h"
#include "src/exceptions/NotImplementedException.h" #include "src/exceptions/NotImplementedException.h"
#include "src/exceptions/InvalidSettingsException.h"
namespace storm { namespace storm {
namespace cli { namespace cli {
@ -49,12 +52,14 @@ namespace storm {
#endif #endif
template<storm::dd::DdType DdType> 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."); STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Abstraction Refinement is not yet implemented.");
} }
template<typename ValueType> 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."); 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) { for (auto const& formula : formulas) {
@ -98,7 +103,7 @@ namespace storm {
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
template<> 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."); STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Exploration-based verification does currently not support parametric models.");
} }
#endif #endif
@ -177,81 +182,80 @@ namespace storm {
} }
template<storm::dd::DdType LibraryType> 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. // 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. // Print some information about the model.
model->printModelInformationToStream(std::cout); markovModel->printModelInformationToStream(std::cout);
// Then select the correct engine. // Then select the correct engine.
if (hybrid) { if (hybrid) {
verifySymbolicModelWithHybridEngine(model, formulas, onlyInitialStatesRelevant); verifySymbolicModelWithHybridEngine(markovModel, formulas, onlyInitialStatesRelevant);
} else { } else {
verifySymbolicModelWithDdEngine(model, formulas, onlyInitialStatesRelevant); verifySymbolicModelWithDdEngine(markovModel, formulas, onlyInitialStatesRelevant);
} }
} }
template<typename ValueType> 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. // 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. // Print some information about the model.
model->printModelInformationToStream(std::cout); markovModel->printModelInformationToStream(std::cout);
// Preprocess the model. // 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. // Finally, treat the formulas.
if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isCounterexampleSet()) { if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isCounterexampleSet()) {
generateCounterexamples<ValueType>(program, sparseModel, formulas); generateCounterexamples<ValueType>(model, sparseModel, formulas);
} else { } else {
verifySparseModel<ValueType>(sparseModel, formulas, onlyInitialStatesRelevant); verifySparseModel<ValueType>(sparseModel, formulas, onlyInitialStatesRelevant);
} }
} }
template<typename ValueType> 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) { 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(); auto ddlib = storm::settings::getModule<storm::settings::modules::CoreSettings>().getDdLibraryType();
if (ddlib == storm::dd::DdType::CUDD) { if (ddlib == storm::dd::DdType::CUDD) {
verifySymbolicModelWithAbstractionRefinementEngine<storm::dd::DdType::CUDD>(program, formulas, onlyInitialStatesRelevant); verifySymbolicModelWithAbstractionRefinementEngine<storm::dd::DdType::CUDD>(model, formulas, onlyInitialStatesRelevant);
} else { } 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) { } 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 { } else {
auto engine = storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine(); 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) { 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(); auto ddlib = storm::settings::getModule<storm::settings::modules::CoreSettings>().getDdLibraryType();
if (ddlib == storm::dd::DdType::CUDD) { 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 { } 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 { } else {
STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Illegal engine."); STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Illegal engine.");
buildAndCheckSymbolicModelWithSparseEngine<ValueType>(model, formulas, onlyInitialStatesRelevant);
buildAndCheckSymbolicModelWithSparseEngine<ValueType>(program, formulas, onlyInitialStatesRelevant);
} }
} }
} }
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
template<> 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."); 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<> 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."); 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 #endif

2
src/counterexamples/SMTMinimalCommandSetGenerator.h

@ -628,7 +628,7 @@ namespace storm {
} }
// Construct an expression that exactly characterizes the initial state. // 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. // 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; 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/utility/solver.h"
#include "src/exceptions/InvalidSettingsException.h" #include "src/exceptions/InvalidSettingsException.h"
#include "src/exceptions/WrongFormatException.h" #include "src/exceptions/WrongFormatException.h"
#include "src/exceptions/InvalidArgumentException.h"
namespace storm { namespace storm {
namespace generator { namespace generator {
@ -21,11 +22,39 @@ namespace storm {
} }
template<typename ValueType, typename StateType> 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(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."); 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 there are terminal states we need to handle, we now need to translate all labels to expressions.
if (this->options.hasTerminalStates()) { if (this->options.hasTerminalStates()) {
for (auto const& expressionOrLabelAndBool : this->options.getTerminalStates()) { for (auto const& expressionOrLabelAndBool : this->options.getTerminalStates()) {
@ -161,6 +190,9 @@ namespace storm {
} }
// Block the current initial state to search for the next one. // Block the current initial state to search for the next one.
if (!blockingExpression.isInitialized()) {
break;
}
solver->add(blockingExpression); solver->add(blockingExpression);
} }
@ -171,13 +203,8 @@ namespace storm {
CompressedState JaniNextStateGenerator<ValueType, StateType>::applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& destination) { CompressedState JaniNextStateGenerator<ValueType, StateType>::applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& destination) {
CompressedState newState(state); CompressedState newState(state);
// NOTE: the following process assumes that the assignments of the destination are ordered in such a way auto assignmentIt = destination.getNonTransientAssignments().begin();
// that the assignments to boolean variables precede the assignments to all integer variables and that auto assignmentIte = destination.getNonTransientAssignments().end();
// 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();
// Iterate over all boolean assignments and carry them out. // Iterate over all boolean assignments and carry them out.
auto boolIt = this->variableInformation.booleanVariables.begin(); auto boolIt = this->variableInformation.booleanVariables.begin();
@ -211,6 +238,22 @@ namespace storm {
// Prepare the result, in case we return early. // Prepare the result, in case we return early.
StateBehavior<ValueType, StateType> result; 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 a terminal expression was set and we must not expand this state, return now.
if (!this->terminalStates.empty()) { if (!this->terminalStates.empty()) {
for (auto const& expressionBool : this->terminalStates) { 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. // Get all choices for the state.
std::vector<Choice<ValueType>> allChoices = getSilentActionChoices(locations, *this->state, stateToIdCallback); std::vector<Choice<ValueType>> allChoices = getSilentActionChoices(locations, *this->state, stateToIdCallback);
std::vector<Choice<ValueType>> allLabeledChoices = getNonsilentActionChoices(locations, *this->state, stateToIdCallback); std::vector<Choice<ValueType>> allLabeledChoices = getNonsilentActionChoices(locations, *this->state, stateToIdCallback);
@ -308,6 +348,9 @@ namespace storm {
probabilitySum += probability; 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. // 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 << ")."); 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> template<typename ValueType, typename StateType>
std::size_t JaniNextStateGenerator<ValueType, StateType>::getNumberOfRewardModels() const { std::size_t JaniNextStateGenerator<ValueType, StateType>::getNumberOfRewardModels() const {
return 0; return rewardVariables.size();
} }
template<typename ValueType, typename StateType> template<typename ValueType, typename StateType>
RewardModelInformation JaniNextStateGenerator<ValueType, StateType>::getRewardModelInformation(uint64_t const& index) const { RewardModelInformation JaniNextStateGenerator<ValueType, StateType>::getRewardModelInformation(uint64_t const& index) const {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Cannot retrieve reward model information."); return rewardModelInformation[index];
return RewardModelInformation("", false, false, false);
} }
template<typename ValueType, typename StateType> template<typename ValueType, typename StateType>
@ -491,6 +533,81 @@ namespace storm {
return NextStateGenerator<ValueType, StateType>::label(states, initialStateIndices, deadlockStateIndices, {}); 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>; template class JaniNextStateGenerator<double>;
#ifdef STORM_HAVE_CARL #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; 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. /// The model used for the generation of next states.
storm::jani::Model model; 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; return transitionRewards;
} }
void RewardModelInformation::setHasStateRewards() {
stateRewards = true;
}
void RewardModelInformation::setHasStateActionRewards() {
stateActionRewards = true;
}
void RewardModelInformation::setHasTransitionRewards() {
transitionRewards = true;
}
template<typename ValueType, typename StateType> 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) { 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. // Intentionally left empty.

3
src/generator/NextStateGenerator.h

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

14
src/generator/PrismNextStateGenerator.cpp

@ -23,8 +23,9 @@ namespace storm {
template<typename ValueType, typename StateType> 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() { 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."); 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. // Only after checking validity of the program, we initialize the variable information.
this->checkValid(program); this->checkValid(program);
this->variableInformation = VariableInformation(program); this->variableInformation = VariableInformation(program);
@ -41,11 +42,10 @@ namespace storm {
} else { } else {
STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException, "Cannot build unknown reward model '" << rewardModelName << "'."); 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() == 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. // standard reward model.
if (rewardModels.empty() && !this->options.getRewardModelNames().empty()) { if (rewardModels.empty() && !this->options.getRewardModelNames().empty()) {
rewardModels.push_back(this->program.getRewardModel(0)); rewardModels.push_back(this->program.getRewardModel(0));
@ -136,7 +136,7 @@ namespace storm {
for (auto const& expression : rangeExpressions) { for (auto const& expression : rangeExpressions) {
solver->add(expression); solver->add(expression);
} }
solver->add(program.getInitialConstruct().getInitialStatesExpression()); solver->add(program.getInitialStatesExpression());
// Proceed ss long as the solver can still enumerate initial states. // Proceed ss long as the solver can still enumerate initial states.
std::vector<StateType> initialStateIndices; std::vector<StateType> initialStateIndices;
@ -166,6 +166,9 @@ namespace storm {
initialStateIndices.push_back(id); initialStateIndices.push_back(id);
// Block the current initial state to search for the next one. // Block the current initial state to search for the next one.
if (!blockingExpression.isInitialized()) {
break;
}
solver->add(blockingExpression); solver->add(blockingExpression);
} }
@ -314,7 +317,7 @@ namespace storm {
template<typename ValueType, typename StateType> 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>>>> 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>>>())); 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. // Iterate over all modules.
for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) { for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
storm::prism::Module const& module = program.getModule(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) { for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) {
storm::prism::Command const& command = *iteratorList[i]; storm::prism::Command const& command = *iteratorList[i];
for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) { for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) {
storm::prism::Update const& update = command.getUpdate(j); storm::prism::Update const& update = command.getUpdate(j);

5
src/generator/StateBehavior.cpp

@ -20,6 +20,11 @@ namespace storm {
stateRewards.push_back(stateReward); 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> template<typename ValueType, typename StateType>
void StateBehavior<ValueType, StateType>::setExpanded(bool newValue) { void StateBehavior<ValueType, StateType>::setExpanded(bool newValue) {
this->expanded = 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. * Adds the given state reward to the behavior of the state.
*/ */
void addStateReward(ValueType const& stateReward); 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. * Sets whether the state was expanded.
*/ */

1
src/modelchecker/AbstractModelChecker.cpp

@ -17,6 +17,7 @@
#include "src/models/symbolic/Mdp.h" #include "src/models/symbolic/Mdp.h"
#include "src/models/sparse/MarkovAutomaton.h" #include "src/models/sparse/MarkovAutomaton.h"
#include "src/models/sparse/StandardRewardModel.h" #include "src/models/sparse/StandardRewardModel.h"
#include "src/models/symbolic/StandardRewardModel.h"
#include "src/storage/dd/Add.h" #include "src/storage/dd/Add.h"
#include "src/storage/dd/Bdd.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)). // for solving the equation system (i.e. compute (I-A)).
submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs());
submatrix = (model.getRowColumnIdentity() * maybeStatesAdd) - submatrix; submatrix = (model.getRowColumnIdentity() * maybeStatesAdd) - submatrix;
// Solve the equation system. // Solve the equation system.
std::unique_ptr<storm::solver::SymbolicLinearEquationSolver<DdType, ValueType>> solver = linearEquationSolverFactory.create(submatrix, maybeStates, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs()); 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); 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/InvalidTypeException.h"
#include "src/exceptions/WrongFormatException.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 storm {
namespace parser { 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_) { 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 = identifier[qi::_val = phoenix::bind(&ExpressionParser::getIdentifierExpression, phoenix::ref(*this), qi::_1, allowBacktracking, qi::_pass)];
identifierExpression.name("identifier expression"); 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"); literalExpression.name("literal expression");
atomicExpression = floorCeilExpression | prefixPowerExpression | minMaxExpression | (qi::lit("(") >> expression >> qi::lit(")")) | literalExpression | identifierExpression; atomicExpression = floorCeilExpression | prefixPowerExpression | minMaxExpression | (qi::lit("(") >> expression >> qi::lit(")")) | literalExpression | identifierExpression;
@ -295,7 +323,7 @@ namespace storm {
return manager->boolean(false); 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 we are not supposed to accept double expressions, we reject it by setting pass to false.
if (!this->acceptDoubleLiterals) { if (!this->acceptDoubleLiterals) {
pass = false; pass = false;

16
src/parser/ExpressionParser.h

@ -8,8 +8,20 @@
#include "src/storage/expressions/Expression.h" #include "src/storage/expressions/Expression.h"
#include "src/storage/expressions/ExpressionManager.h" #include "src/storage/expressions/ExpressionManager.h"
#include "src/adapters/CarlAdapter.h"
namespace storm { namespace storm {
namespace parser { 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> { class ExpressionParser : public qi::grammar<Iterator, storm::expressions::Expression(), Skipper> {
public: public:
/*! /*!
@ -236,7 +248,7 @@ namespace storm {
qi::rule<Iterator, std::string(), Skipper> identifier; qi::rule<Iterator, std::string(), Skipper> identifier;
// Parser that is used to recognize doubles only (as opposed to Spirit's double_ parser). // 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. // Helper functions to create expressions.
storm::expressions::Expression createIteExpression(storm::expressions::Expression e1, storm::expressions::Expression e2, storm::expressions::Expression e3, bool& pass) const; 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 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 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 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 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 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; 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/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. // If the parser fails due to ill-formed data, this exception is thrown.
#include "src/exceptions/WrongFormatException.h" #include "src/exceptions/WrongFormatException.h"
@ -176,7 +179,7 @@ namespace storm {
phoenix::function<SpiritErrorHandler> handler; 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. // Intentionally left empty.
} }

6
src/parser/FormulaParser.h

@ -9,9 +9,11 @@
#include "src/storage/expressions/Expression.h" #include "src/storage/expressions/Expression.h"
#include "src/utility/macros.h" #include "src/utility/macros.h"
#include "src/storage/prism/Program.h"
namespace storm { namespace storm {
namespace prism {
class Program;
}
namespace parser { namespace parser {
// Forward-declare grammar. // 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("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_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::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 + "')"); storm::expressions::Expression rhs = parseExpression(transientValueEntry.at("value"), "Assignment of variable " + lhs.getName() + " in location " + locName + " (automaton: '" + name + "')");
transientAssignments.emplace_back(lhs, rhs); 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::Property parseProperty(json const& propertyStructure);
storm::jani::Automaton parseAutomaton(json const& automatonStructure, storm::jani::Model const& parentModel); 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); 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: private:
std::shared_ptr<storm::jani::Constant> parseConstant(json const& constantStructure, std::string const& scopeDescription = "global"); 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_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << lineNumber << " of file " << filename << ".");
} }
STORM_LOG_TRACE("Parsed PRISM input: " << result);
return 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 = (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"); 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"); 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"); integerVariableDefinition.name("integer variable definition");
variableDefinition = (booleanVariableDefinition[phoenix::push_back(qi::_r1, qi::_1)] | integerVariableDefinition[phoenix::push_back(qi::_r2, qi::_1)]); 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 %= +(moduleRenaming(qi::_r1) | moduleDefinition(qi::_r1))[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::modules, qi::_r1), qi::_1)];
moduleDefinitionList.name("module list"); 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] > modelTypeDefinition[phoenix::bind(&GlobalProgramInformation::modelType, qi::_a) = qi::_1]
> *(definedConstantDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::constants, 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)] | undefinedConstantDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::constants, qi::_a), qi::_1)]
@ -276,7 +278,7 @@ namespace storm {
return true; 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."); 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) { if (globalProgramInformation.hasInitialConstruct) {
return false; return false;
@ -585,7 +587,7 @@ namespace storm {
auto const& renamingPair = renaming.find(variable.getName()); 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."); 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. // Rename the integer variables.
@ -594,7 +596,7 @@ namespace storm {
auto const& renamingPair = renaming.find(variable.getName()); 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."); 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. // Rename commands.
@ -640,7 +642,11 @@ namespace storm {
} }
storm::prism::Program PrismParser::createProgram(GlobalProgramInformation const& globalProgramInformation) const { 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 parser
} // namespace storm } // namespace storm

6
src/parser/PrismParser.h

@ -188,7 +188,7 @@ namespace storm {
// Rules for variable definitions. // 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, 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; qi::rule<Iterator, storm::prism::IntegerVariable(), qi::locals<storm::expressions::Expression>, Skipper> integerVariableDefinition;
// Rules for command definitions. // Rules for command definitions.
@ -241,7 +241,7 @@ namespace storm {
// Helper methods used in the grammar. // Helper methods used in the grammar.
bool isValidIdentifier(std::string const& identifier); 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); 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::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; storm::prism::Program createProgram(GlobalProgramInformation const& globalProgramInformation) const;
void removeInitialConstruct(GlobalProgramInformation& globalProgramInformation) const;
// An error handler function. // An error handler function.
phoenix::function<SpiritErrorHandler> handler; 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::engineOptionShortName = "e";
const std::string CoreSettings::ddLibraryOptionName = "ddlib"; const std::string CoreSettings::ddLibraryOptionName = "ddlib";
const std::string CoreSettings::cudaOptionName = "cuda"; const std::string CoreSettings::cudaOptionName = "cuda";
const std::string CoreSettings::minMaxEquationSolvingTechniqueOptionName = "ndmethod";
CoreSettings::CoreSettings() : ModuleSettings(moduleName), engine(CoreSettings::Engine::Sparse) { 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") 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()); .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, 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()); 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 { 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 engineOptionShortName;
static const std::string ddLibraryOptionName; static const std::string ddLibraryOptionName;
static const std::string cudaOptionName; static const std::string cudaOptionName;
static const std::string minMaxEquationSolvingTechniqueOptionName;
}; };
} // namespace modules } // namespace modules

2
src/settings/modules/CounterexampleGeneratorSettings.cpp

@ -48,7 +48,7 @@ namespace storm {
bool CounterexampleGeneratorSettings::check() const { bool CounterexampleGeneratorSettings::check() const {
// Ensure that the model was given either symbolically or explicitly. // 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()) { 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."); 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::exportMatOptionName = "exportmat";
const std::string IOSettings::explicitOptionName = "explicit"; const std::string IOSettings::explicitOptionName = "explicit";
const std::string IOSettings::explicitOptionShortName = "exp"; const std::string IOSettings::explicitOptionShortName = "exp";
const std::string IOSettings::symbolicOptionName = "symbolic"; const std::string IOSettings::prismInputOptionName = "prism";
const std::string IOSettings::symbolicOptionShortName = "s"; const std::string IOSettings::janiInputOptionName = "jani";
const std::string IOSettings::prismToJaniOptionName = "prism2jani";
const std::string IOSettings::explorationOrderOptionName = "explorder"; const std::string IOSettings::explorationOrderOptionName = "explorder";
const std::string IOSettings::explorationOrderOptionShortName = "eo"; const std::string IOSettings::explorationOrderOptionShortName = "eo";
const std::string IOSettings::transitionRewardsOptionName = "transrew"; 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) 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("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()); .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) 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 symbolic model.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build()); .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"}; std::vector<std::string> explorationOrders = {"dfs", "bfs"};
this->addOption(storm::settings::OptionBuilder(moduleName, explorationOrderOptionName, false, "Sets which exploration order to use.").setShortName(explorationOrderOptionShortName) 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()); .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 + ").") 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()); .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()); .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(); return this->getOption(explicitOptionName).getArgumentByName("labeling filename").getValueAsString();
} }
bool IOSettings::isSymbolicSet() const { bool IOSettings::isPrismInputSet() const {
return this->getOption(symbolicOptionName).getHasOptionBeenSet(); return this->getOption(prismInputOptionName).getHasOptionBeenSet();
} }
std::string IOSettings::getSymbolicModelFilename() const { bool IOSettings::isPrismOrJaniInputSet() const {
return this->getOption(symbolicOptionName).getArgumentByName("filename").getValueAsString(); 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 { bool IOSettings::isExplorationOrderSet() const {
return this->getOption(explorationOrderOptionName).getHasOptionBeenSet(); return this->getOption(explorationOrderOptionName).getHasOptionBeenSet();
} }
@ -141,8 +161,15 @@ namespace storm {
} }
bool IOSettings::check() const { 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. // 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; return true;
} }

48
src/settings/modules/IOSettings.h

@ -59,20 +59,49 @@ namespace storm {
std::string getLabelingFilename() const; 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 * Retrieves whether the JANI or PRISM input option was set.
* using the symbolic option. *
* @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. * Retrieves whether the model exploration order was set.
* *
@ -174,8 +203,9 @@ namespace storm {
static const std::string exportMatOptionName; static const std::string exportMatOptionName;
static const std::string explicitOptionName; static const std::string explicitOptionName;
static const std::string explicitOptionShortName; static const std::string explicitOptionShortName;
static const std::string symbolicOptionName; static const std::string prismInputOptionName;
static const std::string symbolicOptionShortName; static const std::string janiInputOptionName;
static const std::string prismToJaniOptionName;
static const std::string explorationOrderOptionName; static const std::string explorationOrderOptionName;
static const std::string explorationOrderOptionShortName; static const std::string explorationOrderOptionShortName;
static const std::string transitionRewardsOptionName; 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/InvalidTypeException.h"
#include "src/exceptions/InvalidAccessException.h" #include "src/exceptions/InvalidAccessException.h"
#include "src/storage/expressions/Expressions.h"
namespace storm { namespace storm {
namespace expressions { namespace expressions {
BaseExpression::BaseExpression(ExpressionManager const& manager, Type const& type) : manager(manager), type(type) { BaseExpression::BaseExpression(ExpressionManager const& manager, Type const& type) : manager(manager), type(type) {
@ -94,6 +96,86 @@ namespace storm {
return this->shared_from_this(); 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) { std::ostream& operator<<(std::ostream& stream, BaseExpression const& expression) {
expression.printToStream(stream); expression.printToStream(stream);
return stream; return stream;

46
src/storage/expressions/BaseExpression.h

@ -13,12 +13,24 @@
namespace storm { namespace storm {
namespace expressions { namespace expressions {
// Forward-declare expression manager. // Forward-declare expression classes.
class ExpressionManager; class ExpressionManager;
class Variable; class Variable;
class Valuation; class Valuation;
class ExpressionVisitor; class ExpressionVisitor;
enum struct OperatorType; 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. * The base class of all expression classes.
*/ */
@ -164,7 +176,7 @@ namespace storm {
* *
* @param visitor The visitor that is to be accepted. * @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. * 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); 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: protected:
/*! /*!
* Prints the expression to the given stream. * 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 { boost::any BinaryBooleanFunctionExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this); return visitor.visit(*this, data);
} }
void BinaryBooleanFunctionExpression::printToStream(std::ostream& stream) const { 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 storm::expressions::OperatorType getOperator() const override;
virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override; virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() 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. * 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/BinaryNumericalFunctionExpression.h"
#include "src/storage/expressions/IntegerLiteralExpression.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/storage/expressions/ExpressionVisitor.h"
#include "src/utility/macros.h" #include "src/utility/macros.h"
#include "src/exceptions/InvalidTypeException.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::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; 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 { boost::any BinaryNumericalFunctionExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this); return visitor.visit(*this, data);
} }
void BinaryNumericalFunctionExpression::printToStream(std::ostream& stream) const { 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 int_fast64_t evaluateAsInt(Valuation const* valuation = nullptr) const override;
virtual double evaluateAsDouble(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 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. * 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 { boost::any BinaryRelationExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this); return visitor.visit(*this, data);
} }
BinaryRelationExpression::RelationType BinaryRelationExpression::getRelationType() const { 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 storm::expressions::OperatorType getOperator() const override;
virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override; virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() 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. * Retrieves the relation associated with the expression.

4
src/storage/expressions/BooleanLiteralExpression.cpp

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

2
src/storage/expressions/BooleanLiteralExpression.h

@ -32,7 +32,7 @@ namespace storm {
virtual bool isFalse() const override; virtual bool isFalse() const override;
virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override; virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override;
virtual std::shared_ptr<BaseExpression const> simplify() 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. * 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/ExpressionManager.h"
#include "src/storage/expressions/SubstitutionVisitor.h" #include "src/storage/expressions/SubstitutionVisitor.h"
#include "src/storage/expressions/LinearityCheckVisitor.h" #include "src/storage/expressions/LinearityCheckVisitor.h"
#include "src/storage/expressions/SyntacticalEqualityCheckVisitor.h"
#include "src/storage/expressions/Expressions.h" #include "src/storage/expressions/Expressions.h"
#include "src/exceptions/InvalidTypeException.h" #include "src/exceptions/InvalidTypeException.h"
#include "src/exceptions/InvalidArgumentException.h" #include "src/exceptions/InvalidArgumentException.h"
@ -158,8 +159,8 @@ namespace storm {
return this->getBaseExpression().hasBitVectorType(); return this->getBaseExpression().hasBitVectorType();
} }
boost::any Expression::accept(ExpressionVisitor& visitor) const { boost::any Expression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return this->getBaseExpression().accept(visitor); return this->getBaseExpression().accept(visitor, data);
} }
bool Expression::isInitialized() const { bool Expression::isInitialized() const {
@ -168,6 +169,14 @@ namespace storm {
} }
return false; 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::string Expression::toString() const {
std::stringstream stream; std::stringstream stream;

9
src/storage/expressions/Expression.h

@ -302,7 +302,7 @@ namespace storm {
* *
* @param visitor The visitor to accept. * @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. * Converts the expression into a string.
@ -311,11 +311,16 @@ namespace storm {
*/ */
std::string toString() const; std::string toString() const;
/** /*!
* Checks whether the object encapsulates a base-expression. * Checks whether the object encapsulates a base-expression.
*/ */
bool isInitialized() const; 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); friend std::ostream& operator<<(std::ostream& stream, Expression const& expression);
private: private:

6
src/storage/expressions/ExpressionManager.cpp

@ -65,7 +65,11 @@ namespace storm {
} }
Expression ExpressionManager::rational(double value) const { 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 { 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/Variable.h"
#include "src/storage/expressions/Expression.h" #include "src/storage/expressions/Expression.h"
#include "src/adapters/CarlAdapter.h"
#include "src/utility/OsDetection.h" #include "src/utility/OsDetection.h"
namespace storm { namespace storm {
@ -104,6 +105,14 @@ namespace storm {
* @return The resulting expression. * @return The resulting expression.
*/ */
Expression rational(double value) const; 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. * 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 UnaryNumericalFunctionExpression;
class BooleanLiteralExpression; class BooleanLiteralExpression;
class IntegerLiteralExpression; class IntegerLiteralExpression;
class DoubleLiteralExpression; class RationalLiteralExpression;
class ExpressionVisitor { class ExpressionVisitor {
public: public:
virtual boost::any visit(IfThenElseExpression const& expression) = 0; virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) = 0; virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) = 0; virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(BinaryRelationExpression const& expression) = 0; virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(VariableExpression const& expression) = 0; virtual boost::any visit(VariableExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) = 0; virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) = 0; virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(BooleanLiteralExpression const& expression) = 0; virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(IntegerLiteralExpression const& expression) = 0; virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) = 0;
virtual boost::any visit(DoubleLiteralExpression const& expression) = 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/BinaryRelationExpression.h"
#include "src/storage/expressions/BooleanLiteralExpression.h" #include "src/storage/expressions/BooleanLiteralExpression.h"
#include "src/storage/expressions/IntegerLiteralExpression.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/UnaryBooleanFunctionExpression.h"
#include "src/storage/expressions/UnaryNumericalFunctionExpression.h" #include "src/storage/expressions/UnaryNumericalFunctionExpression.h"
#include "src/storage/expressions/VariableExpression.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 { boost::any IfThenElseExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this); return visitor.visit(*this, data);
} }
std::shared_ptr<BaseExpression const> IfThenElseExpression::getCondition() const { 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 double evaluateAsDouble(Valuation const* valuation = nullptr) const override;
virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override; virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override;
virtual std::shared_ptr<BaseExpression const> simplify() 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. * 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(); return this->shared_from_this();
} }
boost::any IntegerLiteralExpression::accept(ExpressionVisitor& visitor) const { boost::any IntegerLiteralExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this); return visitor.visit(*this, data);
} }
int_fast64_t IntegerLiteralExpression::getValue() const { int_fast64_t IntegerLiteralExpression::getValue() const {

2
src/storage/expressions/IntegerLiteralExpression.h

@ -31,7 +31,7 @@ namespace storm {
virtual bool isLiteral() const override; virtual bool isLiteral() const override;
virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override; virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override;
virtual std::shared_ptr<BaseExpression const> simplify() 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. * 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) { 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."); 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."); STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
} }
boost::any LinearCoefficientVisitor::visit(BinaryNumericalFunctionExpression const& expression) { boost::any LinearCoefficientVisitor::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
VariableCoefficients leftResult = boost::any_cast<VariableCoefficients>(expression.getFirstOperand()->accept(*this)); VariableCoefficients leftResult = boost::any_cast<VariableCoefficients>(expression.getFirstOperand()->accept(*this, data));
VariableCoefficients rightResult = boost::any_cast<VariableCoefficients>(expression.getSecondOperand()->accept(*this)); VariableCoefficients rightResult = boost::any_cast<VariableCoefficients>(expression.getSecondOperand()->accept(*this, data));
if (expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Plus) { if (expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Plus) {
leftResult += std::move(rightResult); leftResult += std::move(rightResult);
@ -114,11 +114,11 @@ namespace storm {
return leftResult; 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."); 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; VariableCoefficients coefficients;
if (expression.getType().isNumericalType()) { if (expression.getType().isNumericalType()) {
coefficients.setCoefficient(expression.getVariable(), 1); coefficients.setCoefficient(expression.getVariable(), 1);
@ -128,12 +128,12 @@ namespace storm {
return coefficients; 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."); STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
} }
boost::any LinearCoefficientVisitor::visit(UnaryNumericalFunctionExpression const& expression) { boost::any LinearCoefficientVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
VariableCoefficients childResult = boost::any_cast<VariableCoefficients>(expression.getOperand()->accept(*this)); VariableCoefficients childResult = boost::any_cast<VariableCoefficients>(expression.getOperand()->accept(*this, data));
if (expression.getOperatorType() == UnaryNumericalFunctionExpression::OperatorType::Minus) { if (expression.getOperatorType() == UnaryNumericalFunctionExpression::OperatorType::Minus) {
childResult.negate(); 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."); 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())); return VariableCoefficients(static_cast<double>(expression.getValue()));
} }
boost::any LinearCoefficientVisitor::visit(DoubleLiteralExpression const& expression) { boost::any LinearCoefficientVisitor::visit(RationalLiteralExpression const& expression, boost::any const& data) {
return VariableCoefficients(expression.getValue()); return VariableCoefficients(expression.getValueAsDouble());
} }
} }
} }

20
src/storage/expressions/LinearCoefficientVisitor.h

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

20
src/storage/expressions/LinearityCheckVisitor.h

@ -20,16 +20,16 @@ namespace storm {
*/ */
bool check(Expression const& expression); bool check(Expression const& expression);
virtual boost::any visit(IfThenElseExpression const& expression) override; virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override; virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryRelationExpression const& expression) override; virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
virtual boost::any visit(VariableExpression const& expression) override; virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override; virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override; virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
private: private:
enum class LinearityStatus { NonLinear, LinearContainsVariables, LinearWithoutVariables }; 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> template<typename MapType>
Expression SubstitutionVisitor<MapType>::substitute(Expression const& expression) { 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> template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(IfThenElseExpression const& expression) { 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)); 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)); 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)); 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 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()) { 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> template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(BinaryBooleanFunctionExpression const& expression) { 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)); 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)); 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 the arguments did not change, we simply push the expression itself.
if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) {
@ -45,9 +45,9 @@ namespace storm {
} }
template<typename MapType> template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(BinaryNumericalFunctionExpression const& expression) { 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)); 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)); 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 the arguments did not change, we simply push the expression itself.
if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) {
@ -58,9 +58,9 @@ namespace storm {
} }
template<typename MapType> template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(BinaryRelationExpression const& expression) { 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)); 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)); 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 the arguments did not change, we simply push the expression itself.
if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) {
@ -71,7 +71,7 @@ namespace storm {
} }
template<typename MapType> 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. // If the variable is in the key set of the substitution, we need to replace it.
auto const& nameExpressionPair = this->variableToExpressionMapping.find(expression.getVariable()); auto const& nameExpressionPair = this->variableToExpressionMapping.find(expression.getVariable());
if (nameExpressionPair != this->variableToExpressionMapping.end()) { if (nameExpressionPair != this->variableToExpressionMapping.end()) {
@ -82,8 +82,8 @@ namespace storm {
} }
template<typename MapType> template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(UnaryBooleanFunctionExpression const& expression) { 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)); 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 the argument did not change, we simply push the expression itself.
if (operandExpression.get() == expression.getOperand().get()) { if (operandExpression.get() == expression.getOperand().get()) {
@ -94,8 +94,8 @@ namespace storm {
} }
template<typename MapType> template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(UnaryNumericalFunctionExpression const& expression) { 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)); 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 the argument did not change, we simply push the expression itself.
if (operandExpression.get() == expression.getOperand().get()) { if (operandExpression.get() == expression.getOperand().get()) {
@ -106,17 +106,17 @@ namespace storm {
} }
template<typename MapType> 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(); return expression.getSharedPointer();
} }
template<typename MapType> 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(); return expression.getSharedPointer();
} }
template<typename MapType> 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(); return expression.getSharedPointer();
} }

20
src/storage/expressions/SubstitutionVisitor.h

@ -28,16 +28,16 @@ namespace storm {
*/ */
Expression substitute(Expression const& expression); Expression substitute(Expression const& expression);
virtual boost::any visit(IfThenElseExpression const& expression) override; virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override; virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryRelationExpression const& expression) override; virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
virtual boost::any visit(VariableExpression const& expression) override; virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override; virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override; virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
private: private:
// A mapping of variables to expressions with which they shall be replaced. // 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) { std::string ToExprtkStringVisitor::toString(BaseExpression const* expression) {
stream.str(""); stream.str("");
stream.clear(); stream.clear();
expression->accept(*this); expression->accept(*this, boost::none);
return stream.str(); return stream.str();
} }
boost::any ToExprtkStringVisitor::visit(IfThenElseExpression const& expression) { boost::any ToExprtkStringVisitor::visit(IfThenElseExpression const& expression, boost::any const& data) {
stream << "if("; stream << "if(";
expression.getCondition()->accept(*this); expression.getCondition()->accept(*this, data);
stream << ","; stream << ",";
expression.getThenExpression()->accept(*this); expression.getThenExpression()->accept(*this, data);
stream << ","; stream << ",";
expression.getElseExpression()->accept(*this); expression.getElseExpression()->accept(*this, data);
stream << ")"; stream << ")";
return boost::any(); return boost::any();
} }
boost::any ToExprtkStringVisitor::visit(BinaryBooleanFunctionExpression const& expression) { boost::any ToExprtkStringVisitor::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
switch (expression.getOperatorType()) { switch (expression.getOperatorType()) {
case BinaryBooleanFunctionExpression::OperatorType::And: case BinaryBooleanFunctionExpression::OperatorType::And:
stream << "("; stream << "(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << " and "; stream << " and ";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryBooleanFunctionExpression::OperatorType::Or: case BinaryBooleanFunctionExpression::OperatorType::Or:
stream << "("; stream << "(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << " or "; stream << " or ";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryBooleanFunctionExpression::OperatorType::Xor: case BinaryBooleanFunctionExpression::OperatorType::Xor:
stream << "("; stream << "(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << " xor "; stream << " xor ";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryBooleanFunctionExpression::OperatorType::Implies: case BinaryBooleanFunctionExpression::OperatorType::Implies:
stream << "(not("; stream << "(not(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << ") or "; stream << ") or ";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryBooleanFunctionExpression::OperatorType::Iff: case BinaryBooleanFunctionExpression::OperatorType::Iff:
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << "=="; stream << "==";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
break; break;
} }
return boost::any(); return boost::any();
} }
boost::any ToExprtkStringVisitor::visit(BinaryNumericalFunctionExpression const& expression) { boost::any ToExprtkStringVisitor::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
switch (expression.getOperatorType()) { switch (expression.getOperatorType()) {
case BinaryNumericalFunctionExpression::OperatorType::Plus: case BinaryNumericalFunctionExpression::OperatorType::Plus:
stream << "("; stream << "(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << "+"; stream << "+";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryNumericalFunctionExpression::OperatorType::Minus: case BinaryNumericalFunctionExpression::OperatorType::Minus:
stream << "("; stream << "(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << "-"; stream << "-";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryNumericalFunctionExpression::OperatorType::Times: case BinaryNumericalFunctionExpression::OperatorType::Times:
stream << "("; stream << "(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << "*"; stream << "*";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryNumericalFunctionExpression::OperatorType::Divide: case BinaryNumericalFunctionExpression::OperatorType::Divide:
stream << "("; stream << "(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << "/"; stream << "/";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryNumericalFunctionExpression::OperatorType::Power: case BinaryNumericalFunctionExpression::OperatorType::Power:
stream << "("; stream << "(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << "^"; stream << "^";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryNumericalFunctionExpression::OperatorType::Max: case BinaryNumericalFunctionExpression::OperatorType::Max:
stream << "max("; stream << "max(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << ","; stream << ",";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryNumericalFunctionExpression::OperatorType::Min: case BinaryNumericalFunctionExpression::OperatorType::Min:
stream << "min("; stream << "min(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << ","; stream << ",";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
} }
return boost::any(); return boost::any();
} }
boost::any ToExprtkStringVisitor::visit(BinaryRelationExpression const& expression) { boost::any ToExprtkStringVisitor::visit(BinaryRelationExpression const& expression, boost::any const& data) {
switch (expression.getRelationType()) { switch (expression.getRelationType()) {
case BinaryRelationExpression::RelationType::Equal: case BinaryRelationExpression::RelationType::Equal:
stream << "("; stream << "(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << "=="; stream << "==";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryRelationExpression::RelationType::NotEqual: case BinaryRelationExpression::RelationType::NotEqual:
stream << "("; stream << "(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << "!="; stream << "!=";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryRelationExpression::RelationType::Less: case BinaryRelationExpression::RelationType::Less:
stream << "("; stream << "(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << "<"; stream << "<";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryRelationExpression::RelationType::LessOrEqual: case BinaryRelationExpression::RelationType::LessOrEqual:
stream << "("; stream << "(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << "<="; stream << "<=";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryRelationExpression::RelationType::Greater: case BinaryRelationExpression::RelationType::Greater:
stream << "("; stream << "(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << ">"; stream << ">";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case BinaryRelationExpression::RelationType::GreaterOrEqual: case BinaryRelationExpression::RelationType::GreaterOrEqual:
stream << "("; stream << "(";
expression.getFirstOperand()->accept(*this); expression.getFirstOperand()->accept(*this, data);
stream << ">="; stream << ">=";
expression.getSecondOperand()->accept(*this); expression.getSecondOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
} }
return boost::any(); return boost::any();
} }
boost::any ToExprtkStringVisitor::visit(VariableExpression const& expression) { boost::any ToExprtkStringVisitor::visit(VariableExpression const& expression, boost::any const& data) {
stream << expression.getVariableName(); stream << expression.getVariableName();
return boost::any(); return boost::any();
} }
boost::any ToExprtkStringVisitor::visit(UnaryBooleanFunctionExpression const& expression) { boost::any ToExprtkStringVisitor::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
switch (expression.getOperatorType()) { switch (expression.getOperatorType()) {
case UnaryBooleanFunctionExpression::OperatorType::Not: case UnaryBooleanFunctionExpression::OperatorType::Not:
stream << "not("; stream << "not(";
expression.getOperand()->accept(*this); expression.getOperand()->accept(*this, data);
stream << ")"; stream << ")";
} }
return boost::any(); return boost::any();
} }
boost::any ToExprtkStringVisitor::visit(UnaryNumericalFunctionExpression const& expression) { boost::any ToExprtkStringVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
switch (expression.getOperatorType()) { switch (expression.getOperatorType()) {
case UnaryNumericalFunctionExpression::OperatorType::Minus: case UnaryNumericalFunctionExpression::OperatorType::Minus:
stream << "-("; stream << "-(";
expression.getOperand()->accept(*this); expression.getOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case UnaryNumericalFunctionExpression::OperatorType::Floor: case UnaryNumericalFunctionExpression::OperatorType::Floor:
stream << "floor("; stream << "floor(";
expression.getOperand()->accept(*this); expression.getOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
case UnaryNumericalFunctionExpression::OperatorType::Ceil: case UnaryNumericalFunctionExpression::OperatorType::Ceil:
stream << "ceil("; stream << "ceil(";
expression.getOperand()->accept(*this); expression.getOperand()->accept(*this, data);
stream << ")"; stream << ")";
break; break;
} }
return boost::any(); return boost::any();
} }
boost::any ToExprtkStringVisitor::visit(BooleanLiteralExpression const& expression) { boost::any ToExprtkStringVisitor::visit(BooleanLiteralExpression const& expression, boost::any const& data) {
stream << expression.getValue(); stream << expression.getValue();
return boost::any(); return boost::any();
} }
boost::any ToExprtkStringVisitor::visit(IntegerLiteralExpression const& expression) { boost::any ToExprtkStringVisitor::visit(IntegerLiteralExpression const& expression, boost::any const& data) {
stream << expression.getValue(); stream << expression.getValue();
return boost::any(); return boost::any();
} }
boost::any ToExprtkStringVisitor::visit(DoubleLiteralExpression const& expression) { boost::any ToExprtkStringVisitor::visit(RationalLiteralExpression const& expression, boost::any const& data) {
stream << expression.getValue(); stream << expression.getValue();
return boost::any(); return boost::any();
} }

20
src/storage/expressions/ToExprtkStringVisitor.h

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

35
src/storage/expressions/ToRationalFunctionVisitor.cpp

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

20
src/storage/expressions/ToRationalFunctionVisitor.h

@ -18,16 +18,16 @@ namespace storm {
RationalFunctionType toRationalFunction(Expression const& expression); RationalFunctionType toRationalFunction(Expression const& expression);
virtual boost::any visit(IfThenElseExpression const& expression) override; virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override; virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryRelationExpression const& expression) override; virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
virtual boost::any visit(VariableExpression const& expression) override; virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override; virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override; virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
private: private:
template<typename TP = typename RationalFunctionType::PolyType, carl::EnableIf<carl::needs_cache<TP>> = carl::dummy> 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/storage/expressions/ToRationalNumberVisitor.h"
#include "src/utility/macros.h" #include "src/utility/macros.h"
#include "src/utility/constants.h"
#include "src/exceptions/InvalidArgumentException.h" #include "src/exceptions/InvalidArgumentException.h"
#include "src/exceptions/NotSupportedException.h" #include "src/exceptions/NotSupportedException.h"
@ -13,71 +14,81 @@ namespace storm {
template<typename RationalNumberType> template<typename RationalNumberType>
RationalNumberType ToRationalNumberVisitor<RationalNumberType>::toRationalNumber(Expression const& expression) { 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> 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."); STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
} }
template<typename RationalNumberType> 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."); STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
} }
template<typename RationalNumberType> template<typename RationalNumberType>
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryNumericalFunctionExpression const& expression) { boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
RationalNumberType firstOperandAsRationalFunction = boost::any_cast<RationalNumberType>(expression.getFirstOperand()->accept(*this)); RationalNumberType firstOperandAsRationalNumber = boost::any_cast<RationalNumberType>(expression.getFirstOperand()->accept(*this, data));
RationalNumberType secondOperandAsRationalFunction = boost::any_cast<RationalNumberType>(expression.getSecondOperand()->accept(*this)); RationalNumberType secondOperandAsRationalNumber = boost::any_cast<RationalNumberType>(expression.getSecondOperand()->accept(*this, data));
switch(expression.getOperatorType()) { switch(expression.getOperatorType()) {
case BinaryNumericalFunctionExpression::OperatorType::Plus: case BinaryNumericalFunctionExpression::OperatorType::Plus:
return firstOperandAsRationalFunction + secondOperandAsRationalFunction; return firstOperandAsRationalNumber + secondOperandAsRationalNumber;
break; break;
case BinaryNumericalFunctionExpression::OperatorType::Minus: case BinaryNumericalFunctionExpression::OperatorType::Minus:
return firstOperandAsRationalFunction - secondOperandAsRationalFunction; return firstOperandAsRationalNumber - secondOperandAsRationalNumber;
break; break;
case BinaryNumericalFunctionExpression::OperatorType::Times: case BinaryNumericalFunctionExpression::OperatorType::Times:
return firstOperandAsRationalFunction * secondOperandAsRationalFunction; return firstOperandAsRationalNumber * secondOperandAsRationalNumber;
break; break;
case BinaryNumericalFunctionExpression::OperatorType::Divide: 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; break;
default:
STORM_LOG_ASSERT(false, "Illegal operator type.");
} }
// Return a dummy. This point must, however, never be reached. // Return a dummy. This point must, however, never be reached.
STORM_LOG_ASSERT(false, "Illegal operator type.");
return boost::any(); return boost::any();
} }
template<typename RationalNumberType> 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."); STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
} }
template<typename RationalNumberType> 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."); STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot transform expressions containing variables to a rational number.");
} }
template<typename RationalNumberType> 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."); STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
} }
template<typename RationalNumberType> 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."); STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
} }
template<typename RationalNumberType> 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."); STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
} }
template<typename RationalNumberType> 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 #ifdef STORM_HAVE_CARL
return RationalNumberType(carl::rationalize<storm::RationalNumber>(static_cast<size_t>(expression.getValue()))); return RationalNumberType(carl::rationalize<storm::RationalNumber>(static_cast<size_t>(expression.getValue())));
#else #else
@ -86,9 +97,9 @@ namespace storm {
} }
template<typename RationalNumberType> 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 #ifdef STORM_HAVE_CARL
return RationalNumberType(carl::rationalize<storm::RationalNumber>(expression.getValue())); return expression.getValue();
#else #else
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Rational numbers are not supported in this build."); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Rational numbers are not supported in this build.");
#endif #endif

20
src/storage/expressions/ToRationalNumberVisitor.h

@ -16,16 +16,16 @@ namespace storm {
RationalNumberType toRationalNumber(Expression const& expression); RationalNumberType toRationalNumber(Expression const& expression);
virtual boost::any visit(IfThenElseExpression const& expression) override; virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override; virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryRelationExpression const& expression) override; virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
virtual boost::any visit(VariableExpression const& expression) override; virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override; virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) 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 { boost::any UnaryBooleanFunctionExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this); return visitor.visit(*this, data);
} }
void UnaryBooleanFunctionExpression::printToStream(std::ostream& stream) const { 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 storm::expressions::OperatorType getOperator() const override;
virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override; virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() 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. * 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/UnaryNumericalFunctionExpression.h"
#include "src/storage/expressions/IntegerLiteralExpression.h" #include "src/storage/expressions/IntegerLiteralExpression.h"
#include "src/storage/expressions/DoubleLiteralExpression.h" #include "src/storage/expressions/RationalLiteralExpression.h"
#include "ExpressionVisitor.h" #include "ExpressionVisitor.h"
#include "src/utility/macros.h" #include "src/utility/macros.h"
#include "src/exceptions/InvalidTypeException.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::Floor: value = std::floor(boost::get<double>(operandEvaluation)); break;
case OperatorType::Ceil: value = std::ceil(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 { boost::any UnaryNumericalFunctionExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this); return visitor.visit(*this, data);
} }
void UnaryNumericalFunctionExpression::printToStream(std::ostream& stream) const { 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 int_fast64_t evaluateAsInt(Valuation const* valuation = nullptr) const override;
virtual double evaluateAsDouble(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 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. * Retrieves the operator associated with this expression.

4
src/storage/expressions/VariableExpression.cpp

@ -63,8 +63,8 @@ namespace storm {
return this->shared_from_this(); return this->shared_from_this();
} }
boost::any VariableExpression::accept(ExpressionVisitor& visitor) const { boost::any VariableExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this); return visitor.visit(*this, data);
} }
void VariableExpression::printToStream(std::ostream& stream) const { 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 bool isVariable() const override;
virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override; virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override;
virtual std::shared_ptr<BaseExpression const> simplify() 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. * 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/storage/jani/Assignment.h"
#include "src/utility/macros.h"
#include "src/exceptions/NotImplementedException.h"
namespace storm { namespace storm {
namespace jani { namespace jani {
Assignment::Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression) : variable(variable), expression(expression) { Assignment::Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression, uint64_t level) : variable(variable), expression(expression), level(level) {
// Intentionally left empty. 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 { storm::jani::Variable const& Assignment::getVariable() const {
@ -23,8 +31,16 @@ namespace storm {
this->expression = expression; this->expression = expression;
} }
bool Assignment::isTransientAssignment() const { bool Assignment::isTransient() const {
return this->variable.get().isTransientVariable(); 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) { std::ostream& operator<<(std::ostream& stream, Assignment const& assignment) {
@ -32,5 +48,20 @@ namespace storm {
return stream; 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. * 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. * Retrieves the expression variable that is written in this assignment.
@ -35,10 +37,20 @@ namespace storm {
*/ */
void setAssignedExpression(storm::expressions::Expression const& expression); 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. * 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); 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. // The expression that is being assigned to the variable.
storm::expressions::Expression expression; 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) { Variable const& Automaton::addVariable(Variable const &variable) {
if (variable.isBooleanVariable()) { if (variable.isBooleanVariable()) {
return addBooleanVariable(variable.asBooleanVariable()); return addVariable(variable.asBooleanVariable());
} else if (variable.isBoundedIntegerVariable()) { } else if (variable.isBoundedIntegerVariable()) {
return addBoundedIntegerVariable(variable.asBoundedIntegerVariable()); return addVariable(variable.asBoundedIntegerVariable());
} else if (variable.isUnboundedIntegerVariable()) { } else if (variable.isUnboundedIntegerVariable()) {
return addUnboundedIntegerVariable(variable.asUnboundedIntegerVariable()); return addVariable(variable.asUnboundedIntegerVariable());
} else if (variable.isRealVariable()) {
return addVariable(variable.asRealVariable());
} else { } else {
STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Variable has invalid type."); STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Variable has invalid type.");
} }
} }
BooleanVariable const& Automaton::addBooleanVariable(BooleanVariable const& variable) { BooleanVariable const& Automaton::addVariable(BooleanVariable const& variable) {
return variables.addBooleanVariable(variable); return variables.addVariable(variable);
} }
BoundedIntegerVariable const& Automaton::addBoundedIntegerVariable(BoundedIntegerVariable const& variable) { BoundedIntegerVariable const& Automaton::addVariable(BoundedIntegerVariable const& variable) {
return variables.addBoundedIntegerVariable(variable); return variables.addVariable(variable);
} }
UnboundedIntegerVariable const& Automaton::addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable) { UnboundedIntegerVariable const& Automaton::addVariable(UnboundedIntegerVariable const& variable) {
return variables.addUnboundedIntegerVariable(variable); return variables.addVariable(variable);
}
RealVariable const& Automaton::addVariable(RealVariable const& variable) {
return variables.addVariable(variable);
} }
VariableSet& Automaton::getVariables() { VariableSet& Automaton::getVariables() {
@ -91,6 +97,10 @@ namespace storm {
return variables; return variables;
} }
bool Automaton::hasTransientVariable() const {
return variables.hasTransientVariable();
}
bool Automaton::hasLocation(std::string const& name) const { bool Automaton::hasLocation(std::string const& name) const {
return locationToIndex.find(name) != locationToIndex.end(); return locationToIndex.find(name) != locationToIndex.end();
} }
@ -98,11 +108,19 @@ namespace storm {
std::vector<Location> const& Automaton::getLocations() const { std::vector<Location> const& Automaton::getLocations() const {
return locations; return locations;
} }
std::vector<Location>& Automaton::getLocations() {
return locations;
}
Location const& Automaton::getLocation(uint64_t index) const { Location const& Automaton::getLocation(uint64_t index) const {
return locations[index]; return locations[index];
} }
Location& Automaton::getLocation(uint64_t index) {
return locations[index];
}
uint64_t Automaton::addLocation(Location const& location) { 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."); 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()); locationToIndex.emplace(location.getName(), locations.size());
@ -352,6 +370,22 @@ namespace storm {
return result; 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) { void Automaton::finalize(Model const& containingModel) {
for (auto& edge : edges) { for (auto& edge : edges) {
edge.finalize(containingModel); edge.finalize(containingModel);

33
src/storage/jani/Automaton.h

@ -108,17 +108,22 @@ namespace storm {
/*! /*!
* Adds the given Boolean variable to this automaton. * 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. * 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. * 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. * Retrieves the variables of this automaton.
@ -130,6 +135,11 @@ namespace storm {
*/ */
VariableSet const& getVariables() const; 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. * Retrieves whether the automaton has a location with the given name.
*/ */
@ -147,12 +157,22 @@ namespace storm {
* Retrieves the locations of the automaton. * Retrieves the locations of the automaton.
*/ */
std::vector<Location> const& getLocations() const; std::vector<Location> const& getLocations() const;
/*!
* Retrieves the locations of the automaton.
*/
std::vector<Location>& getLocations();
/*! /*!
* Retrieves the location with the given index. * Retrieves the location with the given index.
*/ */
Location const& getLocation(uint64_t index) const; 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. * Adds the given location to the automaton.
*/ */
@ -263,6 +283,11 @@ namespace storm {
*/ */
std::vector<storm::expressions::Expression> getAllRangeExpressions() const; 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 * 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. * 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. // Intentionally left empty.
} }
bool BooleanVariable::isBooleanVariable() const { bool BooleanVariable::isBooleanVariable() const {
return true; 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; 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. // Intentionally left empty.
} }
storm::expressions::Expression const& BoundedIntegerVariable::getLowerBound() const { storm::expressions::Expression const& BoundedIntegerVariable::getLowerBound() const {
return lowerBound; return lowerBound;
} }
@ -46,11 +45,15 @@ namespace storm {
return true; 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) { 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");
STORM_LOG_THROW(lowerBound && upperBound, storm::exceptions::NotImplementedException, "Jani Bounded Integer variables (for now) have to be bounded from both sides"); if (initValue) {
}
if(initValue) {
return std::make_shared<BoundedIntegerVariable>(name, variable, initValue.get(), transient, lowerBound.get(), upperBound.get()); return std::make_shared<BoundedIntegerVariable>(name, variable, initValue.get(), transient, lowerBound.get(), upperBound.get());
} else { } else {
return std::make_shared<BoundedIntegerVariable>(name, variable, transient, lowerBound.get(), upperBound.get()); 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; 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: private:
// The expression defining the lower bound of the variable. // The expression defining the lower bound of the variable.
storm::expressions::Expression lowerBound; 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); 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/storage/jani/Model.h"
#include "src/utility/macros.h"
#include "src/exceptions/InvalidArgumentException.h"
namespace storm { namespace storm {
namespace jani { 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. // Intentionally left empty.
} }
@ -49,6 +52,23 @@ namespace storm {
destinations.push_back(destination); 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) { void Edge::finalize(Model const& containingModel) {
for (auto const& destination : getDestinations()) { for (auto const& destination : getDestinations()) {
for (auto const& assignment : destination.getAssignments()) { 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 { boost::container::flat_set<storm::expressions::Variable> const& Edge::getWrittenGlobalVariables() const {
return writtenGlobalVariables; return writtenGlobalVariables;
} }

28
src/storage/jani/Edge.h

@ -4,6 +4,7 @@
#include <boost/container/flat_set.hpp> #include <boost/container/flat_set.hpp>
#include "src/storage/jani/EdgeDestination.h" #include "src/storage/jani/EdgeDestination.h"
#include "src/storage/jani/OrderedAssignments.h"
namespace storm { namespace storm {
namespace jani { namespace jani {
@ -64,6 +65,11 @@ namespace storm {
*/ */
void addDestination(EdgeDestination const& destination); 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 * 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. * 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. * that prior to calling this, the edge has to be finalized.
*/ */
boost::container::flat_set<storm::expressions::Variable> const& getWrittenGlobalVariables() const; 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: private:
/// The index of the source location. /// The index of the source location.
@ -93,6 +118,9 @@ namespace storm {
/// The destinations of this edge. /// The destinations of this edge.
std::vector<EdgeDestination> destinations; 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 /// 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>. /// initialized by the call to <code>finalize</code>.
boost::container::flat_set<storm::expressions::Variable> writtenGlobalVariables; boost::container::flat_set<storm::expressions::Variable> writtenGlobalVariables;

63
src/storage/jani/EdgeDestination.cpp

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

45
src/storage/jani/EdgeDestination.h

@ -4,7 +4,7 @@
#include "src/storage/expressions/Expression.h" #include "src/storage/expressions/Expression.h"
#include "src/storage/jani/Assignment.h" #include "src/storage/jani/OrderedAssignments.h"
namespace storm { namespace storm {
namespace jani { namespace jani {
@ -39,55 +39,36 @@ namespace storm {
/*! /*!
* Retrieves the assignments to make when choosing this destination. * 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. * Retrieves the transient assignments to make when choosing this destination.
*/
std::vector<Assignment> const& getAssignments() const;
/*!
* Retrieves the non-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. * 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);
/*! // Convenience methods to access the assignments.
* Retrieves the non-transient assignments to make when choosing this destination. bool hasAssignment(Assignment const& assignment) const;
*/ bool removeAssignment(Assignment const& assignment);
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);
private:
// The index of the destination location. // The index of the destination location.
uint64_t locationIndex; uint64_t locationIndex;
// The probability to go to the destination. // The probability to go to the destination.
storm::expressions::Expression probability; storm::expressions::Expression probability;
// The assignments to make when choosing this destination. // The (ordered) assignments to make when choosing this destination.
std::vector<Assignment> assignments; OrderedAssignments 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;
}; };
} }

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/Location.h"
#include "src/storage/jani/Assignment.h"
#include "src/exceptions/InvalidJaniException.h"
#include "src/utility/macros.h" #include "src/utility/macros.h"
#include "src/exceptions/InvalidJaniException.h"
#include "src/exceptions/InvalidArgumentException.h"
namespace storm { namespace storm {
namespace jani { 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. // Intentionally left empty.
} }
@ -14,15 +15,24 @@ namespace storm {
return name; return name;
} }
std::vector<Assignment> const& Location::getTransientAssignments() const { OrderedAssignments const& Location::getAssignments() const {
return transientAssignments; return assignments;
} }
void Location::checkValid() const { void Location::addTransientAssignment(storm::jani::Assignment const& assignment) {
for(auto const& assignment : transientAssignments) { STORM_LOG_THROW(assignment.isTransient(), storm::exceptions::InvalidArgumentException, "Must not add non-transient assignment to location.");
STORM_LOG_THROW(assignment.isTransientAssignment(), storm::exceptions::InvalidJaniException, "Only transient assignments are allowed in locations."); 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 #pragma once
#include <string> #include <string>
#include <vector> #include "src/storage/jani/OrderedAssignments.h"
#include "src/storage/jani/Assignment.h"
namespace storm { namespace storm {
namespace jani { namespace jani {
@ -25,9 +25,19 @@ namespace storm {
std::string const& getName() const; 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. * 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; std::string name;
/// The transient assignments made in this location. /// 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)); silentActionIndex = addAction(storm::jani::Action(SILENT_ACTION_NAME));
} }
storm::expressions::ExpressionManager& Model::getManager() const {
return *expressionManager;
}
uint64_t Model::getJaniVersion() const { uint64_t Model::getJaniVersion() const {
return version; return version;
} }
@ -104,29 +108,35 @@ namespace storm {
std::vector<Constant>& Model::getConstants() { std::vector<Constant>& Model::getConstants() {
return constants; return constants;
} }
Variable const& Model::addVariable(Variable const& variable) { Variable const& Model::addVariable(Variable const& variable) {
if (variable.isBooleanVariable()) { if (variable.isBooleanVariable()) {
return addBooleanVariable(variable.asBooleanVariable()); return addVariable(variable.asBooleanVariable());
} else if (variable.isBoundedIntegerVariable()) { } else if (variable.isBoundedIntegerVariable()) {
return addBoundedIntegerVariable(variable.asBoundedIntegerVariable()); return addVariable(variable.asBoundedIntegerVariable());
} else if (variable.isUnboundedIntegerVariable()) { } else if (variable.isUnboundedIntegerVariable()) {
return addUnboundedIntegerVariable(variable.asUnboundedIntegerVariable()); return addVariable(variable.asUnboundedIntegerVariable());
} else if (variable.isRealVariable()) {
return addVariable(variable.asRealVariable());
} else { } else {
STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Variable has invalid type."); STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Variable has invalid type.");
} }
} }
BooleanVariable const& Model::addBooleanVariable(BooleanVariable const& variable) { BooleanVariable const& Model::addVariable(BooleanVariable const& variable) {
return globalVariables.addBooleanVariable(variable); return globalVariables.addVariable(variable);
} }
BoundedIntegerVariable const& Model::addBoundedIntegerVariable(BoundedIntegerVariable const& variable) { BoundedIntegerVariable const& Model::addVariable(BoundedIntegerVariable const& variable) {
return globalVariables.addBoundedIntegerVariable(variable); return globalVariables.addVariable(variable);
} }
UnboundedIntegerVariable const& Model::addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable) { UnboundedIntegerVariable const& Model::addVariable(UnboundedIntegerVariable const& variable) {
return globalVariables.addUnboundedIntegerVariable(variable); return globalVariables.addVariable(variable);
}
RealVariable const& Model::addVariable(RealVariable const& variable) {
return globalVariables.addVariable(variable);
} }
VariableSet& Model::getGlobalVariables() { VariableSet& Model::getGlobalVariables() {
@ -137,6 +147,23 @@ namespace storm {
return globalVariables; 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() { storm::expressions::ExpressionManager& Model::getExpressionManager() {
return *expressionManager; return *expressionManager;
} }
@ -173,6 +200,12 @@ namespace storm {
return automata[it->second]; 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 { std::size_t Model::getNumberOfAutomata() const {
return automata.size(); return automata.size();
} }
@ -304,9 +337,7 @@ namespace storm {
// Substitute constants in all global variables. // Substitute constants in all global variables.
for (auto& variable : result.getGlobalVariables().getBoundedIntegerVariables()) { for (auto& variable : result.getGlobalVariables().getBoundedIntegerVariables()) {
variable.setInitExpression(variable.getInitExpression().substitute(constantSubstitution)); variable.substitute(constantSubstitution);
variable.setLowerBound(variable.getLowerBound().substitute(constantSubstitution));
variable.setUpperBound(variable.getUpperBound().substitute(constantSubstitution));
} }
// Substitute constants in initial states expression. // Substitute constants in initial states expression.
@ -314,26 +345,7 @@ namespace storm {
// Substitute constants in variables of automata and their edges. // Substitute constants in variables of automata and their edges.
for (auto& automaton : result.getAutomata()) { for (auto& automaton : result.getAutomata()) {
for (auto& variable : automaton.getVariables().getBoundedIntegerVariables()) { automaton.substitute(constantSubstitution);
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));
}
}
}
} }
return result; return result;

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

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