Browse Source

Merge remote-tracking branch 'origin/future' into jani_support

Former-commit-id: 2c2c57e103 [formerly 8d725b4d90]
Former-commit-id: 918275a8c7
main
dehnert 9 years ago
parent
commit
71f99eb075
  1. 2
      resources/3rdparty/CMakeLists.txt
  2. 4
      src/adapters/AddExpressionAdapter.cpp
  3. 2
      src/adapters/AddExpressionAdapter.h
  4. 4
      src/adapters/MathsatExpressionAdapter.h
  5. 4
      src/adapters/Z3ExpressionAdapter.cpp
  6. 2
      src/adapters/Z3ExpressionAdapter.h
  7. 2
      src/builder/DdPrismModelBuilder.cpp
  8. 2
      src/counterexamples/SMTMinimalCommandSetGenerator.h
  9. 3
      src/generator/JaniNextStateGenerator.cpp
  10. 11
      src/generator/PrismNextStateGenerator.cpp
  11. 1
      src/modelchecker/AbstractModelChecker.cpp
  12. 32
      src/parser/ExpressionParser.cpp
  13. 16
      src/parser/ExpressionParser.h
  14. 3
      src/parser/JaniParser.h
  15. 20
      src/parser/PrismParser.cpp
  16. 6
      src/parser/PrismParser.h
  17. 5
      src/settings/modules/CoreSettings.cpp
  18. 1
      src/settings/modules/CoreSettings.h
  19. 4
      src/storage/expressions/BinaryNumericalFunctionExpression.cpp
  20. 39
      src/storage/expressions/DoubleLiteralExpression.cpp
  21. 53
      src/storage/expressions/DoubleLiteralExpression.h
  22. 6
      src/storage/expressions/ExpressionManager.cpp
  23. 9
      src/storage/expressions/ExpressionManager.h
  24. 4
      src/storage/expressions/ExpressionVisitor.h
  25. 2
      src/storage/expressions/Expressions.h
  26. 4
      src/storage/expressions/LinearCoefficientVisitor.cpp
  27. 2
      src/storage/expressions/LinearCoefficientVisitor.h
  28. 2
      src/storage/expressions/LinearityCheckVisitor.cpp
  29. 2
      src/storage/expressions/LinearityCheckVisitor.h
  30. 53
      src/storage/expressions/RationalLiteralExpression.cpp
  31. 78
      src/storage/expressions/RationalLiteralExpression.h
  32. 2
      src/storage/expressions/SubstitutionVisitor.cpp
  33. 2
      src/storage/expressions/SubstitutionVisitor.h
  34. 2
      src/storage/expressions/ToExprtkStringVisitor.cpp
  35. 2
      src/storage/expressions/ToExprtkStringVisitor.h
  36. 11
      src/storage/expressions/ToRationalFunctionVisitor.cpp
  37. 2
      src/storage/expressions/ToRationalFunctionVisitor.h
  38. 31
      src/storage/expressions/ToRationalNumberVisitor.cpp
  39. 2
      src/storage/expressions/ToRationalNumberVisitor.h
  40. 4
      src/storage/expressions/UnaryNumericalFunctionExpression.cpp
  41. 9
      src/storage/jani/BooleanVariable.cpp
  42. 5
      src/storage/jani/BooleanVariable.h
  43. 6
      src/storage/jani/BoundedIntegerVariable.cpp
  44. 2
      src/storage/jani/BoundedIntegerVariable.h
  45. 1
      src/storage/jani/UnboundedIntegerVariable.h
  46. 16
      src/storage/prism/BooleanVariable.cpp
  47. 2
      src/storage/prism/BooleanVariable.h
  48. 7
      src/storage/prism/Constant.cpp
  49. 14
      src/storage/prism/IntegerVariable.cpp
  50. 2
      src/storage/prism/IntegerVariable.h
  51. 20
      src/storage/prism/Module.cpp
  52. 6
      src/storage/prism/Module.h
  53. 379
      src/storage/prism/Program.cpp
  54. 36
      src/storage/prism/Program.h
  55. 18
      src/storage/prism/RewardModel.cpp
  56. 9
      src/storage/prism/RewardModel.h
  57. 12
      src/storage/prism/Variable.cpp
  58. 27
      src/storage/prism/Variable.h
  59. 13
      src/storm.cpp
  60. 72
      src/utility/constants.cpp
  61. 3
      src/utility/constants.h
  62. 2
      src/utility/storm.cpp
  63. 4
      src/utility/storm.h
  64. 4
      test/functional/parser/PrismParserTest.cpp
  65. 10
      util/osx-package/package.sh
  66. 103
      util/osx-package/packager.py

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)

4
src/adapters/AddExpressionAdapter.cpp

@ -194,8 +194,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::DoubleLiteralExpression const& expression) { boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::RationalLiteralExpression const& expression) {
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

2
src/adapters/AddExpressionAdapter.h

@ -31,7 +31,7 @@ namespace storm {
virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression) override; virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression) override;
virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression) override; virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression) override;
virtual boost::any visit(storm::expressions::DoubleLiteralExpression const& expression) override; virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression) override;
private: private:
// The manager responsible for the DDs built by this adapter. // The manager responsible for the DDs built by this adapter.

4
src/adapters/MathsatExpressionAdapter.h

@ -171,8 +171,8 @@ namespace storm {
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(expressions::RationalLiteralExpression const& expression) 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(expressions::IntegerLiteralExpression const& expression) override {

4
src/adapters/Z3ExpressionAdapter.cpp

@ -177,6 +177,8 @@ 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 << ".");
} }
@ -208,7 +210,7 @@ namespace storm {
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) {
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());

2
src/adapters/Z3ExpressionAdapter.h

@ -63,7 +63,7 @@ namespace storm {
virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression) override; virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression) override;
virtual boost::any visit(storm::expressions::DoubleLiteralExpression const& expression) override; virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression) override;
virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression) override; virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression) override;

2
src/builder/DdPrismModelBuilder.cpp

@ -1415,7 +1415,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);

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;

3
src/generator/JaniNextStateGenerator.cpp

@ -161,6 +161,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);
} }

11
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);
@ -136,7 +137,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 +167,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 +318,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 +449,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);

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"

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;

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

4
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));
} }
} }

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_ */

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.

4
src/storage/expressions/ExpressionVisitor.h

@ -15,7 +15,7 @@ namespace storm {
class UnaryNumericalFunctionExpression; class UnaryNumericalFunctionExpression;
class BooleanLiteralExpression; class BooleanLiteralExpression;
class IntegerLiteralExpression; class IntegerLiteralExpression;
class DoubleLiteralExpression; class RationalLiteralExpression;
class ExpressionVisitor { class ExpressionVisitor {
public: public:
@ -28,7 +28,7 @@ namespace storm {
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) = 0; virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) = 0;
virtual boost::any visit(BooleanLiteralExpression const& expression) = 0; virtual boost::any visit(BooleanLiteralExpression const& expression) = 0;
virtual boost::any visit(IntegerLiteralExpression const& expression) = 0; virtual boost::any visit(IntegerLiteralExpression const& expression) = 0;
virtual boost::any visit(DoubleLiteralExpression const& expression) = 0; virtual boost::any visit(RationalLiteralExpression const& expression) = 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/LinearCoefficientVisitor.cpp

@ -151,8 +151,8 @@ namespace storm {
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) {
return VariableCoefficients(expression.getValue()); return VariableCoefficients(expression.getValueAsDouble());
} }
} }
} }

2
src/storage/expressions/LinearCoefficientVisitor.h

@ -75,7 +75,7 @@ namespace storm {
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override; virtual boost::any visit(RationalLiteralExpression const& expression) override;
}; };
} }
} }

2
src/storage/expressions/LinearityCheckVisitor.cpp

@ -85,7 +85,7 @@ namespace storm {
return LinearityStatus::LinearWithoutVariables; return LinearityStatus::LinearWithoutVariables;
} }
boost::any LinearityCheckVisitor::visit(DoubleLiteralExpression const& expression) { boost::any LinearityCheckVisitor::visit(RationalLiteralExpression const& expression) {
return LinearityStatus::LinearWithoutVariables; return LinearityStatus::LinearWithoutVariables;
} }
} }

2
src/storage/expressions/LinearityCheckVisitor.h

@ -29,7 +29,7 @@ namespace storm {
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override; virtual boost::any visit(RationalLiteralExpression const& expression) 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) const {
return visitor.visit(*this);
}
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) 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_ */

2
src/storage/expressions/SubstitutionVisitor.cpp

@ -116,7 +116,7 @@ namespace storm {
} }
template<typename MapType> template<typename MapType>
boost::any SubstitutionVisitor<MapType>::visit(DoubleLiteralExpression const& expression) { boost::any SubstitutionVisitor<MapType>::visit(RationalLiteralExpression const& expression) {
return expression.getSharedPointer(); return expression.getSharedPointer();
} }

2
src/storage/expressions/SubstitutionVisitor.h

@ -37,7 +37,7 @@ namespace storm {
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override; virtual boost::any visit(RationalLiteralExpression const& expression) 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.

2
src/storage/expressions/ToExprtkStringVisitor.cpp

@ -212,7 +212,7 @@ namespace storm {
return boost::any(); return boost::any();
} }
boost::any ToExprtkStringVisitor::visit(DoubleLiteralExpression const& expression) { boost::any ToExprtkStringVisitor::visit(RationalLiteralExpression const& expression) {
stream << expression.getValue(); stream << expression.getValue();
return boost::any(); return boost::any();
} }

2
src/storage/expressions/ToExprtkStringVisitor.h

@ -25,7 +25,7 @@ namespace storm {
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override; virtual boost::any visit(RationalLiteralExpression const& expression) override;
private: private:
std::stringstream stream; std::stringstream stream;

11
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"
@ -33,6 +34,7 @@ namespace storm {
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryNumericalFunctionExpression const& expression) { boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryNumericalFunctionExpression const& expression) {
RationalFunctionType firstOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getFirstOperand()->accept(*this)); RationalFunctionType firstOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getFirstOperand()->accept(*this));
RationalFunctionType secondOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getSecondOperand()->accept(*this)); RationalFunctionType secondOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getSecondOperand()->accept(*this));
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.");
} }
@ -92,8 +99,8 @@ namespace storm {
} }
template<typename RationalFunctionType> template<typename RationalFunctionType>
boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(DoubleLiteralExpression const& expression) { boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(RationalLiteralExpression const& expression) {
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>;

2
src/storage/expressions/ToRationalFunctionVisitor.h

@ -27,7 +27,7 @@ namespace storm {
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override; virtual boost::any visit(RationalLiteralExpression const& expression) 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>

31
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"
@ -28,26 +29,36 @@ namespace storm {
template<typename RationalNumberType> template<typename RationalNumberType>
boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryNumericalFunctionExpression const& expression) { boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryNumericalFunctionExpression const& expression) {
RationalNumberType firstOperandAsRationalFunction = boost::any_cast<RationalNumberType>(expression.getFirstOperand()->accept(*this)); RationalNumberType firstOperandAsRationalNumber = boost::any_cast<RationalNumberType>(expression.getFirstOperand()->accept(*this));
RationalNumberType secondOperandAsRationalFunction = boost::any_cast<RationalNumberType>(expression.getSecondOperand()->accept(*this)); RationalNumberType secondOperandAsRationalNumber = boost::any_cast<RationalNumberType>(expression.getSecondOperand()->accept(*this));
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();
} }
@ -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) {
#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

2
src/storage/expressions/ToRationalNumberVisitor.h

@ -25,7 +25,7 @@ namespace storm {
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override;
virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression) override;
virtual boost::any visit(IntegerLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression) override;
virtual boost::any visit(DoubleLiteralExpression const& expression) override; virtual boost::any visit(RationalLiteralExpression const& expression) override;
}; };
} }
} }

4
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));
} }
} }

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);
} }
} }

6
src/storage/jani/BoundedIntegerVariable.cpp

@ -47,10 +47,8 @@ namespace storm {
} }
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());

2
src/storage/jani/BoundedIntegerVariable.h

@ -61,7 +61,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);
} }

1
src/storage/jani/UnboundedIntegerVariable.h

@ -15,7 +15,6 @@ namespace storm {
* Creates an unbounded integer variable with initial value. * Creates an unbounded integer variable with initial value.
*/ */
UnboundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, storm::expressions::Expression const&, bool transient=false); UnboundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, storm::expressions::Expression const&, bool transient=false);
virtual bool isUnboundedIntegerVariable() const override; virtual bool isUnboundedIntegerVariable() const override;
}; };

16
src/storage/prism/BooleanVariable.cpp

@ -1,5 +1,7 @@
#include "src/storage/prism/BooleanVariable.h" #include "src/storage/prism/BooleanVariable.h"
#include "src/storage/expressions/ExpressionManager.h"
namespace storm { namespace storm {
namespace prism { namespace prism {
BooleanVariable::BooleanVariable(storm::expressions::Variable const& variable, storm::expressions::Expression const& initialValueExpression, std::string const& filename, uint_fast64_t lineNumber) : Variable(variable, initialValueExpression, false, filename, lineNumber) { BooleanVariable::BooleanVariable(storm::expressions::Variable const& variable, storm::expressions::Expression const& initialValueExpression, std::string const& filename, uint_fast64_t lineNumber) : Variable(variable, initialValueExpression, false, filename, lineNumber) {
@ -7,11 +9,21 @@ namespace storm {
} }
BooleanVariable BooleanVariable::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const { BooleanVariable BooleanVariable::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const {
return BooleanVariable(this->getExpressionVariable(), this->getInitialValueExpression().substitute(substitution), this->getFilename(), this->getLineNumber()); return BooleanVariable(this->getExpressionVariable(), this->getInitialValueExpression().isInitialized() ? this->getInitialValueExpression().substitute(substitution) : this->getInitialValueExpression(), this->getFilename(), this->getLineNumber());
}
void BooleanVariable::createMissingInitialValue() {
if (!this->hasInitialValue()) {
this->setInitialValueExpression(this->getExpressionVariable().getManager().boolean(false));
}
} }
std::ostream& operator<<(std::ostream& stream, BooleanVariable const& variable) { std::ostream& operator<<(std::ostream& stream, BooleanVariable const& variable) {
stream << variable.getName() << ": bool init " << variable.getInitialValueExpression() << ";"; stream << variable.getName() << ": bool";
if (variable.hasInitialValue()) {
stream << " init " << variable.getInitialValueExpression();
}
stream << ";";
return stream; return stream;
} }

2
src/storage/prism/BooleanVariable.h

@ -37,6 +37,8 @@ namespace storm {
*/ */
BooleanVariable substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const; BooleanVariable substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const;
virtual void createMissingInitialValue() override;
friend std::ostream& operator<<(std::ostream& stream, BooleanVariable const& variable); friend std::ostream& operator<<(std::ostream& stream, BooleanVariable const& variable);
}; };

7
src/storage/prism/Constant.cpp

@ -42,7 +42,12 @@ namespace storm {
} }
std::ostream& operator<<(std::ostream& stream, Constant const& constant) { std::ostream& operator<<(std::ostream& stream, Constant const& constant) {
stream << "const " << constant.getExpressionVariable().getType() << " "; stream << "const ";
if (constant.getType().isRationalType()) {
stream << "double" << " ";
} else {
stream << constant.getType() << " ";
}
stream << constant.getName(); stream << constant.getName();
if (constant.isDefined()) { if (constant.isDefined()) {
stream << " = " << constant.getExpression(); stream << " = " << constant.getExpression();

14
src/storage/prism/IntegerVariable.cpp

@ -19,11 +19,21 @@ namespace storm {
} }
IntegerVariable IntegerVariable::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const { IntegerVariable IntegerVariable::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const {
return IntegerVariable(this->getExpressionVariable(), this->getLowerBoundExpression().substitute(substitution), this->getUpperBoundExpression().substitute(substitution), this->getInitialValueExpression().substitute(substitution), this->getFilename(), this->getLineNumber()); return IntegerVariable(this->getExpressionVariable(), this->getLowerBoundExpression().substitute(substitution), this->getUpperBoundExpression().substitute(substitution), this->getInitialValueExpression().isInitialized() ? this->getInitialValueExpression().substitute(substitution) : this->getInitialValueExpression(), this->getFilename(), this->getLineNumber());
}
void IntegerVariable::createMissingInitialValue() {
if (!this->hasInitialValue()) {
this->setInitialValueExpression(this->getLowerBoundExpression());
}
} }
std::ostream& operator<<(std::ostream& stream, IntegerVariable const& variable) { std::ostream& operator<<(std::ostream& stream, IntegerVariable const& variable) {
stream << variable.getName() << ": [" << variable.getLowerBoundExpression() << ".." << variable.getUpperBoundExpression() << "]" << " init " << variable.getInitialValueExpression() << ";"; stream << variable.getName() << ": [" << variable.getLowerBoundExpression() << ".." << variable.getUpperBoundExpression() << "]";
if (variable.hasInitialValue()) {
stream << " init " << variable.getInitialValueExpression();
}
stream << ";";
return stream; return stream;
} }
} // namespace prism } // namespace prism

2
src/storage/prism/IntegerVariable.h

@ -60,6 +60,8 @@ namespace storm {
*/ */
IntegerVariable substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const; IntegerVariable substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const;
virtual void createMissingInitialValue() override;
friend std::ostream& operator<<(std::ostream& stream, IntegerVariable const& variable); friend std::ostream& operator<<(std::ostream& stream, IntegerVariable const& variable);
private: private:

20
src/storage/prism/Module.cpp

@ -42,7 +42,7 @@ namespace storm {
std::vector<storm::prism::IntegerVariable> const& Module::getIntegerVariables() const { std::vector<storm::prism::IntegerVariable> const& Module::getIntegerVariables() const {
return this->integerVariables; return this->integerVariables;
} }
std::set<storm::expressions::Variable> Module::getAllExpressionVariables() const { std::set<storm::expressions::Variable> Module::getAllExpressionVariables() const {
std::set<storm::expressions::Variable> result; std::set<storm::expressions::Variable> result;
for (auto const& var : this->getBooleanVariables()) { for (auto const& var : this->getBooleanVariables()) {
@ -188,10 +188,7 @@ namespace storm {
std::vector<Command> newCommands; std::vector<Command> newCommands;
newCommands.reserve(this->getNumberOfCommands()); newCommands.reserve(this->getNumberOfCommands());
for (auto const& command : this->getCommands()) { for (auto const& command : this->getCommands()) {
Command newCommand = command.substitute(substitution); newCommands.emplace_back(command.substitute(substitution));
if (!newCommand.getGuardExpression().isFalse()) {
newCommands.emplace_back(newCommand);
}
} }
return Module(this->getName(), newBooleanVariables, newIntegerVariables, newCommands, this->getFilename(), this->getLineNumber()); return Module(this->getName(), newBooleanVariables, newIntegerVariables, newCommands, this->getFilename(), this->getLineNumber());
@ -216,12 +213,23 @@ namespace storm {
} }
for (auto const& command : this->getCommands()) { for (auto const& command : this->getCommands()) {
command.containsVariablesOnlyInUpdateProbabilities(undefinedConstantVariables); if (!command.containsVariablesOnlyInUpdateProbabilities(undefinedConstantVariables)) {
return false;
}
} }
return true; return true;
} }
void Module::createMissingInitialValues() {
for (auto& variable : booleanVariables) {
variable.createMissingInitialValue();
}
for (auto& variable : integerVariables) {
variable.createMissingInitialValue();
}
}
std::ostream& operator<<(std::ostream& stream, Module const& module) { std::ostream& operator<<(std::ostream& stream, Module const& module) {
stream << "module " << module.getName() << std::endl; stream << "module " << module.getName() << std::endl;
for (auto const& booleanVariable : module.getBooleanVariables()) { for (auto const& booleanVariable : module.getBooleanVariables()) {

6
src/storage/prism/Module.h

@ -104,7 +104,6 @@ namespace storm {
*/ */
std::set<storm::expressions::Variable> getAllExpressionVariables() const; std::set<storm::expressions::Variable> getAllExpressionVariables() const;
/*! /*!
* Retrieves a list of expressions that characterize the legal ranges of all variables declared by this * Retrieves a list of expressions that characterize the legal ranges of all variables declared by this
* module. * module.
@ -226,6 +225,11 @@ namespace storm {
*/ */
bool containsVariablesOnlyInUpdateProbabilities(std::set<storm::expressions::Variable> const& undefinedConstantVariables) const; bool containsVariablesOnlyInUpdateProbabilities(std::set<storm::expressions::Variable> const& undefinedConstantVariables) const;
/*!
* Equips all of the modules' variables without initial values with initial values based on their type.
*/
void createMissingInitialValues();
friend std::ostream& operator<<(std::ostream& stream, Module const& module); friend std::ostream& operator<<(std::ostream& stream, Module const& module);
private: private:

379
src/storage/prism/Program.cpp

@ -148,28 +148,15 @@ namespace storm {
// Start by creating the necessary mappings from the given ones. // Start by creating the necessary mappings from the given ones.
this->createMappings(); this->createMappings();
// Set the initial construct. // Set the initial construct if given.
if (initialConstruct) { if (initialConstruct) {
this->initialConstruct = initialConstruct.get(); this->initialConstruct = initialConstruct.get();
} else { } else {
// Create a new initial construct if none was given. // Otherwise, we create the missing initial values.
storm::expressions::Expression newInitialExpression = manager->boolean(true); this->createMissingInitialValues();
for (auto& modules : this->modules) {
for (auto const& booleanVariable : this->getGlobalBooleanVariables()) { modules.createMissingInitialValues();
newInitialExpression = newInitialExpression && storm::expressions::iff(booleanVariable.getExpression(), booleanVariable.getInitialValueExpression());
}
for (auto const& integerVariable : this->getGlobalIntegerVariables()) {
newInitialExpression = newInitialExpression && integerVariable.getExpression() == integerVariable.getInitialValueExpression();
}
for (auto const& module : this->getModules()) {
for (auto const& booleanVariable : module.getBooleanVariables()) {
newInitialExpression = newInitialExpression && storm::expressions::iff(booleanVariable.getExpression(), booleanVariable.getInitialValueExpression());
}
for (auto const& integerVariable : module.getIntegerVariables()) {
newInitialExpression = newInitialExpression && integerVariable.getExpression() == integerVariable.getInitialValueExpression();
}
} }
this->initialConstruct = storm::prism::InitialConstruct(newInitialExpression, this->getInitialConstruct().getFilename(), this->getInitialConstruct().getLineNumber());
} }
if (finalModel) { if (finalModel) {
@ -230,7 +217,7 @@ namespace storm {
// constants' variables is empty (except for the update probabilities). // constants' variables is empty (except for the update probabilities).
// Start by checking the defining expressions of all defined constants. If it contains a currently undefined // Start by checking the defining expressions of all defined constants. If it contains a currently undefined
//constant, we need to mark the target constant as undefined as well. // constant, we need to mark the target constant as undefined as well.
for (auto const& constant : this->getConstants()) { for (auto const& constant : this->getConstants()) {
if (constant.isDefined()) { if (constant.isDefined()) {
if (constant.getExpression().containsVariable(undefinedConstantVariables)) { if (constant.getExpression().containsVariable(undefinedConstantVariables)) {
@ -241,13 +228,17 @@ namespace storm {
// Now check initial value expressions of global variables. // Now check initial value expressions of global variables.
for (auto const& booleanVariable : this->getGlobalBooleanVariables()) { for (auto const& booleanVariable : this->getGlobalBooleanVariables()) {
if (booleanVariable.getInitialValueExpression().containsVariable(undefinedConstantVariables)) { if (booleanVariable.hasInitialValue()) {
return false; if (booleanVariable.getInitialValueExpression().containsVariable(undefinedConstantVariables)) {
return false;
}
} }
} }
for (auto const& integerVariable : this->getGlobalIntegerVariables()) { for (auto const& integerVariable : this->getGlobalIntegerVariables()) {
if (integerVariable.getInitialValueExpression().containsVariable(undefinedConstantVariables)) { if (integerVariable.hasInitialValue()) {
return false; if (integerVariable.getInitialValueExpression().containsVariable(undefinedConstantVariables)) {
return false;
}
} }
if (integerVariable.getLowerBoundExpression().containsVariable(undefinedConstantVariables)) { if (integerVariable.getLowerBoundExpression().containsVariable(undefinedConstantVariables)) {
return false; return false;
@ -266,7 +257,9 @@ namespace storm {
// Proceed by checking each of the modules. // Proceed by checking each of the modules.
for (auto const& module : this->getModules()) { for (auto const& module : this->getModules()) {
module.containsVariablesOnlyInUpdateProbabilities(undefinedConstantVariables); if (!module.containsVariablesOnlyInUpdateProbabilities(undefinedConstantVariables)) {
return false;
}
} }
// Check the reward models. // Check the reward models.
@ -275,8 +268,10 @@ namespace storm {
} }
// Initial construct. // Initial construct.
if (this->getInitialConstruct().getInitialStatesExpression().containsVariable(undefinedConstantVariables)) { if (this->hasInitialConstruct()) {
return false; if (this->getInitialConstruct().getInitialStatesExpression().containsVariable(undefinedConstantVariables)) {
return false;
}
} }
// Labels. // Labels.
@ -446,10 +441,61 @@ namespace storm {
return actionToIndexMap; return actionToIndexMap;
} }
bool Program::hasInitialConstruct() const {
return static_cast<bool>(initialConstruct);
}
storm::prism::InitialConstruct const& Program::getInitialConstruct() const { storm::prism::InitialConstruct const& Program::getInitialConstruct() const {
return this->initialConstruct.get();
}
boost::optional<InitialConstruct> const& Program::getOptionalInitialConstruct() const {
return this->initialConstruct; return this->initialConstruct;
} }
storm::expressions::Expression Program::getInitialStatesExpression() const {
// If there is an initial construct, return its expression. If not, we construct the expression from the
// initial values of the variables (which have to exist).
if (this->hasInitialConstruct()) {
return this->getInitialConstruct().getInitialStatesExpression();
} else {
storm::expressions::Expression result;
for (auto const& variable : this->getGlobalBooleanVariables()) {
if (result.isInitialized()) {
result = result && storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression());
} else {
result = storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression());
}
}
for (auto const& variable : this->getGlobalIntegerVariables()) {
if (result.isInitialized()) {
result = result && variable.getExpressionVariable() == variable.getInitialValueExpression();
} else {
result = variable.getExpressionVariable() == variable.getInitialValueExpression();
}
}
for (auto const& module : this->getModules()) {
for (auto const& variable : module.getBooleanVariables()) {
if (result.isInitialized()) {
result = result && storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression());
} else {
result = storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression());
}
}
for (auto const& variable : module.getIntegerVariables()) {
if (result.isInitialized()) {
result = result && variable.getExpressionVariable() == variable.getInitialValueExpression();
} else {
result = variable.getExpressionVariable() == variable.getInitialValueExpression();
}
}
}
return result;
}
}
bool Program::specifiesSystemComposition() const { bool Program::specifiesSystemComposition() const {
return static_cast<bool>(systemCompositionConstruct); return static_cast<bool>(systemCompositionConstruct);
} }
@ -611,7 +657,7 @@ namespace storm {
newModules.push_back(module.restrictCommands(indexSet)); newModules.push_back(module.restrictCommands(indexSet));
} }
return Program(this->manager, this->getModelType(), this->getConstants(), this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(), this->getFormulas(), newModules, this->getActionNameToIndexMapping(), this->getRewardModels(), this->getLabels(), this->getInitialConstruct(), this->getOptionalSystemCompositionConstruct()); return Program(this->manager, this->getModelType(), this->getConstants(), this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(), this->getFormulas(), newModules, this->getActionNameToIndexMapping(), this->getRewardModels(), this->getLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct());
} }
void Program::createMappings() { void Program::createMappings() {
@ -711,11 +757,11 @@ namespace storm {
STORM_LOG_THROW(definedUndefinedConstants.find(constantExpressionPair.first) != definedUndefinedConstants.end(), storm::exceptions::InvalidArgumentException, "Unable to define non-existant constant."); STORM_LOG_THROW(definedUndefinedConstants.find(constantExpressionPair.first) != definedUndefinedConstants.end(), storm::exceptions::InvalidArgumentException, "Unable to define non-existant constant.");
} }
return Program(this->manager, this->getModelType(), newConstants, this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(), this->getFormulas(), this->getModules(), this->getActionNameToIndexMapping(), this->getRewardModels(), this->getLabels(), this->getInitialConstruct(), this->getOptionalSystemCompositionConstruct()); return Program(this->manager, this->getModelType(), newConstants, this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(), this->getFormulas(), this->getModules(), this->getActionNameToIndexMapping(), this->getRewardModels(), this->getLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct());
} }
Program Program::substituteConstants() const { Program Program::substituteConstants() const {
// We start by creating the appropriate substitution // We start by creating the appropriate substitution.
std::map<storm::expressions::Variable, storm::expressions::Expression> constantSubstitution; std::map<storm::expressions::Variable, storm::expressions::Expression> constantSubstitution;
std::vector<Constant> newConstants(this->getConstants()); std::vector<Constant> newConstants(this->getConstants());
for (uint_fast64_t constantIndex = 0; constantIndex < newConstants.size(); ++constantIndex) { for (uint_fast64_t constantIndex = 0; constantIndex < newConstants.size(); ++constantIndex) {
@ -763,7 +809,10 @@ namespace storm {
newRewardModels.emplace_back(rewardModel.substitute(constantSubstitution)); newRewardModels.emplace_back(rewardModel.substitute(constantSubstitution));
} }
storm::prism::InitialConstruct newInitialConstruct = this->getInitialConstruct().substitute(constantSubstitution); boost::optional<storm::prism::InitialConstruct> newInitialConstruct;
if (this->hasInitialConstruct()) {
newInitialConstruct = this->getInitialConstruct().substitute(constantSubstitution);
}
std::vector<Label> newLabels; std::vector<Label> newLabels;
newLabels.reserve(this->getNumberOfLabels()); newLabels.reserve(this->getNumberOfLabels());
@ -807,18 +856,22 @@ namespace storm {
// Now we check the variable declarations. We start with the global variables. // Now we check the variable declarations. We start with the global variables.
std::set<storm::expressions::Variable> variables; std::set<storm::expressions::Variable> variables;
for (auto const& variable : this->getGlobalBooleanVariables()) { for (auto const& variable : this->getGlobalBooleanVariables()) {
// Check the initial value of the variable. if (variable.hasInitialValue()) {
std::set<storm::expressions::Variable> containedVariables = variable.getInitialValueExpression().getVariables(); STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": illegal to specify initial value if an initial construct is present.");
std::set<storm::expressions::Variable> illegalVariables; // Check the initial value of the variable.
std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin())); std::set<storm::expressions::Variable> containedVariables = variable.getInitialValueExpression().getVariables();
bool isValid = illegalVariables.empty(); std::set<storm::expressions::Variable> illegalVariables;
std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin()));
if (!isValid) { bool isValid = illegalVariables.empty();
std::vector<std::string> illegalVariableNames; if (!isValid) {
for (auto const& var : illegalVariables) { std::vector<std::string> illegalVariableNames;
illegalVariableNames.push_back(var.getName()); for (auto const& var : illegalVariables) {
illegalVariableNames.push_back(var.getName());
}
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
} }
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
} }
// Record the new identifier for future checks. // Record the new identifier for future checks.
@ -853,16 +906,20 @@ namespace storm {
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": upper bound expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << "."); STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": upper bound expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
} }
// Check the initial value of the variable. if (variable.hasInitialValue()) {
containedVariables = variable.getInitialValueExpression().getVariables(); STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": illegal to specify initial value if an initial construct is present.");
std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin())); // Check the initial value of the variable.
isValid = illegalVariables.empty(); containedVariables = variable.getInitialValueExpression().getVariables();
if (!isValid) { std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin()));
std::vector<std::string> illegalVariableNames; isValid = illegalVariables.empty();
for (auto const& var : illegalVariables) { if (!isValid) {
illegalVariableNames.push_back(var.getName()); std::vector<std::string> illegalVariableNames;
for (auto const& var : illegalVariables) {
illegalVariableNames.push_back(var.getName());
}
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
} }
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
} }
// Record the new identifier for future checks. // Record the new identifier for future checks.
@ -875,17 +932,21 @@ namespace storm {
// Now go through the variables of the modules. // Now go through the variables of the modules.
for (auto const& module : this->getModules()) { for (auto const& module : this->getModules()) {
for (auto const& variable : module.getBooleanVariables()) { for (auto const& variable : module.getBooleanVariables()) {
// Check the initial value of the variable. if (variable.hasInitialValue()) {
std::set<storm::expressions::Variable> containedVariables = variable.getInitialValueExpression().getVariables(); STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": illegal to specify initial value if an initial construct is present.");
std::set<storm::expressions::Variable> illegalVariables; // Check the initial value of the variable.
std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin())); std::set<storm::expressions::Variable> containedVariables = variable.getInitialValueExpression().getVariables();
bool isValid = illegalVariables.empty(); std::set<storm::expressions::Variable> illegalVariables;
if (!isValid) { std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin()));
std::vector<std::string> illegalVariableNames; bool isValid = illegalVariables.empty();
for (auto const& var : illegalVariables) { if (!isValid) {
illegalVariableNames.push_back(var.getName()); std::vector<std::string> illegalVariableNames;
for (auto const& var : illegalVariables) {
illegalVariableNames.push_back(var.getName());
}
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
} }
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
} }
// Record the new identifier for future checks. // Record the new identifier for future checks.
@ -918,17 +979,21 @@ namespace storm {
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": upper bound expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << "."); STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": upper bound expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
} }
// Check the initial value of the variable. if (variable.hasInitialValue()) {
containedVariables = variable.getInitialValueExpression().getVariables(); STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": illegal to specify initial value if an initial construct is present.");
illegalVariables.clear(); // Check the initial value of the variable.
std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin())); containedVariables = variable.getInitialValueExpression().getVariables();
isValid = illegalVariables.empty(); illegalVariables.clear();
if (!isValid) { std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin()));
std::vector<std::string> illegalVariableNames; isValid = illegalVariables.empty();
for (auto const& var : illegalVariables) { if (!isValid) {
illegalVariableNames.push_back(var.getName()); std::vector<std::string> illegalVariableNames;
for (auto const& var : illegalVariables) {
illegalVariableNames.push_back(var.getName());
}
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
} }
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
} }
// Record the new identifier for future checks. // Record the new identifier for future checks.
@ -1091,9 +1156,11 @@ namespace storm {
} }
// Check the initial states expression. // Check the initial states expression.
std::set<storm::expressions::Variable> containedIdentifiers = this->getInitialConstruct().getInitialStatesExpression().getVariables(); if (this->hasInitialConstruct()) {
bool isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedIdentifiers.begin(), containedIdentifiers.end()); std::set<storm::expressions::Variable> containedIdentifiers = this->getInitialConstruct().getInitialStatesExpression().getVariables();
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << this->getInitialConstruct().getFilename() << ", line " << this->getInitialConstruct().getLineNumber() << ": initial expression refers to unknown identifiers."); bool isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedIdentifiers.begin(), containedIdentifiers.end());
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << this->getInitialConstruct().getFilename() << ", line " << this->getInitialConstruct().getLineNumber() << ": initial construct refers to unknown identifiers.");
}
// Check the system composition if given. // Check the system composition if given.
if (systemCompositionConstruct) { if (systemCompositionConstruct) {
@ -1151,17 +1218,28 @@ namespace storm {
} }
Program Program::simplify() { Program Program::simplify() {
// Start by substituting the constants, because this will potentially erase some commands or even actions.
Program substitutedProgram = this->substituteConstants();
// As we possibly delete some commands and some actions might be dropped from modules altogether, we need to
// maintain a list of actions that we need to remove in other modules. For example, if module A loses all [a]
// commands, we need to delete all [a] commands from all other modules as well. If we do not do that, we will
// remove the forced synchronization that was there before.
std::set<uint_fast64_t> actionIndicesToDelete;
std::vector<Module> newModules; std::vector<Module> newModules;
std::vector<Constant> newConstants = this->getConstants(); std::vector<Constant> newConstants = substitutedProgram.getConstants();
for (auto const& module : this->getModules()) { for (auto const& module : substitutedProgram.getModules()) {
// Remove identity assignments from the updates // Discard all commands with a guard equivalent to false and remove identity assignments from the updates.
std::vector<Command> newCommands; std::vector<Command> newCommands;
for (auto const& command : module.getCommands()) { for (auto const& command : module.getCommands()) {
newCommands.emplace_back(command.removeIdentityAssignmentsFromUpdates()); if (!command.getGuardExpression().isFalse()) {
newCommands.emplace_back(command.removeIdentityAssignmentsFromUpdates());
}
} }
// Substitute Variables by Global constants if possible. // Substitute variables by global constants if possible.
std::map<storm::expressions::Variable, storm::expressions::Expression> booleanVars; std::map<storm::expressions::Variable, storm::expressions::Expression> booleanVars;
std::map<storm::expressions::Variable, storm::expressions::Expression> integerVars; std::map<storm::expressions::Variable, storm::expressions::Expression> integerVars;
for (auto const& variable : module.getBooleanVariables()) { for (auto const& variable : module.getBooleanVariables()) {
@ -1171,54 +1249,84 @@ namespace storm {
integerVars.emplace(variable.getExpressionVariable(), variable.getInitialValueExpression()); integerVars.emplace(variable.getExpressionVariable(), variable.getInitialValueExpression());
} }
// Collect all variables that are being written. These variables cannot be turned to constants.
for (auto const& command : newCommands) { for (auto const& command : newCommands) {
// Check all updates. // Check all updates.
for (auto const& update : command.getUpdates()) { for (auto const& update : command.getUpdates()) {
// Check all assignments. // Check all assignments.
for (auto const& assignment : update.getAssignments()) { for (auto const& assignment : update.getAssignments()) {
auto bit = booleanVars.find(assignment.getVariable()); if (assignment.getVariable().getType().isBooleanType()) {
if(bit != booleanVars.end()) { auto it = booleanVars.find(assignment.getVariable());
booleanVars.erase(bit); if (it != booleanVars.end()) {
booleanVars.erase(it);
}
} else { } else {
auto iit = integerVars.find(assignment.getVariable()); auto it = integerVars.find(assignment.getVariable());
if(iit != integerVars.end()) { if (it != integerVars.end()) {
integerVars.erase(iit); integerVars.erase(it);
} }
} }
} }
} }
} }
std::vector<storm::prism::BooleanVariable> newBVars; std::vector<storm::prism::BooleanVariable> newBooleanVars;
for(auto const& variable : module.getBooleanVariables()) { for (auto const& variable : module.getBooleanVariables()) {
if(booleanVars.count(variable.getExpressionVariable()) == 0) { if (booleanVars.find(variable.getExpressionVariable()) == booleanVars.end()) {
newBVars.push_back(variable); newBooleanVars.push_back(variable);
} }
} }
std::vector<storm::prism::IntegerVariable> newIVars; std::vector<storm::prism::IntegerVariable> newIntegerVars;
for(auto const& variable : module.getIntegerVariables()) { for (auto const& variable : module.getIntegerVariables()) {
if(integerVars.count(variable.getExpressionVariable()) == 0) { if (integerVars.find(variable.getExpressionVariable()) == integerVars.end()) {
newIVars.push_back(variable); newIntegerVars.push_back(variable);
} }
} }
newModules.emplace_back(module.getName(), newBVars, newIVars, newCommands); newModules.emplace_back(module.getName(), newBooleanVars, newIntegerVars, newCommands);
// Determine the set of action indices that have been deleted entirely.
std::set_difference(module.getSynchronizingActionIndices().begin(), module.getSynchronizingActionIndices().end(), newModules.back().getSynchronizingActionIndices().begin(), newModules.back().getSynchronizingActionIndices().end(), std::inserter(actionIndicesToDelete, actionIndicesToDelete.begin()));
for(auto const& entry : booleanVars) { for (auto const& entry : booleanVars) {
newConstants.emplace_back(entry.first, entry.second); newConstants.emplace_back(entry.first, entry.second);
} }
for(auto const& entry : integerVars) { for (auto const& entry : integerVars) {
newConstants.emplace_back(entry.first, entry.second); newConstants.emplace_back(entry.first, entry.second);
} }
} }
return replaceModulesAndConstantsInProgram(newModules, newConstants).substituteConstants(); // If we have to delete whole actions, do so now.
std::map<std::string, uint_fast64_t> newActionToIndexMap;
std::vector<RewardModel> newRewardModels;
if (!actionIndicesToDelete.empty()) {
boost::container::flat_set<uint_fast64_t> actionsToKeep;
std::set_difference(this->getSynchronizingActionIndices().begin(), this->getSynchronizingActionIndices().end(), actionIndicesToDelete.begin(), actionIndicesToDelete.end(), std::inserter(actionsToKeep, actionsToKeep.begin()));
// Insert the silent action as this is not contained in the synchronizing action indices.
actionsToKeep.insert(0);
std::vector<Module> cleanedModules;
cleanedModules.reserve(newModules.size());
for (auto const& module : newModules) {
cleanedModules.emplace_back(module.restrictCommands(actionsToKeep));
}
newModules = std::move(cleanedModules);
newRewardModels.reserve(substitutedProgram.getNumberOfRewardModels());
for (auto const& rewardModel : substitutedProgram.getRewardModels()) {
newRewardModels.emplace_back(rewardModel.restrictActionRelatedRewards(actionsToKeep));
}
for (auto const& entry : this->getActionNameToIndexMapping()) {
if (actionsToKeep.find(entry.second) != actionsToKeep.end()) {
newActionToIndexMap.emplace(entry.first, entry.second);
}
}
}
} return Program(this->manager, modelType, newConstants, getGlobalBooleanVariables(), getGlobalIntegerVariables(), getFormulas(), newModules, actionIndicesToDelete.empty() ? getActionNameToIndexMapping() : newActionToIndexMap, actionIndicesToDelete.empty() ? this->getRewardModels() : newRewardModels, getLabels(), getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct());
Program Program::replaceModulesAndConstantsInProgram(std::vector<Module> const& newModules, std::vector<Constant> const& newConstants) {
return Program(this->manager, modelType, newConstants, getGlobalBooleanVariables(), getGlobalIntegerVariables(), getFormulas(), newModules, getActionNameToIndexMapping(), getRewardModels(), getLabels(), getInitialConstruct(), this->getOptionalSystemCompositionConstruct());
} }
Program Program::flattenModules(std::unique_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory) const { Program Program::flattenModules(std::unique_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory) const {
@ -1404,7 +1512,7 @@ namespace storm {
// Finally, we can create the module and the program and return it. // Finally, we can create the module and the program and return it.
storm::prism::Module singleModule(newModuleName.str(), allBooleanVariables, allIntegerVariables, newCommands, this->getFilename(), 0); storm::prism::Module singleModule(newModuleName.str(), allBooleanVariables, allIntegerVariables, newCommands, this->getFilename(), 0);
return Program(manager, this->getModelType(), this->getConstants(), std::vector<storm::prism::BooleanVariable>(), std::vector<storm::prism::IntegerVariable>(), this->getFormulas(), {singleModule}, actionToIndexMap, this->getRewardModels(), this->getLabels(), this->getInitialConstruct(), this->getOptionalSystemCompositionConstruct(), this->getFilename(), 0, true); return Program(manager, this->getModelType(), this->getConstants(), std::vector<storm::prism::BooleanVariable>(), std::vector<storm::prism::IntegerVariable>(), this->getFormulas(), {singleModule}, actionToIndexMap, this->getRewardModels(), this->getLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), this->getFilename(), 0, true);
} }
std::unordered_map<uint_fast64_t, std::string> Program::buildCommandIndexToActionNameMap() const { std::unordered_map<uint_fast64_t, std::string> Program::buildCommandIndexToActionNameMap() const {
@ -1527,7 +1635,7 @@ namespace storm {
default: modelType = storm::jani::ModelType::UNDEFINED; default: modelType = storm::jani::ModelType::UNDEFINED;
} }
storm::jani::Model janiModel("jani_from_prism", modelType, 1, manager); storm::jani::Model janiModel("jani_from_prism", modelType, 1, manager);
// Add all constants of the PRISM program to the JANI model. // Add all constants of the PRISM program to the JANI model.
for (auto const& constant : constants) { for (auto const& constant : constants) {
janiModel.addConstant(storm::jani::Constant(constant.getName(), constant.getExpressionVariable(), constant.isDefined() ? boost::optional<storm::expressions::Expression>(constant.getExpression()) : boost::none)); janiModel.addConstant(storm::jani::Constant(constant.getName(), constant.getExpressionVariable(), constant.isDefined() ? boost::optional<storm::expressions::Expression>(constant.getExpression()) : boost::none));
@ -1539,12 +1647,22 @@ namespace storm {
// Add all global variables of the PRISM program to the JANI model. // Add all global variables of the PRISM program to the JANI model.
for (auto const& variable : globalIntegerVariables) { for (auto const& variable : globalIntegerVariables) {
storm::jani::BoundedIntegerVariable const& newVariable = janiModel.addBoundedIntegerVariable(storm::jani::BoundedIntegerVariable(variable.getName(), variable.getExpressionVariable(), variable.getInitialValueExpression(), variable.getLowerBoundExpression(), variable.getUpperBoundExpression())); if (variable.hasInitialValue()) {
variableToVariableMap.emplace(variable.getExpressionVariable(), newVariable); storm::jani::BoundedIntegerVariable const& createdVariable = janiModel.addBoundedIntegerVariable(storm::jani::BoundedIntegerVariable(variable.getName(), variable.getExpressionVariable(), variable.getInitialValueExpression(), false, variable.getLowerBoundExpression(), variable.getUpperBoundExpression()));
variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable);
} else {
storm::jani::BoundedIntegerVariable const& createdVariable = janiModel.addBoundedIntegerVariable(storm::jani::BoundedIntegerVariable(variable.getName(), variable.getExpressionVariable(), false, variable.getLowerBoundExpression(), variable.getUpperBoundExpression()));
variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable);
}
} }
for (auto const& variable : globalBooleanVariables) { for (auto const& variable : globalBooleanVariables) {
storm::jani::BooleanVariable const& newVariable = janiModel.addBooleanVariable(storm::jani::BooleanVariable(variable.getName(), variable.getExpressionVariable(), variable.getInitialValueExpression())); if (variable.hasInitialValue()) {
variableToVariableMap.emplace(variable.getExpressionVariable(), newVariable); storm::jani::BooleanVariable const& createdVariable = janiModel.addBooleanVariable(storm::jani::BooleanVariable(variable.getName(), variable.getExpressionVariable(), variable.getInitialValueExpression(), false));
variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable);
} else {
storm::jani::BooleanVariable const& createdVariable = janiModel.addBooleanVariable(storm::jani::BooleanVariable(variable.getName(), variable.getExpressionVariable(), false));
variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable);
}
} }
// Add all actions of the PRISM program to the JANI model. // Add all actions of the PRISM program to the JANI model.
@ -1556,7 +1674,7 @@ namespace storm {
} }
// Because of the rules of JANI, we have to make all variables of modules global that are read by other modules. // Because of the rules of JANI, we have to make all variables of modules global that are read by other modules.
// Create a mapping from variables to the indices of module indices that write/read the variable. // Create a mapping from variables to the indices of module indices that write/read the variable.
std::map<storm::expressions::Variable, std::set<uint_fast64_t>> variablesToAccessingModuleIndices; std::map<storm::expressions::Variable, std::set<uint_fast64_t>> variablesToAccessingModuleIndices;
for (uint_fast64_t index = 0; index < modules.size(); ++index) { for (uint_fast64_t index = 0; index < modules.size(); ++index) {
@ -1584,31 +1702,30 @@ namespace storm {
// previously built mapping to make variables global that are read by more than one module. // previously built mapping to make variables global that are read by more than one module.
for (auto const& module : modules) { for (auto const& module : modules) {
storm::jani::Automaton automaton(module.getName()); storm::jani::Automaton automaton(module.getName());
for (auto const& variable : module.getIntegerVariables()) { for (auto const& variable : module.getIntegerVariables()) {
storm::jani::BoundedIntegerVariable newIntegerVariable(variable.getName(), variable.getExpressionVariable(), variable.getInitialValueExpression(), variable.getLowerBoundExpression(), variable.getUpperBoundExpression()); storm::jani::BoundedIntegerVariable newIntegerVariable = *storm::jani::makeBoundedIntegerVariable(variable.getName(), variable.getExpressionVariable(), variable.hasInitialValue() ? boost::make_optional(variable.getInitialValueExpression()) : boost::none, false, variable.getLowerBoundExpression(), variable.getUpperBoundExpression());
std::set<uint_fast64_t> const& accessingModuleIndices = variablesToAccessingModuleIndices[variable.getExpressionVariable()]; std::set<uint_fast64_t> const& accessingModuleIndices = variablesToAccessingModuleIndices[variable.getExpressionVariable()];
// If there is exactly one module reading and writing the variable, we can make the variable local to this module. // If there is exactly one module reading and writing the variable, we can make the variable local to this module.
if (!allVariablesGlobal && accessingModuleIndices.size() == 1) { if (!allVariablesGlobal && accessingModuleIndices.size() == 1) {
storm::jani::BoundedIntegerVariable const& newVariable = automaton.addBoundedIntegerVariable(newIntegerVariable); storm::jani::BoundedIntegerVariable const& createdVariable = automaton.addBoundedIntegerVariable(newIntegerVariable);
variableToVariableMap.emplace(variable.getExpressionVariable(), newVariable); variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable);
} else if (!accessingModuleIndices.empty()) { } else if (!accessingModuleIndices.empty()) {
// Otherwise, we need to make it global. // Otherwise, we need to make it global.
storm::jani::BoundedIntegerVariable const& newVariable = janiModel.addBoundedIntegerVariable(newIntegerVariable); storm::jani::BoundedIntegerVariable const& createdVariable = janiModel.addBoundedIntegerVariable(newIntegerVariable);
variableToVariableMap.emplace(variable.getExpressionVariable(), newVariable); variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable);
} }
} }
for (auto const& variable : module.getBooleanVariables()) { for (auto const& variable : module.getBooleanVariables()) {
storm::jani::BooleanVariable newBooleanVariable(variable.getName(), variable.getExpressionVariable(), variable.getInitialValueExpression()); storm::jani::BooleanVariable newBooleanVariable = *storm::jani::makeBooleanVariable(variable.getName(), variable.getExpressionVariable(), variable.hasInitialValue() ? boost::make_optional(variable.getInitialValueExpression()) : boost::none, false);
std::set<uint_fast64_t> const& accessingModuleIndices = variablesToAccessingModuleIndices[variable.getExpressionVariable()]; std::set<uint_fast64_t> const& accessingModuleIndices = variablesToAccessingModuleIndices[variable.getExpressionVariable()];
// If there is exactly one module reading and writing the variable, we can make the variable local to this module. // If there is exactly one module reading and writing the variable, we can make the variable local to this module.
if (!allVariablesGlobal && accessingModuleIndices.size() == 1) { if (!allVariablesGlobal && accessingModuleIndices.size() == 1) {
storm::jani::BooleanVariable const& newVariable = automaton.addBooleanVariable(newBooleanVariable); storm::jani::BooleanVariable const& createdVariable = automaton.addBooleanVariable(newBooleanVariable);
variableToVariableMap.emplace(variable.getExpressionVariable(), newVariable); variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable);
} else if (!accessingModuleIndices.empty()) { } else if (!accessingModuleIndices.empty()) {
// Otherwise, we need to make it global. // Otherwise, we need to make it global.
storm::jani::BooleanVariable const& newVariable = janiModel.addBooleanVariable(newBooleanVariable); storm::jani::BooleanVariable const& createdVariable = janiModel.addBooleanVariable(newBooleanVariable);
variableToVariableMap.emplace(variable.getExpressionVariable(), newVariable); variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable);
} }
} }
automaton.setInitialStatesRestriction(manager->boolean(true)); automaton.setInitialStatesRestriction(manager->boolean(true));
@ -1647,7 +1764,12 @@ namespace storm {
janiModel.addAutomaton(automaton); janiModel.addAutomaton(automaton);
} }
janiModel.setInitialStatesRestriction(manager->boolean(true)); if (this->hasInitialConstruct()) {
janiModel.setInitialStatesRestriction(this->getInitialConstruct().getInitialStatesExpression());
} else {
janiModel.setInitialStatesRestriction(manager->boolean(true));
}
// Set the standard system composition. This is possible, because we reject non-standard compositions anyway. // Set the standard system composition. This is possible, because we reject non-standard compositions anyway.
if (this->specifiesSystemComposition()) { if (this->specifiesSystemComposition()) {
@ -1662,6 +1784,19 @@ namespace storm {
return janiModel; return janiModel;
} }
void Program::createMissingInitialValues() {
for (auto& variable : globalBooleanVariables) {
if (!variable.hasInitialValue()) {
variable.setInitialValueExpression(manager->boolean(false));
}
}
for (auto& variable : globalIntegerVariables) {
if (!variable.hasInitialValue()) {
variable.setInitialValueExpression(variable.getLowerBoundExpression());
}
}
}
std::ostream& operator<<(std::ostream& out, Program::ModelType const& type) { std::ostream& operator<<(std::ostream& out, Program::ModelType const& type) {
switch (type) { switch (type) {
case Program::ModelType::UNDEFINED: out << "undefined"; break; case Program::ModelType::UNDEFINED: out << "undefined"; break;
@ -1706,7 +1841,9 @@ namespace storm {
stream << label << std::endl; stream << label << std::endl;
} }
stream << program.getInitialConstruct() << std::endl; if (program.hasInitialConstruct()) {
stream << program.getInitialConstruct() << std::endl;
}
if (program.specifiesSystemComposition()) { if (program.specifiesSystemComposition()) {
stream << program.getSystemCompositionConstruct(); stream << program.getSystemCompositionConstruct();

36
src/storage/prism/Program.h

@ -175,7 +175,7 @@ namespace storm {
* @return The global boolean variables of the program. * @return The global boolean variables of the program.
*/ */
std::vector<BooleanVariable> const& getGlobalBooleanVariables() const; std::vector<BooleanVariable> const& getGlobalBooleanVariables() const;
/*! /*!
* Retrieves a the global boolean variable with the given name. * Retrieves a the global boolean variable with the given name.
* *
@ -285,12 +285,31 @@ namespace storm {
*/ */
std::map<std::string, uint_fast64_t> const& getActionNameToIndexMapping() const; std::map<std::string, uint_fast64_t> const& getActionNameToIndexMapping() const;
/*!
* Retrieves whether the program specifies an initial construct.
*/
bool hasInitialConstruct() const;
/*! /*!
* Retrieves the initial construct of the program. * Retrieves the initial construct of the program.
* *
* @return The initial construct of the program. * @return The initial construct of the program.
*/ */
InitialConstruct const& getInitialConstruct() const; InitialConstruct const& getInitialConstruct() const;
/*!
* Retrieves an optional containing the initial construct of the program if there is any and nothing otherwise.
*
* @return The initial construct of the program.
*/
boost::optional<InitialConstruct> const& getOptionalInitialConstruct() const;
/*!
* Retrieves an expression characterizing the initial states.
*
* @return an expression characterizing the initial states.
*/
storm::expressions::Expression getInitialStatesExpression() const;
/*! /*!
* Retrieves whether the program specifies a system composition in terms of process algebra operations over * Retrieves whether the program specifies a system composition in terms of process algebra operations over
@ -587,6 +606,11 @@ namespace storm {
*/ */
Command synchronizeCommands(uint_fast64_t newCommandIndex, uint_fast64_t actionIndex, uint_fast64_t firstUpdateIndex, std::string const& actionName, std::vector<std::reference_wrapper<Command const>> const& commands) const; Command synchronizeCommands(uint_fast64_t newCommandIndex, uint_fast64_t actionIndex, uint_fast64_t firstUpdateIndex, std::string const& actionName, std::vector<std::reference_wrapper<Command const>> const& commands) const;
/*!
* Equips all global variables without initial values with initial values based on their type.
*/
void createMissingInitialValues();
// The manager responsible for the variables/expressions of the program. // The manager responsible for the variables/expressions of the program.
std::shared_ptr<storm::expressions::ExpressionManager> manager; std::shared_ptr<storm::expressions::ExpressionManager> manager;
@ -633,7 +657,7 @@ namespace storm {
std::map<std::string, uint_fast64_t> rewardModelToIndexMap; std::map<std::string, uint_fast64_t> rewardModelToIndexMap;
// The initial construct of the program. // The initial construct of the program.
InitialConstruct initialConstruct; boost::optional<InitialConstruct> initialConstruct;
// If set, this specifies the way the modules are composed to obtain the full system. // If set, this specifies the way the modules are composed to obtain the full system.
boost::optional<SystemCompositionConstruct> systemCompositionConstruct; boost::optional<SystemCompositionConstruct> systemCompositionConstruct;
@ -661,14 +685,6 @@ namespace storm {
// A mapping from variable names to the modules in which they were declared. // A mapping from variable names to the modules in which they were declared.
std::map<std::string, uint_fast64_t> variableToModuleIndexMap; std::map<std::string, uint_fast64_t> variableToModuleIndexMap;
/**
* Takes the current program and replaces all modules. As we reuse the expression manager, we recommend to not use the original program any further.
* @param newModules the modules which replace the old modules.
* @param newConstants the constants which replace the old constants.
* @return A program with the new modules and constants.
*/
Program replaceModulesAndConstantsInProgram(std::vector<Module> const& newModules, std::vector<Constant> const& newConstants);
}; };
std::ostream& operator<<(std::ostream& out, Program::ModelType const& type); std::ostream& operator<<(std::ostream& out, Program::ModelType const& type);

18
src/storage/prism/RewardModel.cpp

@ -81,6 +81,24 @@ namespace storm {
return true; return true;
} }
RewardModel RewardModel::restrictActionRelatedRewards(boost::container::flat_set<uint_fast64_t> const& actionIndicesToKeep) const {
std::vector<StateActionReward> newStateActionRewards;
for (auto const& stateActionReward : this->getStateActionRewards()) {
if (actionIndicesToKeep.find(stateActionReward.getActionIndex()) != actionIndicesToKeep.end()) {
newStateActionRewards.emplace_back(stateActionReward);
}
}
std::vector<TransitionReward> newTransitionRewards;
for (auto const& transitionReward : this->getTransitionRewards()) {
if (actionIndicesToKeep.find(transitionReward.getActionIndex()) != actionIndicesToKeep.end()) {
newTransitionRewards.emplace_back(transitionReward);
}
}
return RewardModel(this->getName(), this->getStateRewards(), newStateActionRewards, newTransitionRewards, this->getFilename(), this->getLineNumber());
}
std::ostream& operator<<(std::ostream& stream, RewardModel const& rewardModel) { std::ostream& operator<<(std::ostream& stream, RewardModel const& rewardModel) {
stream << "rewards"; stream << "rewards";
if (rewardModel.getName() != "") { if (rewardModel.getName() != "") {

9
src/storage/prism/RewardModel.h

@ -4,6 +4,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <map> #include <map>
#include <boost/container/flat_set.hpp>
#include "src/storage/prism/StateReward.h" #include "src/storage/prism/StateReward.h"
#include "src/storage/prism/StateActionReward.h" #include "src/storage/prism/StateActionReward.h"
@ -108,6 +109,14 @@ namespace storm {
*/ */
bool containsVariablesOnlyInRewardValueExpressions(std::set<storm::expressions::Variable> const& undefinedConstantVariables) const; bool containsVariablesOnlyInRewardValueExpressions(std::set<storm::expressions::Variable> const& undefinedConstantVariables) const;
/*!
* Restricts all action-related rewards of the reward model to the ones with an action index in the provided set.
*
* @param actionIndicesToKeep The set of action indices to keep.
* @return The resulting reward model.
*/
RewardModel restrictActionRelatedRewards(boost::container::flat_set<uint_fast64_t> const& actionIndicesToKeep) const;
friend std::ostream& operator<<(std::ostream& stream, RewardModel const& rewardModel); friend std::ostream& operator<<(std::ostream& stream, RewardModel const& rewardModel);
private: private:

12
src/storage/prism/Variable.cpp

@ -5,11 +5,11 @@
namespace storm { namespace storm {
namespace prism { namespace prism {
Variable::Variable(storm::expressions::Variable const& variable, storm::expressions::Expression const& initialValueExpression, bool defaultInitialValue, std::string const& filename, uint_fast64_t lineNumber) : LocatedInformation(filename, lineNumber), variable(variable), initialValueExpression(initialValueExpression), defaultInitialValue(defaultInitialValue) { Variable::Variable(storm::expressions::Variable const& variable, storm::expressions::Expression const& initialValueExpression, bool defaultInitialValue, std::string const& filename, uint_fast64_t lineNumber) : LocatedInformation(filename, lineNumber), variable(variable), initialValueExpression(initialValueExpression) {
// Nothing to do here. // Nothing to do here.
} }
Variable::Variable(storm::expressions::ExpressionManager& manager, Variable const& oldVariable, std::string const& newName, std::map<storm::expressions::Variable, storm::expressions::Expression> const& renaming, std::string const& filename, uint_fast64_t lineNumber) : LocatedInformation(filename, lineNumber), variable(manager.declareVariable(newName, oldVariable.variable.getType())), initialValueExpression(oldVariable.getInitialValueExpression().substitute(renaming)), defaultInitialValue(oldVariable.hasDefaultInitialValue()) { Variable::Variable(storm::expressions::ExpressionManager& manager, Variable const& oldVariable, std::string const& newName, std::map<storm::expressions::Variable, storm::expressions::Expression> const& renaming, std::string const& filename, uint_fast64_t lineNumber) : LocatedInformation(filename, lineNumber), variable(manager.declareVariable(newName, oldVariable.variable.getType())), initialValueExpression(oldVariable.getInitialValueExpression().substitute(renaming)) {
// Intentionally left empty. // Intentionally left empty.
} }
@ -17,14 +17,18 @@ namespace storm {
return this->variable.getName(); return this->variable.getName();
} }
bool Variable::hasDefaultInitialValue() const { bool Variable::hasInitialValue() const {
return this->defaultInitialValue; return this->initialValueExpression.isInitialized();
} }
storm::expressions::Expression const& Variable::getInitialValueExpression() const { storm::expressions::Expression const& Variable::getInitialValueExpression() const {
return this->initialValueExpression; return this->initialValueExpression;
} }
void Variable::setInitialValueExpression(storm::expressions::Expression const& initialValueExpression) {
this->initialValueExpression = initialValueExpression;
}
storm::expressions::Variable const& Variable::getExpressionVariable() const { storm::expressions::Variable const& Variable::getExpressionVariable() const {
return this->variable; return this->variable;
} }

27
src/storage/prism/Variable.h

@ -28,19 +28,27 @@ namespace storm {
std::string const& getName() const; std::string const& getName() const;
/*! /*!
* Retrieves the expression defining the initial value of the variable. * Retrieves whether the variable has an initial value.
*
* @return True iff the variable has an initial value.
*/
bool hasInitialValue() const;
/*!
* Retrieves the expression defining the initial value of the variable. This can only be called if there is
* an initial value (expression).
* *
* @return The expression defining the initial value of the variable. * @return The expression defining the initial value of the variable.
*/ */
storm::expressions::Expression const& getInitialValueExpression() const; storm::expressions::Expression const& getInitialValueExpression() const;
/*! /*!
* Retrieves whether the variable has the default initial value with respect to its type. * Sets the expression defining the initial value of the variable.
* *
* @return True iff the variable has the default initial value. * @param initialValueExpression The expression defining the initial value of the variable.
*/ */
bool hasDefaultInitialValue() const; void setInitialValueExpression(storm::expressions::Expression const& initialValueExpression);
/*! /*!
* Retrieves the expression variable associated with this variable. * Retrieves the expression variable associated with this variable.
* *
@ -55,6 +63,10 @@ namespace storm {
*/ */
storm::expressions::Expression getExpression() const; storm::expressions::Expression getExpression() const;
/*!
* Equips the variable with an initial value based on its type if not initial value is present.
*/
virtual void createMissingInitialValue() = 0;
// Make the constructors protected to forbid instantiation of this class. // Make the constructors protected to forbid instantiation of this class.
protected: protected:
@ -90,9 +102,6 @@ namespace storm {
// The constant expression defining the initial value of the variable. // The constant expression defining the initial value of the variable.
storm::expressions::Expression initialValueExpression; storm::expressions::Expression initialValueExpression;
// A flag that stores whether the variable has its default initial expression.
bool defaultInitialValue;
}; };
} // namespace prism } // namespace prism

13
src/storm.cpp

@ -6,6 +6,7 @@
#include "src/utility/initialize.h" #include "src/utility/initialize.h"
#include "src/settings/SettingsManager.h" #include "src/settings/SettingsManager.h"
#include "src/settings/modules/GeneralSettings.h"
/*! /*!
* Main entry point of the executable storm. * Main entry point of the executable storm.
@ -13,7 +14,7 @@
int main(const int argc, const char** argv) { int main(const int argc, const char** argv) {
try { try {
auto starttime = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
storm::utility::setUp(); storm::utility::setUp();
storm::cli::printHeader("Storm", argc, argv); storm::cli::printHeader("Storm", argc, argv);
storm::settings::initializeAll("Storm", "storm"); storm::settings::initializeAll("Storm", "storm");
@ -27,11 +28,11 @@ int main(const int argc, const char** argv) {
// All operations have now been performed, so we clean up everything and terminate. // All operations have now been performed, so we clean up everything and terminate.
storm::utility::cleanUp(); storm::utility::cleanUp();
auto endtime = std::chrono::high_resolution_clock::now(); auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endtime-starttime); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
auto durationSec = std::chrono::duration_cast<std::chrono::seconds>(endtime-starttime); auto durationSec = std::chrono::duration_cast<std::chrono::seconds>(end - start);
if(storm::settings::getModule<storm::settings::modules::IOSettings>().isPrintTimingsSet()) { if(storm::settings::getModule<storm::settings::modules::GeneralSettings>().isPrintTimingsSet()) {
std::cout << "Overal runtime: " << duration.count() << " ms. ( approx " << durationSec.count() << " seconds)." << std::endl; std::cout << "Overal runtime: " << duration.count() << " ms. (approximately " << durationSec.count() << " seconds)." << std::endl;
} }
return 0; return 0;
} catch (storm::exceptions::BaseException const& exception) { } catch (storm::exceptions::BaseException const& exception) {

72
src/utility/constants.cpp

@ -39,6 +39,23 @@ namespace storm {
bool isConstant(ValueType const& a) { bool isConstant(ValueType const& a) {
return true; return true;
} }
template<typename ValueType>
bool isInteger(ValueType const& number) {
ValueType iPart;
ValueType result = std::modf(number, &iPart);
return result = zero<ValueType>();
}
template<>
bool isInteger(int const& number) {
return true;
}
template<>
bool isInteger(uint_fast64_t const& number) {
return true;
}
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
template<> template<>
@ -50,7 +67,6 @@ namespace storm {
bool isZero(storm::RationalNumber const& a) { bool isZero(storm::RationalNumber const& a) {
return carl::isZero(a); return carl::isZero(a);
} }
template<> template<>
bool isOne(storm::RationalFunction const& a) { bool isOne(storm::RationalFunction const& a) {
@ -93,6 +109,16 @@ namespace storm {
// FIXME: this should be treated more properly. // FIXME: this should be treated more properly.
return storm::RationalNumber(-1); return storm::RationalNumber(-1);
} }
template<>
bool isInteger(storm::RationalNumber const& number) {
return carl::isInteger(number);
}
template<>
bool isInteger(storm::RationalFunction const& func) {
return storm::utility::isConstant(func) && storm::utility::isOne(func.denominator());
}
#endif #endif
template<typename ValueType> template<typename ValueType>
@ -102,9 +128,9 @@ namespace storm {
template<typename ValueType> template<typename ValueType>
ValueType simplify(ValueType value) { ValueType simplify(ValueType value) {
// In the general case, we don't do anything here, but merely return the value. If something else is // In the general case, we don't do anything here, but merely return the value. If something else is
// supposed to happen here, the templated function can be specialized for this particular type. // supposed to happen here, the templated function can be specialized for this particular type.
return value; return value;
} }
template<> template<>
@ -151,7 +177,12 @@ namespace storm {
double convertNumber(RationalNumber const& number){ double convertNumber(RationalNumber const& number){
return carl::toDouble(number); return carl::toDouble(number);
} }
template<>
uint_fast64_t convertNumber(RationalNumber const& number){
return carl::toInt<unsigned long>(number);
}
template<> template<>
RationalNumber convertNumber(double const& number){ RationalNumber convertNumber(double const& number){
return carl::rationalize<RationalNumber>(number); return carl::rationalize<RationalNumber>(number);
@ -167,15 +198,31 @@ namespace storm {
return RationalFunction(carl::rationalize<RationalNumber>(number)); return RationalFunction(carl::rationalize<RationalNumber>(number));
} }
template<>
RationalNumber convertNumber(std::string const& number) {
return carl::rationalize<RationalNumber>(number);
}
template<> template<>
RationalFunction convertNumber(RationalNumber const& number) { RationalFunction convertNumber(RationalNumber const& number) {
return RationalFunction(number); return RationalFunction(number);
} }
template<> template<>
storm::RationalNumber abs(storm::RationalNumber const& number) { uint_fast64_t convertNumber(RationalFunction const& func) {
return carl::toInt<unsigned long>(func.nominatorAsNumber());
}
template<>
RationalNumber abs(storm::RationalNumber const& number) {
return carl::abs(number); return carl::abs(number);
} }
template<>
RationalNumber pow(RationalNumber const& value, uint_fast64_t exponent) {
return carl::pow(value, exponent);
}
#endif #endif
template<typename IndexType, typename ValueType> template<typename IndexType, typename ValueType>
@ -214,6 +261,7 @@ namespace storm {
template storm::storage::MatrixEntry<storm::storage::sparse::state_type, double>&& simplify(storm::storage::MatrixEntry<storm::storage::sparse::state_type, double>&& matrixEntry); template storm::storage::MatrixEntry<storm::storage::sparse::state_type, double>&& simplify(storm::storage::MatrixEntry<storm::storage::sparse::state_type, double>&& matrixEntry);
template double abs(double const& number); template double abs(double const& number);
template bool isInteger(double const& number);
template bool isOne(float const& value); template bool isOne(float const& value);
template bool isZero(float const& value); template bool isZero(float const& value);
@ -224,6 +272,7 @@ namespace storm {
template float infinity(); template float infinity();
template float pow(float const& value, uint_fast64_t exponent); template float pow(float const& value, uint_fast64_t exponent);
template bool isInteger(float const& number);
template float simplify(float value); template float simplify(float value);
@ -240,7 +289,8 @@ namespace storm {
template int infinity(); template int infinity();
template int pow(int const& value, uint_fast64_t exponent); template int pow(int const& value, uint_fast64_t exponent);
template bool isInteger(int const& number);
template int simplify(int value); template int simplify(int value);
template storm::storage::MatrixEntry<storm::storage::sparse::state_type, int> simplify(storm::storage::MatrixEntry<storm::storage::sparse::state_type, int> matrixEntry); template storm::storage::MatrixEntry<storm::storage::sparse::state_type, int> simplify(storm::storage::MatrixEntry<storm::storage::sparse::state_type, int> matrixEntry);
@ -278,12 +328,14 @@ namespace storm {
template storm::RationalNumber infinity(); template storm::RationalNumber infinity();
template double convertNumber(storm::RationalNumber const& number); template double convertNumber(storm::RationalNumber const& number);
template uint_fast64_t convertNumber(storm::RationalNumber const& number);
template storm::RationalNumber convertNumber(double const& number); template storm::RationalNumber convertNumber(double const& number);
template storm::RationalNumber convertNumber(storm::RationalNumber const& number); template storm::RationalNumber convertNumber(storm::RationalNumber const& number);
RationalNumber convertNumber(std::string const& number);
template storm::RationalNumber abs(storm::RationalNumber const& number); template storm::RationalNumber abs(storm::RationalNumber const& number);
// template storm::RationalNumber pow(storm::RationalNumber const& value, uint_fast64_t exponent); template storm::RationalNumber pow(storm::RationalNumber const& value, uint_fast64_t exponent);
template storm::RationalNumber simplify(storm::RationalNumber value); template storm::RationalNumber simplify(storm::RationalNumber value);
template storm::storage::MatrixEntry<storm::storage::sparse::state_type, storm::RationalNumber> simplify(storm::storage::MatrixEntry<storm::storage::sparse::state_type, storm::RationalNumber> matrixEntry); template storm::storage::MatrixEntry<storm::storage::sparse::state_type, storm::RationalNumber> simplify(storm::storage::MatrixEntry<storm::storage::sparse::state_type, storm::RationalNumber> matrixEntry);

3
src/utility/constants.h

@ -56,6 +56,9 @@ namespace storm {
template<typename ValueType> template<typename ValueType>
ValueType abs(ValueType const& number); ValueType abs(ValueType const& number);
template<typename ValueType>
bool isInteger(ValueType const& number);
} }
} }

2
src/utility/storm.cpp

@ -10,7 +10,7 @@
namespace storm { namespace storm {
storm::prism::Program parseProgram(std::string const& path) { storm::prism::Program parseProgram(std::string const& path) {
storm::prism::Program program= storm::parser::PrismParser::parse(path).simplify().simplify(); storm::prism::Program program = storm::parser::PrismParser::parse(path).simplify().simplify();
program.checkValidity(); program.checkValidity();
return program; return program;
} }

4
src/utility/storm.h

@ -382,10 +382,10 @@ namespace storm {
if (model->getType() == storm::models::ModelType::Dtmc) { if (model->getType() == storm::models::ModelType::Dtmc) {
result = verifySparseDtmc(model->template as<storm::models::sparse::Dtmc<storm::RationalFunction>>(), task); result = verifySparseDtmc(model->template as<storm::models::sparse::Dtmc<storm::RationalFunction>>(), task);
} else if (model->getType() == storm::models::ModelType::Mdp) { } else if (model->getType() == storm::models::ModelType::Mdp) {
std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> mdp = model->template as<storm::models::sparse::Mdp<storm::RationalFunction>>(); //std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> mdp = model->template as<storm::models::sparse::Mdp<storm::RationalFunction>>();
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The parametric engine currently does not support MDPs."); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The parametric engine currently does not support MDPs.");
} else if (model->getType() == storm::models::ModelType::Ctmc) { } else if (model->getType() == storm::models::ModelType::Ctmc) {
verifySparseCtmc(model->template as<storm::models::sparse::Ctmc<storm::RationalFunction>>(), task); result = verifySparseCtmc(model->template as<storm::models::sparse::Ctmc<storm::RationalFunction>>(), task);
} else { } else {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The parametric engine currently does not support " << model->getType()); STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The parametric engine currently does not support " << model->getType());
} }

4
test/functional/parser/PrismParserTest.cpp

@ -79,10 +79,6 @@ TEST(PrismParser, ComplexTest) {
module mod3 = mod1 [ i = i1, j = j1, k = k1 ] endmodule module mod3 = mod1 [ i = i1, j = j1, k = k1 ] endmodule
label "mal" = max(a, 10) > 0; label "mal" = max(a, 10) > 0;
init
true
endinit
rewards "testrewards" rewards "testrewards"
[a] true : a + 7; [a] true : a + 7;

10
util/osx-package/package.sh

@ -0,0 +1,10 @@
#!/bin/sh
DYLIBBUNDLER_DIR=/Users/chris/work/macdylibbundler/
mkdir -p $1
mkdir -p $1/bin
mkdir -p $1/lib
cp $2 $1/bin
$DYLIBBUNDLER_DIR/dylibbundler -cd -od -b -p @executable_path/../lib -x $1/bin/storm -d $1/lib
python packager.py --bin storm --dir $1

103
util/osx-package/packager.py

@ -0,0 +1,103 @@
import argparse
import subprocess
import os
from shutil import copyfile
def get_dependencies(file):
# Call otool -L file to obtain the dependencies.
proc = subprocess.Popen(["otool", "-L", args.binary], stdout=subprocess.PIPE)
result = {}
for line_bytes in proc.stdout:
line = line_bytes.decode("utf-8").strip()
lib = line.split()[0]
if (lib.startswith("@")):
lib = lib.split("/", 1)[1]
(base, file) = os.path.split(lib)
print(base + " // " + file)
return result
def create_package(args):
create_package_dirs(args.dir)
copy_binary_to_package_dir(args.bin, args.binary_basename, args.dir)
run_dylibbundler(args.bundler_binary, args.dir, args.binary_basename)
pass
def parse_arguments():
parser = argparse.ArgumentParser(description='Package the storm binary on Mac OS.')
parser.add_argument('--bin', dest='bin', help='the binary to package', default='storm')
parser.add_argument('--dir', dest='dir', help='the root directory of the package (will be created if it does not exist)', default='.')
parser.add_argument('--dylibbundler', dest='bundler_binary', help='the binary of the dylibbundler', default='dylibbundler')
args = parser.parse_args()
args.binary_dir = os.path.split(args.bin)[0]
args.binary_basename = os.path.split(args.bin)[1]
return args
def create_package_dirs(root_dir):
if not os.path.exists(root_dir):
os.makedirs(root_dir)
if not os.path.exists(root_dir + "/bin"):
os.makedirs(root_dir + "/bin")
if not os.path.exists(root_dir + "/lib"):
os.makedirs(root_dir + "/bin")
pass
def copy_binary_to_package_dir(binary, binary_basename, root_dir):
copyfile(binary, root_dir + "/bin/storm")
pass
def run_dylibbundler(bundler_binary, root_dir, binary_basename):
command = [bundler_binary, "-cd", "-od", "-b", "-p", "@executable_path/../lib", "-x", root_dir + "/bin/" + binary_basename, "-d", root_dir + "/lib"]
print("executing " + str(command))
#proc = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
pass
def fix_paths(root_dir, binary_basename):
fix_paths_file(root_dir + "/bin/" + binary_basename)
for file in os.listdir(root_dir + "/lib"):
fix_paths_file(root_dir + "/lib/" + file)
pass
pass
def fix_paths_file(file):
print("fixing paths for " + file)
fixable_deps = get_fixable_deps(file)
for (path, lib) in fixable_deps:
change_fixable_dep(file, path, lib)
native_libs = ["libc++.1.dylib", "libSystem.B.dylib"]
def get_fixable_deps(file):
# Call otool -L file to obtain the dependencies.
proc = subprocess.Popen(["otool", "-L", file], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
result = []
for line_bytes in proc.stdout:
line = line_bytes.decode("utf-8").strip()
lib = line.split()[0]
if lib.startswith("@rpath/"):
result.append(("@rpath", lib.split("/", 1)[1]))
elif lib.startswith("/"):
path_file = os.path.split(lib)
if path_file[1] not in native_libs:
result.append((path_file[0], path_file[1]))
return result
def change_fixable_dep(file, path, lib):
# Call install_name_tool to change the fixable dependencies
command = ["install_name_tool", "-change", path + "/" + lib, "@executable_path/../lib/" + lib, file]
print("executing " + str(command))
proc = subprocess.Popen(command, stdout=subprocess.PIPE)
#print ("after call to install_name_tool")
#proc = subprocess.Popen(["otool", "-L", file], stdout=subprocess.PIPE)
#for line_bytes in proc.stdout:
# line = line_bytes.decode("utf-8").strip()
# print(line)
pass
if __name__ == "__main__":
args = parse_arguments()
#create_package(args)
fix_paths(args.dir, args.binary_basename)
|||||||
100:0
Loading…
Cancel
Save