From e43dfc278409729580d78ce4f9a4a8a527d4e4c6 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Thu, 11 Aug 2016 16:24:43 +0200 Subject: [PATCH 01/34] removed unused setting Former-commit-id: 18a91c2acb82ec553b91370047e20e4ef3872281 --- src/settings/modules/CoreSettings.cpp | 5 ----- src/settings/modules/CoreSettings.h | 1 - 2 files changed, 6 deletions(-) diff --git a/src/settings/modules/CoreSettings.cpp b/src/settings/modules/CoreSettings.cpp index b42a301c8..5a6dfc9c0 100644 --- a/src/settings/modules/CoreSettings.cpp +++ b/src/settings/modules/CoreSettings.cpp @@ -30,7 +30,6 @@ namespace storm { const std::string CoreSettings::engineOptionShortName = "e"; const std::string CoreSettings::ddLibraryOptionName = "ddlib"; const std::string CoreSettings::cudaOptionName = "cuda"; - const std::string CoreSettings::minMaxEquationSolvingTechniqueOptionName = "ndmethod"; CoreSettings::CoreSettings() : ModuleSettings(moduleName), engine(CoreSettings::Engine::Sparse) { this->addOption(storm::settings::OptionBuilder(moduleName, counterexampleOptionName, false, "Generates a counterexample for the given PRCTL formulas if not satisfied by the model") @@ -57,10 +56,6 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of an SMT solver. Available are: z3 and mathsat.").addValidationFunctionString(storm::settings::ArgumentValidators::stringInListValidator(smtSolvers)).setDefaultValueString("z3").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, statisticsOptionName, false, "Sets whether to display statistics if available.").setShortName(statisticsOptionShortName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, cudaOptionName, false, "Sets whether to use CUDA to speed up computation time.").build()); - - std::vector<std::string> minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration"}; - this->addOption(storm::settings::OptionBuilder(moduleName, minMaxEquationSolvingTechniqueOptionName, false, "Sets which min/max linear equation solving technique is preferred.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a min/max linear equation solving technique. Available are: value-iteration (vi) and policy-iteration (pi).").addValidationFunctionString(storm::settings::ArgumentValidators::stringInListValidator(minMaxSolvingTechniques)).setDefaultValueString("vi").build()).build()); } bool CoreSettings::isCounterexampleSet() const { diff --git a/src/settings/modules/CoreSettings.h b/src/settings/modules/CoreSettings.h index 9b7189e2c..f6c8fbdf2 100644 --- a/src/settings/modules/CoreSettings.h +++ b/src/settings/modules/CoreSettings.h @@ -151,7 +151,6 @@ namespace storm { static const std::string engineOptionShortName; static const std::string ddLibraryOptionName; static const std::string cudaOptionName; - static const std::string minMaxEquationSolvingTechniqueOptionName; }; } // namespace modules From 7ab88457a71851fe7d1245d0aedebac1c4fdff5c Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Thu, 11 Aug 2016 18:07:58 +0200 Subject: [PATCH 02/34] corrected reference to wrong settings module Former-commit-id: 2f35b2dc82efbb76fed5fb17696a13599d9fadd7 --- src/storm.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/storm.cpp b/src/storm.cpp index 0d23f9ecc..236d15a7b 100644 --- a/src/storm.cpp +++ b/src/storm.cpp @@ -6,6 +6,7 @@ #include "src/utility/initialize.h" #include "src/settings/SettingsManager.h" +#include "src/settings/modules/GeneralSettings.h" /*! * Main entry point of the executable storm. @@ -13,7 +14,7 @@ int main(const int argc, const char** argv) { try { - auto starttime = std::chrono::high_resolution_clock::now(); + auto start = std::chrono::high_resolution_clock::now(); storm::utility::setUp(); storm::cli::printHeader("Storm", argc, argv); 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. storm::utility::cleanUp(); - auto endtime = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endtime-starttime); - auto durationSec = std::chrono::duration_cast<std::chrono::seconds>(endtime-starttime); - if(storm::settings::getModule<storm::settings::modules::IOSettings>().isPrintTimingsSet()) { - std::cout << "Overal runtime: " << duration.count() << " ms. ( approx " << durationSec.count() << " seconds)." << std::endl; + auto end = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); + auto durationSec = std::chrono::duration_cast<std::chrono::seconds>(end - start); + if(storm::settings::getModule<storm::settings::modules::GeneralSettings>().isPrintTimingsSet()) { + std::cout << "Overal runtime: " << duration.count() << " ms. (approximately " << durationSec.count() << " seconds)." << std::endl; } return 0; } catch (storm::exceptions::BaseException const& exception) { From 569b27e11055cb63a1c7c183d1abeff743a242ea Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 15 Aug 2016 14:49:21 +0200 Subject: [PATCH 03/34] work towards having rational numbers instead of doubles as literals in expressions Former-commit-id: c62f8af0612a5cc4c351d79cd224f6439b523e99 --- src/adapters/AddExpressionAdapter.cpp | 2 +- src/adapters/MathsatExpressionAdapter.h | 2 +- .../expressions/DoubleLiteralExpression.cpp | 16 ++++- .../expressions/DoubleLiteralExpression.h | 25 ++++++-- .../expressions/LinearCoefficientVisitor.cpp | 2 +- .../expressions/ToRationalFunctionVisitor.cpp | 3 +- .../expressions/ToRationalNumberVisitor.cpp | 29 ++++++--- src/utility/constants.cpp | 61 ++++++++++++++++--- src/utility/constants.h | 3 + 9 files changed, 114 insertions(+), 29 deletions(-) diff --git a/src/adapters/AddExpressionAdapter.cpp b/src/adapters/AddExpressionAdapter.cpp index e50620db8..7a22c8f8f 100644 --- a/src/adapters/AddExpressionAdapter.cpp +++ b/src/adapters/AddExpressionAdapter.cpp @@ -195,7 +195,7 @@ namespace storm { template<storm::dd::DdType Type, typename ValueType> boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::DoubleLiteralExpression const& expression) { - return ddManager->getConstant(static_cast<ValueType>(expression.getValue())); + return ddManager->getConstant(static_cast<ValueType>(expression.getValueAsDouble())); } // Explicitly instantiate the symbolic expression adapter diff --git a/src/adapters/MathsatExpressionAdapter.h b/src/adapters/MathsatExpressionAdapter.h index 9fec0cf15..db5bf9b69 100644 --- a/src/adapters/MathsatExpressionAdapter.h +++ b/src/adapters/MathsatExpressionAdapter.h @@ -172,7 +172,7 @@ namespace storm { } virtual boost::any visit(expressions::DoubleLiteralExpression 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 { diff --git a/src/storage/expressions/DoubleLiteralExpression.cpp b/src/storage/expressions/DoubleLiteralExpression.cpp index cab9fc31b..192d747ee 100644 --- a/src/storage/expressions/DoubleLiteralExpression.cpp +++ b/src/storage/expressions/DoubleLiteralExpression.cpp @@ -2,14 +2,20 @@ #include "src/storage/expressions/ExpressionManager.h" #include "src/storage/expressions/ExpressionVisitor.h" +#include "src/utility/constants.h" + namespace storm { namespace expressions { - DoubleLiteralExpression::DoubleLiteralExpression(ExpressionManager const& manager, double value) : BaseExpression(manager, manager.getRationalType()), value(value) { + DoubleLiteralExpression::DoubleLiteralExpression(ExpressionManager const& manager, double value) : BaseExpression(manager, manager.getRationalType()), value(storm::utility::convertNumber<storm::RationalNumber>(value)) { + // Intentionally left empty. + } + + DoubleLiteralExpression::DoubleLiteralExpression(ExpressionManager const& manager, std::string const& valueAsString) : BaseExpression(manager, manager.getRationalType()), value(storm::utility::convertNumber<storm::RationalNumber>(valueAsString)) { // Intentionally left empty. } double DoubleLiteralExpression::evaluateAsDouble(Valuation const* valuation) const { - return this->getValue(); + return this->getValueAsDouble(); } bool DoubleLiteralExpression::isLiteral() const { @@ -28,7 +34,11 @@ namespace storm { return visitor.visit(*this); } - double DoubleLiteralExpression::getValue() const { + double DoubleLiteralExpression::getValueAsDouble() const { + return storm::utility::convertNumber<double>(this->value); + } + + storm::RationalNumber DoubleLiteralExpression::getValue() const { return this->value; } diff --git a/src/storage/expressions/DoubleLiteralExpression.h b/src/storage/expressions/DoubleLiteralExpression.h index 676291a77..6a04f23e3 100644 --- a/src/storage/expressions/DoubleLiteralExpression.h +++ b/src/storage/expressions/DoubleLiteralExpression.h @@ -4,6 +4,8 @@ #include "src/storage/expressions/BaseExpression.h" #include "src/utility/OsDetection.h" +#include "src/adapters/CarlAdapter.h" + namespace storm { namespace expressions { class DoubleLiteralExpression : public BaseExpression { @@ -15,7 +17,15 @@ namespace storm { * @param value The value of the double literal. */ DoubleLiteralExpression(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. + */ + DoubleLiteralExpression(ExpressionManager const& manager, std::string const& valueAsString); + // Instantiate constructors and assignments with their default implementations. DoubleLiteralExpression(DoubleLiteralExpression const& other) = default; DoubleLiteralExpression& operator=(DoubleLiteralExpression const& other) = delete; @@ -37,15 +47,22 @@ namespace storm { * * @return The value of the double literal. */ - double getValue() const; + 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 double literal. - double value; + // The value of the literal. + storm::RationalNumber value; }; } } diff --git a/src/storage/expressions/LinearCoefficientVisitor.cpp b/src/storage/expressions/LinearCoefficientVisitor.cpp index 8d7f39278..3d881c25e 100644 --- a/src/storage/expressions/LinearCoefficientVisitor.cpp +++ b/src/storage/expressions/LinearCoefficientVisitor.cpp @@ -152,7 +152,7 @@ namespace storm { } boost::any LinearCoefficientVisitor::visit(DoubleLiteralExpression const& expression) { - return VariableCoefficients(expression.getValue()); + return VariableCoefficients(expression.getValueAsDouble()); } } } \ No newline at end of file diff --git a/src/storage/expressions/ToRationalFunctionVisitor.cpp b/src/storage/expressions/ToRationalFunctionVisitor.cpp index 1a3dd0fc3..533fa1f1f 100644 --- a/src/storage/expressions/ToRationalFunctionVisitor.cpp +++ b/src/storage/expressions/ToRationalFunctionVisitor.cpp @@ -2,6 +2,7 @@ #include <sstream> +#include "src/utility/constants.h" #include "src/utility/macros.h" #include "src/exceptions/InvalidArgumentException.h" @@ -93,7 +94,7 @@ namespace storm { template<typename RationalFunctionType> boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(DoubleLiteralExpression const& expression) { - return RationalFunctionType(carl::rationalize<storm::RationalNumber>(expression.getValue())); + return storm::utility::convertNumber<storm::RationalFunction>(expression.getValue()); } template class ToRationalFunctionVisitor<storm::RationalFunction>; diff --git a/src/storage/expressions/ToRationalNumberVisitor.cpp b/src/storage/expressions/ToRationalNumberVisitor.cpp index 785f36950..44194cb4b 100644 --- a/src/storage/expressions/ToRationalNumberVisitor.cpp +++ b/src/storage/expressions/ToRationalNumberVisitor.cpp @@ -1,6 +1,7 @@ #include "src/storage/expressions/ToRationalNumberVisitor.h" #include "src/utility/macros.h" +#include "src/utility/constants.h" #include "src/exceptions/InvalidArgumentException.h" #include "src/exceptions/NotSupportedException.h" @@ -28,26 +29,36 @@ namespace storm { template<typename RationalNumberType> boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryNumericalFunctionExpression const& expression) { - RationalNumberType firstOperandAsRationalFunction = boost::any_cast<RationalNumberType>(expression.getFirstOperand()->accept(*this)); - RationalNumberType secondOperandAsRationalFunction = boost::any_cast<RationalNumberType>(expression.getSecondOperand()->accept(*this)); + RationalNumberType firstOperandAsRationalNumber = boost::any_cast<RationalNumberType>(expression.getFirstOperand()->accept(*this)); + RationalNumberType secondOperandAsRationalNumber = boost::any_cast<RationalNumberType>(expression.getSecondOperand()->accept(*this)); switch(expression.getOperatorType()) { case BinaryNumericalFunctionExpression::OperatorType::Plus: - return firstOperandAsRationalFunction + secondOperandAsRationalFunction; + return firstOperandAsRationalNumber + secondOperandAsRationalNumber; break; case BinaryNumericalFunctionExpression::OperatorType::Minus: - return firstOperandAsRationalFunction - secondOperandAsRationalFunction; + return firstOperandAsRationalNumber - secondOperandAsRationalNumber; break; case BinaryNumericalFunctionExpression::OperatorType::Times: - return firstOperandAsRationalFunction * secondOperandAsRationalFunction; + return firstOperandAsRationalNumber * secondOperandAsRationalNumber; break; case BinaryNumericalFunctionExpression::OperatorType::Divide: - return firstOperandAsRationalFunction / secondOperandAsRationalFunction; + return firstOperandAsRationalNumber / secondOperandAsRationalNumber; + break; + case BinaryNumericalFunctionExpression::OperatorType::Min: + return std::min(firstOperandAsRationalNumber, secondOperandAsRationalNumber); + break; + case BinaryNumericalFunctionExpression::OperatorType::Max: + return std::max(firstOperandAsRationalNumber, secondOperandAsRationalNumber); + break; + case BinaryNumericalFunctionExpression::OperatorType::Power: + STORM_LOG_THROW(storm::utility::isInteger(secondOperandAsRationalNumber), storm::exceptions::InvalidArgumentException, "Exponent of power operator must be a positive integer."); + uint_fast64_t exponentAsInteger = storm::utility::convertNumber<uint_fast64_t>(secondOperandAsRationalNumber); + return storm::utility::pow(firstOperandAsRationalNumber, exponentAsInteger); break; - default: - STORM_LOG_ASSERT(false, "Illegal operator type."); } // Return a dummy. This point must, however, never be reached. + STORM_LOG_ASSERT(false, "Illegal operator type."); return boost::any(); } @@ -88,7 +99,7 @@ namespace storm { template<typename RationalNumberType> boost::any ToRationalNumberVisitor<RationalNumberType>::visit(DoubleLiteralExpression const& expression) { #ifdef STORM_HAVE_CARL - return RationalNumberType(carl::rationalize<storm::RationalNumber>(expression.getValue())); + return expression.getValue(); #else STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Rational numbers are not supported in this build."); #endif diff --git a/src/utility/constants.cpp b/src/utility/constants.cpp index 71d56cd63..2630ed285 100644 --- a/src/utility/constants.cpp +++ b/src/utility/constants.cpp @@ -39,6 +39,23 @@ namespace storm { bool isConstant(ValueType const& a) { 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 template<> @@ -50,7 +67,6 @@ namespace storm { bool isZero(storm::RationalNumber const& a) { return carl::isZero(a); } - template<> bool isOne(storm::RationalFunction const& a) { @@ -93,6 +109,12 @@ namespace storm { // FIXME: this should be treated more properly. return storm::RationalNumber(-1); } + + template<> + bool isInteger(storm::RationalNumber const& number) { + return carl::isInteger(number); + } + #endif template<typename ValueType> @@ -102,9 +124,9 @@ namespace storm { template<typename ValueType> ValueType simplify(ValueType value) { - // 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. - return value; + // 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. + return value; } template<> @@ -151,7 +173,12 @@ namespace storm { double convertNumber(RationalNumber const& number){ return carl::toDouble(number); } - + + template<> + uint_fast64_t convertNumber(RationalNumber const& number){ + return carl::toInt<unsigned long>(number); + } + template<> RationalNumber convertNumber(double const& number){ return carl::rationalize<RationalNumber>(number); @@ -167,15 +194,26 @@ namespace storm { return RationalFunction(carl::rationalize<RationalNumber>(number)); } + template<> + RationalNumber convertNumber(std::string const& number) { + return carl::rationalize<RationalNumber>(number); + } + template<> RationalFunction convertNumber(RationalNumber const& number) { return RationalFunction(number); } template<> - storm::RationalNumber abs(storm::RationalNumber const& number) { + RationalNumber abs(storm::RationalNumber const& number) { return carl::abs(number); } + + template<> + RationalNumber pow(RationalNumber const& value, uint_fast64_t exponent) { + return carl::pow(value, exponent); + } + #endif template<typename IndexType, typename ValueType> @@ -214,6 +252,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 double abs(double const& number); + template bool isInteger(double const& number); template bool isOne(float const& value); template bool isZero(float const& value); @@ -224,6 +263,7 @@ namespace storm { template float infinity(); template float pow(float const& value, uint_fast64_t exponent); + template bool isInteger(float const& number); template float simplify(float value); @@ -240,7 +280,8 @@ namespace storm { template int infinity(); template int pow(int const& value, uint_fast64_t exponent); - + template bool isInteger(int const& number); + 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); @@ -278,12 +319,14 @@ namespace storm { template storm::RationalNumber infinity(); 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(storm::RationalNumber const& number); - + RationalNumber convertNumber(std::string 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::storage::MatrixEntry<storm::storage::sparse::state_type, storm::RationalNumber> simplify(storm::storage::MatrixEntry<storm::storage::sparse::state_type, storm::RationalNumber> matrixEntry); diff --git a/src/utility/constants.h b/src/utility/constants.h index 4ec4e7539..66edb9f46 100644 --- a/src/utility/constants.h +++ b/src/utility/constants.h @@ -56,6 +56,9 @@ namespace storm { template<typename ValueType> ValueType abs(ValueType const& number); + + template<typename ValueType> + bool isInteger(ValueType const& number); } } From 7b2a667a9d28b0a81fef0f11116bb9dba652823d Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 15 Aug 2016 16:53:56 +0200 Subject: [PATCH 04/34] double literal now stores rational internally Former-commit-id: c0f089b8baa1c6bef553889fb708f8a44cae1937 --- src/parser/ExpressionParser.cpp | 32 +++++++++++++++++-- src/parser/ExpressionParser.h | 16 ++++++++-- .../expressions/DoubleLiteralExpression.cpp | 4 +++ .../expressions/DoubleLiteralExpression.h | 8 +++++ src/storage/expressions/ExpressionManager.cpp | 4 +++ src/storage/expressions/ExpressionManager.h | 9 ++++++ 6 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/parser/ExpressionParser.cpp b/src/parser/ExpressionParser.cpp index 20982bd20..d556d799a 100644 --- a/src/parser/ExpressionParser.cpp +++ b/src/parser/ExpressionParser.cpp @@ -3,6 +3,34 @@ #include "src/exceptions/InvalidTypeException.h" #include "src/exceptions/WrongFormatException.h" +#include "src/utility/constants.h" + +namespace boost { + namespace spirit { + namespace traits { + template<> + bool scale(int exp, storm::RationalNumber& r, storm::RationalNumber acc) { + if (exp >= 0) { + r = acc * storm::utility::pow(storm::RationalNumber(10), static_cast<uint_fast64_t>(exp)); + } else { + r = acc / storm::utility::pow(storm::RationalNumber(10), static_cast<uint_fast64_t>(-exp)); + } + return true; + } + + template<> + bool is_equal_to_one(storm::RationalNumber const& value) { + return storm::utility::isOne(value); + } + + template<> + storm::RationalNumber negate(bool neg, storm::RationalNumber const& number) { + return neg ? storm::RationalNumber(-number) : number; + } + } + } +} + namespace storm { namespace parser { ExpressionParser::ExpressionParser(storm::expressions::ExpressionManager const& manager, qi::symbols<char, uint_fast64_t> const& invalidIdentifiers_, bool enableErrorHandling, bool allowBacktracking) : ExpressionParser::base_type(expression), orOperator_(), andOperator_(), equalityOperator_(), relationalOperator_(), plusOperator_(), multiplicationOperator_(), infixPowerOperator_(), unaryOperator_(), floorCeilOperator_(), minMaxOperator_(), prefixPowerOperator_(), trueFalse_(manager), manager(manager.getSharedPointer()), createExpressions(false), acceptDoubleLiterals(true), identifiers_(nullptr), invalidIdentifiers_(invalidIdentifiers_) { @@ -33,7 +61,7 @@ namespace storm { identifierExpression = identifier[qi::_val = phoenix::bind(&ExpressionParser::getIdentifierExpression, phoenix::ref(*this), qi::_1, allowBacktracking, qi::_pass)]; identifierExpression.name("identifier expression"); - literalExpression = trueFalse_[qi::_val = qi::_1] | strict_double[qi::_val = phoenix::bind(&ExpressionParser::createDoubleLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)] | qi::int_[qi::_val = phoenix::bind(&ExpressionParser::createIntegerLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)]; + literalExpression = trueFalse_[qi::_val = qi::_1] | rationalLiteral_[qi::_val = phoenix::bind(&ExpressionParser::createDoubleLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)] | qi::int_[qi::_val = phoenix::bind(&ExpressionParser::createIntegerLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)]; literalExpression.name("literal expression"); atomicExpression = floorCeilExpression | prefixPowerExpression | minMaxExpression | (qi::lit("(") >> expression >> qi::lit(")")) | literalExpression | identifierExpression; @@ -295,7 +323,7 @@ namespace storm { return manager->boolean(false); } - storm::expressions::Expression ExpressionParser::createDoubleLiteralExpression(double value, bool& pass) const { + storm::expressions::Expression ExpressionParser::createDoubleLiteralExpression(storm::RationalNumber const& value, bool& pass) const { // If we are not supposed to accept double expressions, we reject it by setting pass to false. if (!this->acceptDoubleLiterals) { pass = false; diff --git a/src/parser/ExpressionParser.h b/src/parser/ExpressionParser.h index 66d851707..c728e0b84 100644 --- a/src/parser/ExpressionParser.h +++ b/src/parser/ExpressionParser.h @@ -8,8 +8,20 @@ #include "src/storage/expressions/Expression.h" #include "src/storage/expressions/ExpressionManager.h" +#include "src/adapters/CarlAdapter.h" + namespace storm { namespace parser { + template<typename NumberType> + struct RationalPolicies : boost::spirit::qi::strict_real_policies<NumberType> { + static const bool expect_dot = true; + + template <typename It, typename Attr> + static bool parse_nan(It&, It const&, Attr&) { return false; } + template <typename It, typename Attr> + static bool parse_inf(It&, It const&, Attr&) { return false; } + }; + class ExpressionParser : public qi::grammar<Iterator, storm::expressions::Expression(), Skipper> { public: /*! @@ -236,7 +248,7 @@ namespace storm { qi::rule<Iterator, std::string(), Skipper> identifier; // Parser that is used to recognize doubles only (as opposed to Spirit's double_ parser). - boost::spirit::qi::real_parser<double, boost::spirit::qi::strict_real_policies<double>> strict_double; + boost::spirit::qi::real_parser<storm::RationalNumber, RationalPolicies<storm::RationalNumber>> rationalLiteral_; // Helper functions to create expressions. storm::expressions::Expression createIteExpression(storm::expressions::Expression e1, storm::expressions::Expression e2, storm::expressions::Expression e3, bool& pass) const; @@ -248,7 +260,7 @@ namespace storm { storm::expressions::Expression createMultExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; storm::expressions::Expression createPowerExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; storm::expressions::Expression createUnaryExpression(boost::optional<storm::expressions::OperatorType> const& operatorType, storm::expressions::Expression const& e1, bool& pass) const; - storm::expressions::Expression createDoubleLiteralExpression(double value, bool& pass) const; + storm::expressions::Expression createDoubleLiteralExpression(storm::RationalNumber const& value, bool& pass) const; storm::expressions::Expression createIntegerLiteralExpression(int value, bool& pass) const; storm::expressions::Expression createMinimumMaximumExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; storm::expressions::Expression createFloorCeilExpression(storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e1, bool& pass) const; diff --git a/src/storage/expressions/DoubleLiteralExpression.cpp b/src/storage/expressions/DoubleLiteralExpression.cpp index 192d747ee..86a2ba889 100644 --- a/src/storage/expressions/DoubleLiteralExpression.cpp +++ b/src/storage/expressions/DoubleLiteralExpression.cpp @@ -14,6 +14,10 @@ namespace storm { // Intentionally left empty. } + DoubleLiteralExpression::DoubleLiteralExpression(ExpressionManager const& manager, storm::RationalNumber const& value) : BaseExpression(manager, manager.getRationalType()), value(value) { + // Intentionally left empty. + } + double DoubleLiteralExpression::evaluateAsDouble(Valuation const* valuation) const { return this->getValueAsDouble(); } diff --git a/src/storage/expressions/DoubleLiteralExpression.h b/src/storage/expressions/DoubleLiteralExpression.h index 6a04f23e3..1b6aa28b3 100644 --- a/src/storage/expressions/DoubleLiteralExpression.h +++ b/src/storage/expressions/DoubleLiteralExpression.h @@ -26,6 +26,14 @@ namespace storm { */ DoubleLiteralExpression(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. + */ + DoubleLiteralExpression(ExpressionManager const& manager, storm::RationalNumber const& value); + // Instantiate constructors and assignments with their default implementations. DoubleLiteralExpression(DoubleLiteralExpression const& other) = default; DoubleLiteralExpression& operator=(DoubleLiteralExpression const& other) = delete; diff --git a/src/storage/expressions/ExpressionManager.cpp b/src/storage/expressions/ExpressionManager.cpp index d1add4402..a92d908f3 100644 --- a/src/storage/expressions/ExpressionManager.cpp +++ b/src/storage/expressions/ExpressionManager.cpp @@ -68,6 +68,10 @@ namespace storm { return Expression(std::shared_ptr<BaseExpression>(new DoubleLiteralExpression(*this, value))); } + Expression ExpressionManager::rational(storm::RationalNumber const& value) const { + return Expression(std::shared_ptr<BaseExpression>(new DoubleLiteralExpression(*this, value))); + } + bool ExpressionManager::operator==(ExpressionManager const& other) const { return this == &other; } diff --git a/src/storage/expressions/ExpressionManager.h b/src/storage/expressions/ExpressionManager.h index 6fee92fd6..f3ec7e76b 100644 --- a/src/storage/expressions/ExpressionManager.h +++ b/src/storage/expressions/ExpressionManager.h @@ -10,6 +10,7 @@ #include "src/storage/expressions/Variable.h" #include "src/storage/expressions/Expression.h" +#include "src/adapters/CarlAdapter.h" #include "src/utility/OsDetection.h" namespace storm { @@ -104,6 +105,14 @@ namespace storm { * @return The resulting expression. */ Expression rational(double value) const; + + /*! + * Creates an expression that characterizes the given rational literal. + * + * @param value The value of the rational literal. + * @return The resulting expression. + */ + Expression rational(storm::RationalNumber const& value) const; /*! * Compares the two expression managers for equality, which holds iff they are the very same object. From 58857d62ed395040aa69cbc6b3d1e6e789fa0744 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 15 Aug 2016 16:55:45 +0200 Subject: [PATCH 05/34] renamed double literal to rational literal Former-commit-id: 7bafe79eed1fd06aa0254a20699454265ed0eeb2 --- src/adapters/AddExpressionAdapter.cpp | 2 +- src/adapters/AddExpressionAdapter.h | 2 +- src/adapters/MathsatExpressionAdapter.h | 2 +- src/adapters/Z3ExpressionAdapter.cpp | 2 +- src/adapters/Z3ExpressionAdapter.h | 2 +- src/parser/ExpressionParser.cpp | 4 ++-- src/parser/ExpressionParser.h | 2 +- .../BinaryNumericalFunctionExpression.cpp | 4 ++-- .../expressions/DoubleLiteralExpression.cpp | 24 +++++++++---------- .../expressions/DoubleLiteralExpression.h | 24 +++++++++---------- src/storage/expressions/ExpressionManager.cpp | 4 ++-- src/storage/expressions/ExpressionVisitor.h | 4 ++-- src/storage/expressions/Expressions.h | 2 +- .../expressions/LinearCoefficientVisitor.cpp | 2 +- .../expressions/LinearCoefficientVisitor.h | 2 +- .../expressions/LinearityCheckVisitor.cpp | 2 +- .../expressions/LinearityCheckVisitor.h | 2 +- .../expressions/SubstitutionVisitor.cpp | 2 +- src/storage/expressions/SubstitutionVisitor.h | 2 +- .../expressions/ToExprtkStringVisitor.cpp | 2 +- .../expressions/ToExprtkStringVisitor.h | 2 +- .../expressions/ToRationalFunctionVisitor.cpp | 2 +- .../expressions/ToRationalFunctionVisitor.h | 2 +- .../expressions/ToRationalNumberVisitor.cpp | 2 +- .../expressions/ToRationalNumberVisitor.h | 2 +- .../UnaryNumericalFunctionExpression.cpp | 4 ++-- 26 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/adapters/AddExpressionAdapter.cpp b/src/adapters/AddExpressionAdapter.cpp index 7a22c8f8f..2f0dc7190 100644 --- a/src/adapters/AddExpressionAdapter.cpp +++ b/src/adapters/AddExpressionAdapter.cpp @@ -194,7 +194,7 @@ namespace storm { } 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.getValueAsDouble())); } diff --git a/src/adapters/AddExpressionAdapter.h b/src/adapters/AddExpressionAdapter.h index 89d825d96..dfb13a315 100644 --- a/src/adapters/AddExpressionAdapter.h +++ b/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::BooleanLiteralExpression const& expression) override; virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression) override; - virtual boost::any visit(storm::expressions::DoubleLiteralExpression const& expression) override; + virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression) override; private: // The manager responsible for the DDs built by this adapter. diff --git a/src/adapters/MathsatExpressionAdapter.h b/src/adapters/MathsatExpressionAdapter.h index db5bf9b69..77b39cc68 100644 --- a/src/adapters/MathsatExpressionAdapter.h +++ b/src/adapters/MathsatExpressionAdapter.h @@ -171,7 +171,7 @@ namespace storm { 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.getValueAsDouble()).c_str()); } diff --git a/src/adapters/Z3ExpressionAdapter.cpp b/src/adapters/Z3ExpressionAdapter.cpp index 60b4e8e1c..6f4efc178 100644 --- a/src/adapters/Z3ExpressionAdapter.cpp +++ b/src/adapters/Z3ExpressionAdapter.cpp @@ -208,7 +208,7 @@ namespace storm { 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; fractionStream << expression.getValue(); return context.real_val(fractionStream.str().c_str()); diff --git a/src/adapters/Z3ExpressionAdapter.h b/src/adapters/Z3ExpressionAdapter.h index 4fc60c8a5..2735f5713 100644 --- a/src/adapters/Z3ExpressionAdapter.h +++ b/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::DoubleLiteralExpression const& expression) override; + virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression) override; virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression) override; diff --git a/src/parser/ExpressionParser.cpp b/src/parser/ExpressionParser.cpp index d556d799a..3054f2fe0 100644 --- a/src/parser/ExpressionParser.cpp +++ b/src/parser/ExpressionParser.cpp @@ -61,7 +61,7 @@ namespace storm { identifierExpression = identifier[qi::_val = phoenix::bind(&ExpressionParser::getIdentifierExpression, phoenix::ref(*this), qi::_1, allowBacktracking, qi::_pass)]; identifierExpression.name("identifier expression"); - literalExpression = trueFalse_[qi::_val = qi::_1] | rationalLiteral_[qi::_val = phoenix::bind(&ExpressionParser::createDoubleLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)] | qi::int_[qi::_val = phoenix::bind(&ExpressionParser::createIntegerLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)]; + literalExpression = trueFalse_[qi::_val = qi::_1] | rationalLiteral_[qi::_val = phoenix::bind(&ExpressionParser::createRationalLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)] | qi::int_[qi::_val = phoenix::bind(&ExpressionParser::createIntegerLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)]; literalExpression.name("literal expression"); atomicExpression = floorCeilExpression | prefixPowerExpression | minMaxExpression | (qi::lit("(") >> expression >> qi::lit(")")) | literalExpression | identifierExpression; @@ -323,7 +323,7 @@ namespace storm { return manager->boolean(false); } - storm::expressions::Expression ExpressionParser::createDoubleLiteralExpression(storm::RationalNumber const& value, bool& pass) const { + storm::expressions::Expression ExpressionParser::createRationalLiteralExpression(storm::RationalNumber const& value, bool& pass) const { // If we are not supposed to accept double expressions, we reject it by setting pass to false. if (!this->acceptDoubleLiterals) { pass = false; diff --git a/src/parser/ExpressionParser.h b/src/parser/ExpressionParser.h index c728e0b84..077be8db2 100644 --- a/src/parser/ExpressionParser.h +++ b/src/parser/ExpressionParser.h @@ -260,7 +260,7 @@ namespace storm { storm::expressions::Expression createMultExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; storm::expressions::Expression createPowerExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; storm::expressions::Expression createUnaryExpression(boost::optional<storm::expressions::OperatorType> const& operatorType, storm::expressions::Expression const& e1, bool& pass) const; - storm::expressions::Expression createDoubleLiteralExpression(storm::RationalNumber const& value, bool& pass) const; + storm::expressions::Expression createRationalLiteralExpression(storm::RationalNumber const& value, bool& pass) const; storm::expressions::Expression createIntegerLiteralExpression(int value, bool& pass) const; storm::expressions::Expression createMinimumMaximumExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; storm::expressions::Expression createFloorCeilExpression(storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e1, bool& pass) const; diff --git a/src/storage/expressions/BinaryNumericalFunctionExpression.cpp b/src/storage/expressions/BinaryNumericalFunctionExpression.cpp index 95a326de1..7c4367952 100644 --- a/src/storage/expressions/BinaryNumericalFunctionExpression.cpp +++ b/src/storage/expressions/BinaryNumericalFunctionExpression.cpp @@ -3,7 +3,7 @@ #include "src/storage/expressions/BinaryNumericalFunctionExpression.h" #include "src/storage/expressions/IntegerLiteralExpression.h" -#include "src/storage/expressions/DoubleLiteralExpression.h" +#include "src/storage/expressions/RationalLiteralExpression.h" #include "src/storage/expressions/ExpressionVisitor.h" #include "src/utility/macros.h" #include "src/exceptions/InvalidTypeException.h" @@ -102,7 +102,7 @@ namespace storm { case OperatorType::Power: newValue = static_cast<int_fast64_t>(std::pow(firstOperandEvaluation, secondOperandEvaluation)); break; case OperatorType::Divide: STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Unable to simplify division."); break; } - return std::shared_ptr<BaseExpression>(new DoubleLiteralExpression(this->getManager(), newValue)); + return std::shared_ptr<BaseExpression>(new RationalLiteralExpression(this->getManager(), newValue)); } } diff --git a/src/storage/expressions/DoubleLiteralExpression.cpp b/src/storage/expressions/DoubleLiteralExpression.cpp index 86a2ba889..3fa226a8a 100644 --- a/src/storage/expressions/DoubleLiteralExpression.cpp +++ b/src/storage/expressions/DoubleLiteralExpression.cpp @@ -1,4 +1,4 @@ -#include "src/storage/expressions/DoubleLiteralExpression.h" +#include "src/storage/expressions/RationalLiteralExpression.h" #include "src/storage/expressions/ExpressionManager.h" #include "src/storage/expressions/ExpressionVisitor.h" @@ -6,47 +6,47 @@ namespace storm { namespace expressions { - DoubleLiteralExpression::DoubleLiteralExpression(ExpressionManager const& manager, double value) : BaseExpression(manager, manager.getRationalType()), value(storm::utility::convertNumber<storm::RationalNumber>(value)) { + RationalLiteralExpression::RationalLiteralExpression(ExpressionManager const& manager, double value) : BaseExpression(manager, manager.getRationalType()), value(storm::utility::convertNumber<storm::RationalNumber>(value)) { // Intentionally left empty. } - DoubleLiteralExpression::DoubleLiteralExpression(ExpressionManager const& manager, std::string const& valueAsString) : BaseExpression(manager, manager.getRationalType()), value(storm::utility::convertNumber<storm::RationalNumber>(valueAsString)) { + RationalLiteralExpression::RationalLiteralExpression(ExpressionManager const& manager, std::string const& valueAsString) : BaseExpression(manager, manager.getRationalType()), value(storm::utility::convertNumber<storm::RationalNumber>(valueAsString)) { // Intentionally left empty. } - DoubleLiteralExpression::DoubleLiteralExpression(ExpressionManager const& manager, storm::RationalNumber const& value) : BaseExpression(manager, manager.getRationalType()), value(value) { + RationalLiteralExpression::RationalLiteralExpression(ExpressionManager const& manager, storm::RationalNumber const& value) : BaseExpression(manager, manager.getRationalType()), value(value) { // Intentionally left empty. } - double DoubleLiteralExpression::evaluateAsDouble(Valuation const* valuation) const { + double RationalLiteralExpression::evaluateAsDouble(Valuation const* valuation) const { return this->getValueAsDouble(); } - bool DoubleLiteralExpression::isLiteral() const { + bool RationalLiteralExpression::isLiteral() const { return true; } - void DoubleLiteralExpression::gatherVariables(std::set<storm::expressions::Variable>& variables) const { + void RationalLiteralExpression::gatherVariables(std::set<storm::expressions::Variable>& variables) const { return; } - std::shared_ptr<BaseExpression const> DoubleLiteralExpression::simplify() const { + std::shared_ptr<BaseExpression const> RationalLiteralExpression::simplify() const { return this->shared_from_this(); } - boost::any DoubleLiteralExpression::accept(ExpressionVisitor& visitor) const { + boost::any RationalLiteralExpression::accept(ExpressionVisitor& visitor) const { return visitor.visit(*this); } - double DoubleLiteralExpression::getValueAsDouble() const { + double RationalLiteralExpression::getValueAsDouble() const { return storm::utility::convertNumber<double>(this->value); } - storm::RationalNumber DoubleLiteralExpression::getValue() const { + storm::RationalNumber RationalLiteralExpression::getValue() const { return this->value; } - void DoubleLiteralExpression::printToStream(std::ostream& stream) const { + void RationalLiteralExpression::printToStream(std::ostream& stream) const { stream << this->getValue(); } } diff --git a/src/storage/expressions/DoubleLiteralExpression.h b/src/storage/expressions/DoubleLiteralExpression.h index 1b6aa28b3..4eff900b2 100644 --- a/src/storage/expressions/DoubleLiteralExpression.h +++ b/src/storage/expressions/DoubleLiteralExpression.h @@ -1,5 +1,5 @@ -#ifndef STORM_STORAGE_EXPRESSIONS_DOUBLELITERALEXPRESSION_H_ -#define STORM_STORAGE_EXPRESSIONS_DOUBLELITERALEXPRESSION_H_ +#ifndef STORM_STORAGE_EXPRESSIONS_RationalLiteralExpression_H_ +#define STORM_STORAGE_EXPRESSIONS_RationalLiteralExpression_H_ #include "src/storage/expressions/BaseExpression.h" #include "src/utility/OsDetection.h" @@ -8,7 +8,7 @@ namespace storm { namespace expressions { - class DoubleLiteralExpression : public BaseExpression { + class RationalLiteralExpression : public BaseExpression { public: /*! * Creates an double literal expression with the given value. @@ -16,7 +16,7 @@ namespace storm { * @param manager The manager responsible for this expression. * @param value The value of the double literal. */ - DoubleLiteralExpression(ExpressionManager const& manager, double value); + RationalLiteralExpression(ExpressionManager const& manager, double value); /*! * Creates an double literal expression with the value given as a string. @@ -24,7 +24,7 @@ namespace storm { * @param manager The manager responsible for this expression. * @param value The string representation of the value of the literal. */ - DoubleLiteralExpression(ExpressionManager const& manager, std::string const& valueAsString); + RationalLiteralExpression(ExpressionManager const& manager, std::string const& valueAsString); /*! * Creates an double literal expression with the rational value. @@ -32,16 +32,16 @@ namespace storm { * @param manager The manager responsible for this expression. * @param value The rational number that is the value of this literal expression. */ - DoubleLiteralExpression(ExpressionManager const& manager, storm::RationalNumber const& value); + RationalLiteralExpression(ExpressionManager const& manager, storm::RationalNumber const& value); // Instantiate constructors and assignments with their default implementations. - DoubleLiteralExpression(DoubleLiteralExpression const& other) = default; - DoubleLiteralExpression& operator=(DoubleLiteralExpression const& other) = delete; + RationalLiteralExpression(RationalLiteralExpression const& other) = default; + RationalLiteralExpression& operator=(RationalLiteralExpression const& other) = delete; #ifndef WINDOWS - DoubleLiteralExpression(DoubleLiteralExpression&&) = default; - DoubleLiteralExpression& operator=(DoubleLiteralExpression&&) = delete; + RationalLiteralExpression(RationalLiteralExpression&&) = default; + RationalLiteralExpression& operator=(RationalLiteralExpression&&) = delete; #endif - virtual ~DoubleLiteralExpression() = default; + virtual ~RationalLiteralExpression() = default; // Override base class methods. virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override; @@ -75,4 +75,4 @@ namespace storm { } } -#endif /* STORM_STORAGE_EXPRESSIONS_DOUBLELITERALEXPRESSION_H_ */ \ No newline at end of file +#endif /* STORM_STORAGE_EXPRESSIONS_RationalLiteralExpression_H_ */ \ No newline at end of file diff --git a/src/storage/expressions/ExpressionManager.cpp b/src/storage/expressions/ExpressionManager.cpp index a92d908f3..ed51f76ee 100644 --- a/src/storage/expressions/ExpressionManager.cpp +++ b/src/storage/expressions/ExpressionManager.cpp @@ -65,11 +65,11 @@ namespace storm { } Expression ExpressionManager::rational(double value) const { - return Expression(std::shared_ptr<BaseExpression>(new DoubleLiteralExpression(*this, value))); + return Expression(std::shared_ptr<BaseExpression>(new RationalLiteralExpression(*this, value))); } Expression ExpressionManager::rational(storm::RationalNumber const& value) const { - return Expression(std::shared_ptr<BaseExpression>(new DoubleLiteralExpression(*this, value))); + return Expression(std::shared_ptr<BaseExpression>(new RationalLiteralExpression(*this, value))); } bool ExpressionManager::operator==(ExpressionManager const& other) const { diff --git a/src/storage/expressions/ExpressionVisitor.h b/src/storage/expressions/ExpressionVisitor.h index 5fdb486c2..1abafc2a6 100644 --- a/src/storage/expressions/ExpressionVisitor.h +++ b/src/storage/expressions/ExpressionVisitor.h @@ -15,7 +15,7 @@ namespace storm { class UnaryNumericalFunctionExpression; class BooleanLiteralExpression; class IntegerLiteralExpression; - class DoubleLiteralExpression; + class RationalLiteralExpression; class ExpressionVisitor { public: @@ -28,7 +28,7 @@ namespace storm { virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) = 0; virtual boost::any visit(BooleanLiteralExpression const& expression) = 0; virtual boost::any visit(IntegerLiteralExpression const& expression) = 0; - virtual boost::any visit(DoubleLiteralExpression const& expression) = 0; + virtual boost::any visit(RationalLiteralExpression const& expression) = 0; }; } } diff --git a/src/storage/expressions/Expressions.h b/src/storage/expressions/Expressions.h index d670c29e3..655cc4aab 100644 --- a/src/storage/expressions/Expressions.h +++ b/src/storage/expressions/Expressions.h @@ -4,7 +4,7 @@ #include "src/storage/expressions/BinaryRelationExpression.h" #include "src/storage/expressions/BooleanLiteralExpression.h" #include "src/storage/expressions/IntegerLiteralExpression.h" -#include "src/storage/expressions/DoubleLiteralExpression.h" +#include "src/storage/expressions/RationalLiteralExpression.h" #include "src/storage/expressions/UnaryBooleanFunctionExpression.h" #include "src/storage/expressions/UnaryNumericalFunctionExpression.h" #include "src/storage/expressions/VariableExpression.h" diff --git a/src/storage/expressions/LinearCoefficientVisitor.cpp b/src/storage/expressions/LinearCoefficientVisitor.cpp index 3d881c25e..dc9a909f9 100644 --- a/src/storage/expressions/LinearCoefficientVisitor.cpp +++ b/src/storage/expressions/LinearCoefficientVisitor.cpp @@ -151,7 +151,7 @@ namespace storm { return VariableCoefficients(static_cast<double>(expression.getValue())); } - boost::any LinearCoefficientVisitor::visit(DoubleLiteralExpression const& expression) { + boost::any LinearCoefficientVisitor::visit(RationalLiteralExpression const& expression) { return VariableCoefficients(expression.getValueAsDouble()); } } diff --git a/src/storage/expressions/LinearCoefficientVisitor.h b/src/storage/expressions/LinearCoefficientVisitor.h index b48c53d09..dea1bfc2e 100644 --- a/src/storage/expressions/LinearCoefficientVisitor.h +++ b/src/storage/expressions/LinearCoefficientVisitor.h @@ -75,7 +75,7 @@ namespace storm { virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression) override; - virtual boost::any visit(DoubleLiteralExpression const& expression) override; + virtual boost::any visit(RationalLiteralExpression const& expression) override; }; } } diff --git a/src/storage/expressions/LinearityCheckVisitor.cpp b/src/storage/expressions/LinearityCheckVisitor.cpp index 35e1e5c76..7a33a501a 100644 --- a/src/storage/expressions/LinearityCheckVisitor.cpp +++ b/src/storage/expressions/LinearityCheckVisitor.cpp @@ -85,7 +85,7 @@ namespace storm { return LinearityStatus::LinearWithoutVariables; } - boost::any LinearityCheckVisitor::visit(DoubleLiteralExpression const& expression) { + boost::any LinearityCheckVisitor::visit(RationalLiteralExpression const& expression) { return LinearityStatus::LinearWithoutVariables; } } diff --git a/src/storage/expressions/LinearityCheckVisitor.h b/src/storage/expressions/LinearityCheckVisitor.h index 2df8f8084..6bb35b7e8 100644 --- a/src/storage/expressions/LinearityCheckVisitor.h +++ b/src/storage/expressions/LinearityCheckVisitor.h @@ -29,7 +29,7 @@ namespace storm { virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression) override; - virtual boost::any visit(DoubleLiteralExpression const& expression) override; + virtual boost::any visit(RationalLiteralExpression const& expression) override; private: enum class LinearityStatus { NonLinear, LinearContainsVariables, LinearWithoutVariables }; diff --git a/src/storage/expressions/SubstitutionVisitor.cpp b/src/storage/expressions/SubstitutionVisitor.cpp index c736de156..1490e6f59 100644 --- a/src/storage/expressions/SubstitutionVisitor.cpp +++ b/src/storage/expressions/SubstitutionVisitor.cpp @@ -116,7 +116,7 @@ namespace storm { } template<typename MapType> - boost::any SubstitutionVisitor<MapType>::visit(DoubleLiteralExpression const& expression) { + boost::any SubstitutionVisitor<MapType>::visit(RationalLiteralExpression const& expression) { return expression.getSharedPointer(); } diff --git a/src/storage/expressions/SubstitutionVisitor.h b/src/storage/expressions/SubstitutionVisitor.h index 343521335..5f1a93cb2 100644 --- a/src/storage/expressions/SubstitutionVisitor.h +++ b/src/storage/expressions/SubstitutionVisitor.h @@ -37,7 +37,7 @@ namespace storm { virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression) override; - virtual boost::any visit(DoubleLiteralExpression const& expression) override; + virtual boost::any visit(RationalLiteralExpression const& expression) override; private: // A mapping of variables to expressions with which they shall be replaced. diff --git a/src/storage/expressions/ToExprtkStringVisitor.cpp b/src/storage/expressions/ToExprtkStringVisitor.cpp index 51d9c1f34..1492aeae5 100644 --- a/src/storage/expressions/ToExprtkStringVisitor.cpp +++ b/src/storage/expressions/ToExprtkStringVisitor.cpp @@ -212,7 +212,7 @@ namespace storm { return boost::any(); } - boost::any ToExprtkStringVisitor::visit(DoubleLiteralExpression const& expression) { + boost::any ToExprtkStringVisitor::visit(RationalLiteralExpression const& expression) { stream << expression.getValue(); return boost::any(); } diff --git a/src/storage/expressions/ToExprtkStringVisitor.h b/src/storage/expressions/ToExprtkStringVisitor.h index 6c285ff28..d68da589d 100644 --- a/src/storage/expressions/ToExprtkStringVisitor.h +++ b/src/storage/expressions/ToExprtkStringVisitor.h @@ -25,7 +25,7 @@ namespace storm { virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression) override; - virtual boost::any visit(DoubleLiteralExpression const& expression) override; + virtual boost::any visit(RationalLiteralExpression const& expression) override; private: std::stringstream stream; diff --git a/src/storage/expressions/ToRationalFunctionVisitor.cpp b/src/storage/expressions/ToRationalFunctionVisitor.cpp index 533fa1f1f..60fecc08c 100644 --- a/src/storage/expressions/ToRationalFunctionVisitor.cpp +++ b/src/storage/expressions/ToRationalFunctionVisitor.cpp @@ -93,7 +93,7 @@ namespace storm { } template<typename RationalFunctionType> - boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(DoubleLiteralExpression const& expression) { + boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(RationalLiteralExpression const& expression) { return storm::utility::convertNumber<storm::RationalFunction>(expression.getValue()); } diff --git a/src/storage/expressions/ToRationalFunctionVisitor.h b/src/storage/expressions/ToRationalFunctionVisitor.h index 12603f44e..1cda5028f 100644 --- a/src/storage/expressions/ToRationalFunctionVisitor.h +++ b/src/storage/expressions/ToRationalFunctionVisitor.h @@ -27,7 +27,7 @@ namespace storm { virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression) override; - virtual boost::any visit(DoubleLiteralExpression const& expression) override; + virtual boost::any visit(RationalLiteralExpression const& expression) override; private: template<typename TP = typename RationalFunctionType::PolyType, carl::EnableIf<carl::needs_cache<TP>> = carl::dummy> diff --git a/src/storage/expressions/ToRationalNumberVisitor.cpp b/src/storage/expressions/ToRationalNumberVisitor.cpp index 44194cb4b..1b7319927 100644 --- a/src/storage/expressions/ToRationalNumberVisitor.cpp +++ b/src/storage/expressions/ToRationalNumberVisitor.cpp @@ -97,7 +97,7 @@ namespace storm { } template<typename RationalNumberType> - boost::any ToRationalNumberVisitor<RationalNumberType>::visit(DoubleLiteralExpression const& expression) { + boost::any ToRationalNumberVisitor<RationalNumberType>::visit(RationalLiteralExpression const& expression) { #ifdef STORM_HAVE_CARL return expression.getValue(); #else diff --git a/src/storage/expressions/ToRationalNumberVisitor.h b/src/storage/expressions/ToRationalNumberVisitor.h index 2254931f6..3d53b8a87 100644 --- a/src/storage/expressions/ToRationalNumberVisitor.h +++ b/src/storage/expressions/ToRationalNumberVisitor.h @@ -25,7 +25,7 @@ namespace storm { virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; virtual boost::any visit(BooleanLiteralExpression const& expression) override; virtual boost::any visit(IntegerLiteralExpression const& expression) override; - virtual boost::any visit(DoubleLiteralExpression const& expression) override; + virtual boost::any visit(RationalLiteralExpression const& expression) override; }; } } diff --git a/src/storage/expressions/UnaryNumericalFunctionExpression.cpp b/src/storage/expressions/UnaryNumericalFunctionExpression.cpp index fa7cad7e3..f5178fb6f 100644 --- a/src/storage/expressions/UnaryNumericalFunctionExpression.cpp +++ b/src/storage/expressions/UnaryNumericalFunctionExpression.cpp @@ -4,7 +4,7 @@ #include "src/storage/expressions/UnaryNumericalFunctionExpression.h" #include "src/storage/expressions/IntegerLiteralExpression.h" -#include "src/storage/expressions/DoubleLiteralExpression.h" +#include "src/storage/expressions/RationalLiteralExpression.h" #include "ExpressionVisitor.h" #include "src/utility/macros.h" #include "src/exceptions/InvalidTypeException.h" @@ -87,7 +87,7 @@ namespace storm { case OperatorType::Floor: value = std::floor(boost::get<double>(operandEvaluation)); break; case OperatorType::Ceil: value = std::ceil(boost::get<double>(operandEvaluation)); break; } - return std::shared_ptr<BaseExpression>(new DoubleLiteralExpression(this->getManager(), value)); + return std::shared_ptr<BaseExpression>(new RationalLiteralExpression(this->getManager(), value)); } } From 984abfd22bfc0df35d90d3c933f282b089f0fd20 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 15 Aug 2016 16:56:26 +0200 Subject: [PATCH 06/34] proper renaming of files Former-commit-id: 5594ddec3849939f24194f7d3d6c8648b3e70ee8 --- ...{DoubleLiteralExpression.cpp => RationalLiteralExpression.cpp} | 0 .../{DoubleLiteralExpression.h => RationalLiteralExpression.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/storage/expressions/{DoubleLiteralExpression.cpp => RationalLiteralExpression.cpp} (100%) rename src/storage/expressions/{DoubleLiteralExpression.h => RationalLiteralExpression.h} (100%) diff --git a/src/storage/expressions/DoubleLiteralExpression.cpp b/src/storage/expressions/RationalLiteralExpression.cpp similarity index 100% rename from src/storage/expressions/DoubleLiteralExpression.cpp rename to src/storage/expressions/RationalLiteralExpression.cpp diff --git a/src/storage/expressions/DoubleLiteralExpression.h b/src/storage/expressions/RationalLiteralExpression.h similarity index 100% rename from src/storage/expressions/DoubleLiteralExpression.h rename to src/storage/expressions/RationalLiteralExpression.h From f342ce3287f8b2aacb6fd9149fe24a548b1a2ca3 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 15 Aug 2016 20:29:50 +0200 Subject: [PATCH 07/34] translation from expressions involving the power operator to rational functions/rational numbers is now possible Former-commit-id: e0ce43ab35f88de46426b967c91b584e5adbe955 --- src/storage/expressions/ToRationalFunctionVisitor.cpp | 6 ++++++ src/utility/constants.cpp | 11 ++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/storage/expressions/ToRationalFunctionVisitor.cpp b/src/storage/expressions/ToRationalFunctionVisitor.cpp index 60fecc08c..a219066e4 100644 --- a/src/storage/expressions/ToRationalFunctionVisitor.cpp +++ b/src/storage/expressions/ToRationalFunctionVisitor.cpp @@ -34,6 +34,7 @@ namespace storm { boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryNumericalFunctionExpression const& expression) { RationalFunctionType firstOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getFirstOperand()->accept(*this)); RationalFunctionType secondOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getSecondOperand()->accept(*this)); + uint_fast64_t exponentAsInteger = 0; switch(expression.getOperatorType()) { case BinaryNumericalFunctionExpression::OperatorType::Plus: return firstOperandAsRationalFunction + secondOperandAsRationalFunction; @@ -47,6 +48,11 @@ namespace storm { case BinaryNumericalFunctionExpression::OperatorType::Divide: return firstOperandAsRationalFunction / secondOperandAsRationalFunction; break; + case BinaryNumericalFunctionExpression::OperatorType::Power: + STORM_LOG_THROW(storm::utility::isInteger(secondOperandAsRationalFunction), storm::exceptions::InvalidArgumentException, "Exponent of power operator must be a positive integer."); + exponentAsInteger = storm::utility::convertNumber<uint_fast64_t>(secondOperandAsRationalFunction); + return storm::utility::pow(firstOperandAsRationalFunction, exponentAsInteger); + break; default: STORM_LOG_ASSERT(false, "Illegal operator type."); } diff --git a/src/utility/constants.cpp b/src/utility/constants.cpp index 2630ed285..6d954722a 100644 --- a/src/utility/constants.cpp +++ b/src/utility/constants.cpp @@ -115,6 +115,10 @@ namespace storm { return carl::isInteger(number); } + template<> + bool isInteger(storm::RationalFunction const& func) { + return storm::utility::isConstant(func) && storm::utility::isOne(func.denominator()); + } #endif template<typename ValueType> @@ -203,7 +207,12 @@ namespace storm { RationalFunction convertNumber(RationalNumber const& number) { return RationalFunction(number); } - + + template<> + 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); From 49b663aa87da00c0277e3ba3be664d121b8803ba Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 15 Aug 2016 22:03:29 +0200 Subject: [PATCH 08/34] started working on python script that automatically packages the binary for mac os Former-commit-id: 11a73f85e7493bc3ab940241599cdab6d505ab91 --- util/osx-package/packager.py | 47 ++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 util/osx-package/packager.py diff --git a/util/osx-package/packager.py b/util/osx-package/packager.py new file mode 100644 index 000000000..39d06a667 --- /dev/null +++ b/util/osx-package/packager.py @@ -0,0 +1,47 @@ +import argparse +import subprocess +import os + +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 parse_arguments(): + parser = argparse.ArgumentParser(description='Package the storm binary on Mac OS.') + parser.add_argument('binary', help='the binary to package') + args = parser.parse_args() + return args + +dep_exeptions = set() +dep_exeptions.add("libSystem.B.dylib") +dep_exeptions.add("libc++.1.dylib") + +def rec_gather_all_dependencies(file, deps = set()): + current_deps = get_dependencies(file) + new_deps = current_deps.keys() - dep_exeptions - deps + deps = deps | current_deps.keys() + + for d in new_deps: + rec_gather_all_dependencies(file, deps) + + return deps + +def print_deps(deps): + print("Found the following dependencies:") + for d in deps: + print(d) + +if __name__ == "__main__": + args = parse_arguments() + deps = rec_gather_all_dependencies(args.binary) + print_deps(deps) From 8d88572b03a3095f8ff9d604850f5553339deae8 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Tue, 16 Aug 2016 15:50:37 +0200 Subject: [PATCH 09/34] packager and script Former-commit-id: 4db9b3616e8549a9b1a436f62e9b9f1a14d3728c --- util/osx-package/packager.py | 94 ++++++++++++++++++++++++++++-------- util/osx-package/run.sh | 10 ++++ 2 files changed, 85 insertions(+), 19 deletions(-) create mode 100644 util/osx-package/run.sh diff --git a/util/osx-package/packager.py b/util/osx-package/packager.py index 39d06a667..60b26a8b8 100644 --- a/util/osx-package/packager.py +++ b/util/osx-package/packager.py @@ -1,6 +1,7 @@ import argparse import subprocess import os +from shutil import copyfile def get_dependencies(file): # Call otool -L file to obtain the dependencies. @@ -16,32 +17,87 @@ def get_dependencies(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('binary', help='the binary to package') + 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 -dep_exeptions = set() -dep_exeptions.add("libSystem.B.dylib") -dep_exeptions.add("libc++.1.dylib") +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 rec_gather_all_dependencies(file, deps = set()): - current_deps = get_dependencies(file) - new_deps = current_deps.keys() - dep_exeptions - deps - deps = deps | current_deps.keys() - - for d in new_deps: - rec_gather_all_dependencies(file, deps) - - return deps +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 print_deps(deps): - print("Found the following dependencies:") - for d in deps: - print(d) +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() - deps = rec_gather_all_dependencies(args.binary) - print_deps(deps) + + #create_package(args) + fix_paths(args.dir, args.binary_basename) + + diff --git a/util/osx-package/run.sh b/util/osx-package/run.sh new file mode 100644 index 000000000..0db5b2b5d --- /dev/null +++ b/util/osx-package/run.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 From 07a457b5d1beded6946652ed83dc900183d94120 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Wed, 17 Aug 2016 11:33:14 +0200 Subject: [PATCH 10/34] renaming packaging script Former-commit-id: ef506391b4d4211df4c021ac720e8c9da9fd43d2 --- util/osx-package/{run.sh => package.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename util/osx-package/{run.sh => package.sh} (100%) diff --git a/util/osx-package/run.sh b/util/osx-package/package.sh similarity index 100% rename from util/osx-package/run.sh rename to util/osx-package/package.sh From 5109c45c23af58398e7751db8639b039f62082c3 Mon Sep 17 00:00:00 2001 From: Mavo <matthias.volk@rwth-aachen.de> Date: Fri, 19 Aug 2016 12:09:48 +0200 Subject: [PATCH 11/34] Fixed returning result for pCTMC Former-commit-id: 2db7f87f65cefd4da1250163fe73af85a8f9c806 --- src/utility/storm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utility/storm.h b/src/utility/storm.h index ad9cb1de0..4a32c7ad4 100644 --- a/src/utility/storm.h +++ b/src/utility/storm.h @@ -381,10 +381,10 @@ namespace storm { if (model->getType() == storm::models::ModelType::Dtmc) { result = verifySparseDtmc(model->template as<storm::models::sparse::Dtmc<storm::RationalFunction>>(), task); } 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."); } 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 { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The parametric engine currently does not support " << model->getType()); } From 6d5f4dc9c924985e7e0879a480750c1b8e4f70a9 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 19 Aug 2016 08:56:59 +0200 Subject: [PATCH 12/34] fixed bug in detection whether parameters are only used in probabilities/rewards Former-commit-id: 1929f5e079a03863d9b838043070be4ffe640314 --- src/storage/prism/Constant.cpp | 7 ++++++- src/storage/prism/Module.cpp | 4 +++- src/storage/prism/Program.cpp | 6 ++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/storage/prism/Constant.cpp b/src/storage/prism/Constant.cpp index 0416dc4b9..1c3b07057 100644 --- a/src/storage/prism/Constant.cpp +++ b/src/storage/prism/Constant.cpp @@ -42,7 +42,12 @@ namespace storm { } 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(); if (constant.isDefined()) { stream << " = " << constant.getExpression(); diff --git a/src/storage/prism/Module.cpp b/src/storage/prism/Module.cpp index d4168196d..7b929edfc 100644 --- a/src/storage/prism/Module.cpp +++ b/src/storage/prism/Module.cpp @@ -216,7 +216,9 @@ namespace storm { } for (auto const& command : this->getCommands()) { - command.containsVariablesOnlyInUpdateProbabilities(undefinedConstantVariables); + if (!command.containsVariablesOnlyInUpdateProbabilities(undefinedConstantVariables)) { + return false; + } } return true; diff --git a/src/storage/prism/Program.cpp b/src/storage/prism/Program.cpp index c1a1e4cf0..4962157eb 100644 --- a/src/storage/prism/Program.cpp +++ b/src/storage/prism/Program.cpp @@ -230,7 +230,7 @@ namespace storm { // 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 - //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()) { if (constant.isDefined()) { if (constant.getExpression().containsVariable(undefinedConstantVariables)) { @@ -266,7 +266,9 @@ namespace storm { // Proceed by checking each of the modules. for (auto const& module : this->getModules()) { - module.containsVariablesOnlyInUpdateProbabilities(undefinedConstantVariables); + if (!module.containsVariablesOnlyInUpdateProbabilities(undefinedConstantVariables)) { + return false; + } } // Check the reward models. From e6d9c85749964659472384a2fe5d40ddaf26de01 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 19 Aug 2016 19:33:40 +0200 Subject: [PATCH 13/34] fixed some bugs related to simplifaction of PRISM programs Former-commit-id: 3c81bcac8d34b9a88180a0542c7b1e1f305848b3 --- src/generator/JaniNextStateGenerator.cpp | 3 + src/generator/PrismNextStateGenerator.cpp | 9 ++- src/parser/PrismParser.cpp | 2 + src/storage/prism/Module.h | 1 - src/storage/prism/Program.cpp | 72 ++++++++++++++++++----- src/storage/prism/RewardModel.cpp | 18 ++++++ src/storage/prism/RewardModel.h | 9 +++ src/utility/storm.cpp | 2 +- 8 files changed, 95 insertions(+), 21 deletions(-) diff --git a/src/generator/JaniNextStateGenerator.cpp b/src/generator/JaniNextStateGenerator.cpp index cfb08fb79..0b2fad41a 100644 --- a/src/generator/JaniNextStateGenerator.cpp +++ b/src/generator/JaniNextStateGenerator.cpp @@ -161,6 +161,9 @@ namespace storm { } // Block the current initial state to search for the next one. + if (!blockingExpression.isInitialized()) { + break; + } solver->add(blockingExpression); } diff --git a/src/generator/PrismNextStateGenerator.cpp b/src/generator/PrismNextStateGenerator.cpp index c0026a98d..7eb2291c5 100644 --- a/src/generator/PrismNextStateGenerator.cpp +++ b/src/generator/PrismNextStateGenerator.cpp @@ -23,8 +23,9 @@ namespace storm { template<typename ValueType, typename StateType> PrismNextStateGenerator<ValueType, StateType>::PrismNextStateGenerator(storm::prism::Program const& program, NextStateGeneratorOptions const& options, bool flag) : NextStateGenerator<ValueType, StateType>(program.getManager(), options), program(program), rewardModels() { + STORM_LOG_TRACE("Creating next-state generator for PRISM program: " << program); STORM_LOG_THROW(!this->program.specifiesSystemComposition(), storm::exceptions::WrongFormatException, "The explicit next-state generator currently does not support custom system compositions."); - + // Only after checking validity of the program, we initialize the variable information. this->checkValid(program); this->variableInformation = VariableInformation(program); @@ -166,6 +167,9 @@ namespace storm { initialStateIndices.push_back(id); // Block the current initial state to search for the next one. + if (!blockingExpression.isInitialized()) { + break; + } solver->add(blockingExpression); } @@ -314,7 +318,7 @@ namespace storm { template<typename ValueType, typename StateType> boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> PrismNextStateGenerator<ValueType, StateType>::getActiveCommandsByActionIndex(uint_fast64_t const& actionIndex) { boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> result((std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>())); - + // Iterate over all modules. for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) { storm::prism::Module const& module = program.getModule(i); @@ -445,7 +449,6 @@ namespace storm { for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { storm::prism::Command const& command = *iteratorList[i]; - for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) { storm::prism::Update const& update = command.getUpdate(j); diff --git a/src/parser/PrismParser.cpp b/src/parser/PrismParser.cpp index 7d54f18c6..f9f4350b9 100644 --- a/src/parser/PrismParser.cpp +++ b/src/parser/PrismParser.cpp @@ -65,6 +65,8 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in line " << lineNumber << " of file " << filename << "."); } + STORM_LOG_TRACE("Parsed PRISM input: " << result); + return result; } diff --git a/src/storage/prism/Module.h b/src/storage/prism/Module.h index 620432580..df8a61c21 100644 --- a/src/storage/prism/Module.h +++ b/src/storage/prism/Module.h @@ -104,7 +104,6 @@ namespace storm { */ std::set<storm::expressions::Variable> getAllExpressionVariables() const; - /*! * Retrieves a list of expressions that characterize the legal ranges of all variables declared by this * module. diff --git a/src/storage/prism/Program.cpp b/src/storage/prism/Program.cpp index 4962157eb..acb17a17e 100644 --- a/src/storage/prism/Program.cpp +++ b/src/storage/prism/Program.cpp @@ -734,6 +734,12 @@ namespace storm { } } + // 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; + // Now we can substitute the constants in all expressions appearing in the program. std::vector<BooleanVariable> newBooleanVariables; newBooleanVariables.reserve(this->getNumberOfGlobalBooleanVariables()); @@ -757,6 +763,9 @@ namespace storm { newModules.reserve(this->getNumberOfModules()); for (auto const& module : this->getModules()) { newModules.emplace_back(module.substitute(constantSubstitution)); + + // 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())); } std::vector<RewardModel> newRewardModels; @@ -773,7 +782,37 @@ namespace storm { newLabels.emplace_back(label.substitute(constantSubstitution)); } - return Program(this->manager, this->getModelType(), newConstants, newBooleanVariables, newIntegerVariables, newFormulas, newModules, this->getActionNameToIndexMapping(), newRewardModels, newLabels, newInitialConstruct, this->getOptionalSystemCompositionConstruct()); + // If we have to delete whole actions, do so now. + std::map<std::string, uint_fast64_t> newActionToIndexMap; + 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(this->getNumberOfModules()); + for (auto const& module : newModules) { + cleanedModules.emplace_back(module.restrictCommands(actionsToKeep)); + } + newModules = std::move(cleanedModules); + + std::vector<RewardModel> cleanedRewardModels; + cleanedRewardModels.reserve(this->getNumberOfRewardModels()); + for (auto const& rewardModel : newRewardModels) { + cleanedRewardModels.emplace_back(rewardModel.restrictActionRelatedRewards(actionsToKeep)); + } + newRewardModels = std::move(cleanedRewardModels); + + for (auto const& entry : this->getActionNameToIndexMapping()) { + if (actionsToKeep.find(entry.second) != actionsToKeep.end()) { + newActionToIndexMap.emplace(entry.first, entry.second); + } + } + } + + return Program(this->manager, this->getModelType(), newConstants, newBooleanVariables, newIntegerVariables, newFormulas, newModules, actionIndicesToDelete.empty() ? this->getActionNameToIndexMapping() : newActionToIndexMap, newRewardModels, newLabels, newInitialConstruct, this->getOptionalSystemCompositionConstruct()); } void Program::checkValidity(Program::ValidityCheckLevel lvl) const { @@ -1153,17 +1192,19 @@ namespace storm { } Program Program::simplify() { + // Start by substituting the constants, because this will potentially erase some commands or even actions. + Program substitutedProgram = this->substituteConstants(); + std::vector<Module> newModules; - std::vector<Constant> newConstants = this->getConstants(); - for (auto const& module : this->getModules()) { - // Remove identity assignments from the updates + std::vector<Constant> newConstants = substitutedProgram.getConstants(); + for (auto const& module : substitutedProgram.getModules()) { + // Remove identity assignments from the updates. std::vector<Command> newCommands; for (auto const& command : module.getCommands()) { 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> integerVars; for (auto const& variable : module.getBooleanVariables()) { @@ -1179,11 +1220,11 @@ namespace storm { // Check all assignments. for (auto const& assignment : update.getAssignments()) { auto bit = booleanVars.find(assignment.getVariable()); - if(bit != booleanVars.end()) { + if (bit != booleanVars.end()) { booleanVars.erase(bit); } else { auto iit = integerVars.find(assignment.getVariable()); - if(iit != integerVars.end()) { + if (iit != integerVars.end()) { integerVars.erase(iit); } } @@ -1192,31 +1233,30 @@ namespace storm { } std::vector<storm::prism::BooleanVariable> newBVars; - for(auto const& variable : module.getBooleanVariables()) { - if(booleanVars.count(variable.getExpressionVariable()) == 0) { + for (auto const& variable : module.getBooleanVariables()) { + if (booleanVars.find(variable.getExpressionVariable()) == booleanVars.end()) { newBVars.push_back(variable); } } std::vector<storm::prism::IntegerVariable> newIVars; - for(auto const& variable : module.getIntegerVariables()) { - if(integerVars.count(variable.getExpressionVariable()) == 0) { + for (auto const& variable : module.getIntegerVariables()) { + if (integerVars.find(variable.getExpressionVariable()) == integerVars.end()) { newIVars.push_back(variable); } } newModules.emplace_back(module.getName(), newBVars, newIVars, newCommands); - for(auto const& entry : booleanVars) { + for (auto const& entry : booleanVars) { newConstants.emplace_back(entry.first, entry.second); } - for(auto const& entry : integerVars) { + for (auto const& entry : integerVars) { newConstants.emplace_back(entry.first, entry.second); } } - return replaceModulesAndConstantsInProgram(newModules, newConstants).substituteConstants(); - + return substitutedProgram.replaceModulesAndConstantsInProgram(newModules, newConstants); } Program Program::replaceModulesAndConstantsInProgram(std::vector<Module> const& newModules, std::vector<Constant> const& newConstants) { diff --git a/src/storage/prism/RewardModel.cpp b/src/storage/prism/RewardModel.cpp index 30c43728c..52ef5dc67 100644 --- a/src/storage/prism/RewardModel.cpp +++ b/src/storage/prism/RewardModel.cpp @@ -81,6 +81,24 @@ namespace storm { 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) { stream << "rewards"; if (rewardModel.getName() != "") { diff --git a/src/storage/prism/RewardModel.h b/src/storage/prism/RewardModel.h index c62aff61a..01ab69508 100644 --- a/src/storage/prism/RewardModel.h +++ b/src/storage/prism/RewardModel.h @@ -4,6 +4,7 @@ #include <string> #include <vector> #include <map> +#include <boost/container/flat_set.hpp> #include "src/storage/prism/StateReward.h" #include "src/storage/prism/StateActionReward.h" @@ -108,6 +109,14 @@ namespace storm { */ 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); private: diff --git a/src/utility/storm.cpp b/src/utility/storm.cpp index 5956e72c9..c6d2f9c65 100644 --- a/src/utility/storm.cpp +++ b/src/utility/storm.cpp @@ -10,7 +10,7 @@ namespace storm { 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(); return program; } From 3ea11188b7f0c9bb6e3784686eece7678594108d Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 19 Aug 2016 19:35:03 +0200 Subject: [PATCH 14/34] fixed an issue in the CMakeLists.txt that prevented carl from being properly loaded if it's not already present Former-commit-id: 95b83d39882a6bd743d65b484fb3e5d168cb7020 --- resources/3rdparty/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/3rdparty/CMakeLists.txt b/resources/3rdparty/CMakeLists.txt index 042eaea43..244e24057 100644 --- a/resources/3rdparty/CMakeLists.txt +++ b/resources/3rdparty/CMakeLists.txt @@ -204,7 +204,7 @@ if(USE_CARL) LOG_INSTALL ON ) - add_dependencies(resources xercesc) + add_dependencies(resources carl) include_directories(${STORM_3RDPARTY_BINARY_DIR}/carl/include) list(APPEND STORM_LINK_LIBRARIES ${STORM_3RDPARTY_BINARY_DIR}/carl/lib/libcarl${DYNAMIC_EXT}) set(STORM_HAVE_CARL ON) From bcb13a4fe1140ea6d415ba94c9fd9ca167404a2b Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 19 Aug 2016 21:36:56 +0200 Subject: [PATCH 15/34] moved deletion of commands (if guard becomes false) from Program::substitute to Program::simplify Former-commit-id: ec5b4d4a579898eb36252f1e0b0fb786b8ea7c50 --- src/storage/prism/Module.cpp | 5 +- src/storage/prism/Program.cpp | 119 +++++++++++++++++----------------- src/storage/prism/Program.h | 8 --- 3 files changed, 61 insertions(+), 71 deletions(-) diff --git a/src/storage/prism/Module.cpp b/src/storage/prism/Module.cpp index 7b929edfc..755c4c78a 100644 --- a/src/storage/prism/Module.cpp +++ b/src/storage/prism/Module.cpp @@ -188,10 +188,7 @@ namespace storm { std::vector<Command> newCommands; newCommands.reserve(this->getNumberOfCommands()); for (auto const& command : this->getCommands()) { - Command newCommand = command.substitute(substitution); - if (!newCommand.getGuardExpression().isFalse()) { - newCommands.emplace_back(newCommand); - } + newCommands.emplace_back(command.substitute(substitution)); } return Module(this->getName(), newBooleanVariables, newIntegerVariables, newCommands, this->getFilename(), this->getLineNumber()); diff --git a/src/storage/prism/Program.cpp b/src/storage/prism/Program.cpp index acb17a17e..cdc3d323a 100644 --- a/src/storage/prism/Program.cpp +++ b/src/storage/prism/Program.cpp @@ -717,7 +717,7 @@ namespace storm { } 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::vector<Constant> newConstants(this->getConstants()); for (uint_fast64_t constantIndex = 0; constantIndex < newConstants.size(); ++constantIndex) { @@ -734,12 +734,6 @@ namespace storm { } } - // 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; - // Now we can substitute the constants in all expressions appearing in the program. std::vector<BooleanVariable> newBooleanVariables; newBooleanVariables.reserve(this->getNumberOfGlobalBooleanVariables()); @@ -763,9 +757,6 @@ namespace storm { newModules.reserve(this->getNumberOfModules()); for (auto const& module : this->getModules()) { newModules.emplace_back(module.substitute(constantSubstitution)); - - // 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())); } std::vector<RewardModel> newRewardModels; @@ -782,37 +773,7 @@ namespace storm { newLabels.emplace_back(label.substitute(constantSubstitution)); } - // If we have to delete whole actions, do so now. - std::map<std::string, uint_fast64_t> newActionToIndexMap; - 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(this->getNumberOfModules()); - for (auto const& module : newModules) { - cleanedModules.emplace_back(module.restrictCommands(actionsToKeep)); - } - newModules = std::move(cleanedModules); - - std::vector<RewardModel> cleanedRewardModels; - cleanedRewardModels.reserve(this->getNumberOfRewardModels()); - for (auto const& rewardModel : newRewardModels) { - cleanedRewardModels.emplace_back(rewardModel.restrictActionRelatedRewards(actionsToKeep)); - } - newRewardModels = std::move(cleanedRewardModels); - - for (auto const& entry : this->getActionNameToIndexMapping()) { - if (actionsToKeep.find(entry.second) != actionsToKeep.end()) { - newActionToIndexMap.emplace(entry.first, entry.second); - } - } - } - - return Program(this->manager, this->getModelType(), newConstants, newBooleanVariables, newIntegerVariables, newFormulas, newModules, actionIndicesToDelete.empty() ? this->getActionNameToIndexMapping() : newActionToIndexMap, newRewardModels, newLabels, newInitialConstruct, this->getOptionalSystemCompositionConstruct()); + return Program(this->manager, this->getModelType(), newConstants, newBooleanVariables, newIntegerVariables, newFormulas, newModules, this->getActionNameToIndexMapping(), newRewardModels, newLabels, newInitialConstruct, this->getOptionalSystemCompositionConstruct()); } void Program::checkValidity(Program::ValidityCheckLevel lvl) const { @@ -1195,13 +1156,22 @@ namespace storm { // 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<Constant> newConstants = substitutedProgram.getConstants(); 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; 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. @@ -1214,38 +1184,44 @@ namespace storm { 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) { // Check all updates. for (auto const& update : command.getUpdates()) { // Check all assignments. for (auto const& assignment : update.getAssignments()) { - auto bit = booleanVars.find(assignment.getVariable()); - if (bit != booleanVars.end()) { - booleanVars.erase(bit); + if (assignment.getVariable().getType().isBooleanType()) { + auto it = booleanVars.find(assignment.getVariable()); + if (it != booleanVars.end()) { + booleanVars.erase(it); + } } else { - auto iit = integerVars.find(assignment.getVariable()); - if (iit != integerVars.end()) { - integerVars.erase(iit); + auto it = integerVars.find(assignment.getVariable()); + if (it != integerVars.end()) { + integerVars.erase(it); } } } } } - std::vector<storm::prism::BooleanVariable> newBVars; + std::vector<storm::prism::BooleanVariable> newBooleanVars; for (auto const& variable : module.getBooleanVariables()) { 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()) { 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) { newConstants.emplace_back(entry.first, entry.second); @@ -1256,11 +1232,36 @@ namespace storm { } } - return substitutedProgram.replaceModulesAndConstantsInProgram(newModules, newConstants); - } - - 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()); + // 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(), getInitialConstruct(), this->getOptionalSystemCompositionConstruct()); } Program Program::flattenModules(std::unique_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory) const { diff --git a/src/storage/prism/Program.h b/src/storage/prism/Program.h index 71719c583..8c30079e0 100644 --- a/src/storage/prism/Program.h +++ b/src/storage/prism/Program.h @@ -661,14 +661,6 @@ namespace storm { // A mapping from variable names to the modules in which they were declared. 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); From 96891acfe7e53805c6ed6813538319704354adc7 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 22 Aug 2016 13:10:03 +0200 Subject: [PATCH 16/34] included missing (at least for some compilers) header Former-commit-id: 4792acf519378b62e9899f5b941559c5b6fffcd6 --- src/modelchecker/AbstractModelChecker.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modelchecker/AbstractModelChecker.cpp b/src/modelchecker/AbstractModelChecker.cpp index 616dcf828..5d1759b94 100644 --- a/src/modelchecker/AbstractModelChecker.cpp +++ b/src/modelchecker/AbstractModelChecker.cpp @@ -17,6 +17,7 @@ #include "src/models/symbolic/Mdp.h" #include "src/models/sparse/MarkovAutomaton.h" #include "src/models/sparse/StandardRewardModel.h" +#include "src/models/sparse/StandardRewardModel.h" #include "src/storage/dd/Add.h" #include "src/storage/dd/Bdd.h" From a8383a283df2ec0de677d411ccf52d2e01a2704b Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 22 Aug 2016 13:40:20 +0200 Subject: [PATCH 17/34] fixed wrong header inclusion in previous commit Former-commit-id: f91e63cccd11cc119e4c7eb4320b4575693250aa --- src/modelchecker/AbstractModelChecker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modelchecker/AbstractModelChecker.cpp b/src/modelchecker/AbstractModelChecker.cpp index 5d1759b94..660906acb 100644 --- a/src/modelchecker/AbstractModelChecker.cpp +++ b/src/modelchecker/AbstractModelChecker.cpp @@ -17,7 +17,7 @@ #include "src/models/symbolic/Mdp.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/Bdd.h" From d1ea67524587f8cb6744d6f5c69158a5fcde7c65 Mon Sep 17 00:00:00 2001 From: TimQu <tim.quatmann@web.de> Date: Tue, 30 Aug 2016 01:54:24 +0200 Subject: [PATCH 18/34] Added missing case for Power when converting to z3::expr Former-commit-id: 4279fba636d06c93c030003b6c1f105139a6e2a8 --- src/adapters/Z3ExpressionAdapter.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/adapters/Z3ExpressionAdapter.cpp b/src/adapters/Z3ExpressionAdapter.cpp index 6f4efc178..a80355422 100644 --- a/src/adapters/Z3ExpressionAdapter.cpp +++ b/src/adapters/Z3ExpressionAdapter.cpp @@ -177,6 +177,8 @@ namespace storm { return ite(leftResult <= rightResult, leftResult, rightResult); case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Max: return ite(leftResult >= rightResult, leftResult, rightResult); + case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Power: + return pw(leftResult,rightResult); default: STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression: unknown numerical binary operator '" << static_cast<int>(expression.getOperatorType()) << "' in expression " << expression << "."); } From 1b19372a14a34fa5c828964df264fc7be1a8ebde Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Sat, 3 Sep 2016 19:20:05 +0200 Subject: [PATCH 19/34] changed a default argument initializer list to make compilers happier Former-commit-id: 41dcbd2f10c6528714e4bb727c78f70f519e0400 --- src/parser/JaniParser.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/parser/JaniParser.h b/src/parser/JaniParser.h index e4fafcd2a..90891c759 100644 --- a/src/parser/JaniParser.h +++ b/src/parser/JaniParser.h @@ -34,7 +34,8 @@ namespace storm { storm::jani::Model parseModel(); storm::jani::Automaton parseAutomaton(json const& automatonStructure); 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: /** * Helper for parsing the actions of a model. @@ -43,8 +44,6 @@ namespace storm { std::shared_ptr<storm::jani::Composition> parseComposition(json const& compositionStructure); - - }; } } From 92932fced10eecd82b93c5fedcfea557b2e49b2f Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 5 Sep 2016 17:12:30 +0200 Subject: [PATCH 20/34] support for initial constructs in PRISM programs Former-commit-id: 0c8132aa432a46bff8de64792bd9a9204efd2ce3 --- src/parser/PrismParser.cpp | 18 +-- src/parser/PrismParser.h | 6 +- src/storage/prism/BooleanVariable.cpp | 16 ++- src/storage/prism/BooleanVariable.h | 2 + src/storage/prism/IntegerVariable.cpp | 14 ++- src/storage/prism/IntegerVariable.h | 2 + src/storage/prism/Module.cpp | 11 +- src/storage/prism/Module.h | 5 + src/storage/prism/Program.cpp | 171 ++++++++++++++++---------- src/storage/prism/Program.h | 7 +- src/storage/prism/Variable.cpp | 12 +- src/storage/prism/Variable.h | 27 ++-- 12 files changed, 199 insertions(+), 92 deletions(-) diff --git a/src/parser/PrismParser.cpp b/src/parser/PrismParser.cpp index f9f4350b9..d3e5191e2 100644 --- a/src/parser/PrismParser.cpp +++ b/src/parser/PrismParser.cpp @@ -105,10 +105,10 @@ namespace storm { formulaDefinition = (qi::lit("formula") > identifier > qi::lit("=") > expressionParser > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createFormula, phoenix::ref(*this), qi::_1, qi::_2)]; formulaDefinition.name("formula definition"); - booleanVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("bool")) > ((qi::lit("init") > expressionParser) | qi::attr(manager->boolean(false))) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createBooleanVariable, phoenix::ref(*this), qi::_1, qi::_2)]; + booleanVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("bool")) > -((qi::lit("init") > expressionParser[qi::_a = qi::_1]) | qi::attr(manager->boolean(false))) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createBooleanVariable, phoenix::ref(*this), qi::_1, qi::_a)]; booleanVariableDefinition.name("boolean variable definition"); - integerVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("[")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), false)]) > expressionParser[qi::_a = qi::_1] > qi::lit("..") > expressionParser > qi::lit("]")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), true)] > -(qi::lit("init") > expressionParser[qi::_a = qi::_1]) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createIntegerVariable, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_a)]; + integerVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("[")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), false)]) > expressionParser > qi::lit("..") > expressionParser > qi::lit("]")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), true)] > -(qi::lit("init") > expressionParser[qi::_a = qi::_1]) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createIntegerVariable, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_a)]; integerVariableDefinition.name("integer variable definition"); variableDefinition = (booleanVariableDefinition[phoenix::push_back(qi::_r1, qi::_1)] | integerVariableDefinition[phoenix::push_back(qi::_r2, qi::_1)]); @@ -210,7 +210,7 @@ namespace storm { moduleDefinitionList %= +(moduleRenaming(qi::_r1) | moduleDefinition(qi::_r1))[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::modules, qi::_r1), qi::_1)]; moduleDefinitionList.name("module list"); - start = (qi::eps + start = (qi::eps[phoenix::bind(&PrismParser::removeInitialConstruct, phoenix::ref(*this), qi::_a)] > modelTypeDefinition[phoenix::bind(&GlobalProgramInformation::modelType, qi::_a) = qi::_1] > *(definedConstantDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::constants, qi::_a), qi::_1)] | undefinedConstantDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::constants, qi::_a), qi::_1)] @@ -278,7 +278,7 @@ namespace storm { return true; } - bool PrismParser::addInitialStatesConstruct(storm::expressions::Expression initialStatesExpression, GlobalProgramInformation& globalProgramInformation) { + bool PrismParser::addInitialStatesConstruct(storm::expressions::Expression const& initialStatesExpression, GlobalProgramInformation& globalProgramInformation) { STORM_LOG_THROW(!globalProgramInformation.hasInitialConstruct, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": Program must not define two initial constructs."); if (globalProgramInformation.hasInitialConstruct) { return false; @@ -587,7 +587,7 @@ namespace storm { auto const& renamingPair = renaming.find(variable.getName()); STORM_LOG_THROW(renamingPair != renaming.end(), storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": Boolean variable '" << variable.getName() << " was not renamed."); - booleanVariables.push_back(storm::prism::BooleanVariable(manager->getVariable(renamingPair->second), variable.getInitialValueExpression().substitute(expressionRenaming), this->getFilename(), get_line(qi::_1))); + booleanVariables.push_back(storm::prism::BooleanVariable(manager->getVariable(renamingPair->second), variable.hasInitialValue() ? variable.getInitialValueExpression().substitute(expressionRenaming) : variable.getInitialValueExpression(), this->getFilename(), get_line(qi::_1))); } // Rename the integer variables. @@ -596,7 +596,7 @@ namespace storm { auto const& renamingPair = renaming.find(variable.getName()); STORM_LOG_THROW(renamingPair != renaming.end(), storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": Integer variable '" << variable.getName() << " was not renamed."); - integerVariables.push_back(storm::prism::IntegerVariable(manager->getVariable(renamingPair->second), variable.getLowerBoundExpression().substitute(expressionRenaming), variable.getUpperBoundExpression().substitute(expressionRenaming), variable.getInitialValueExpression().substitute(expressionRenaming), this->getFilename(), get_line(qi::_1))); + integerVariables.push_back(storm::prism::IntegerVariable(manager->getVariable(renamingPair->second), variable.getLowerBoundExpression().substitute(expressionRenaming), variable.getUpperBoundExpression().substitute(expressionRenaming), variable.hasInitialValue() ? variable.getInitialValueExpression().substitute(expressionRenaming) : variable.getInitialValueExpression(), this->getFilename(), get_line(qi::_1))); } // Rename commands. @@ -642,7 +642,11 @@ namespace storm { } storm::prism::Program PrismParser::createProgram(GlobalProgramInformation const& globalProgramInformation) const { - return storm::prism::Program(manager, globalProgramInformation.modelType, globalProgramInformation.constants, globalProgramInformation.globalBooleanVariables, globalProgramInformation.globalIntegerVariables, globalProgramInformation.formulas, globalProgramInformation.modules, globalProgramInformation.actionIndices, globalProgramInformation.rewardModels, globalProgramInformation.labels, secondRun && !globalProgramInformation.hasInitialConstruct ? boost::none : boost::optional<storm::prism::InitialConstruct>(storm::prism::InitialConstruct(manager->boolean(false))), globalProgramInformation.systemCompositionConstruct, this->getFilename(), 1, this->secondRun); + return storm::prism::Program(manager, globalProgramInformation.modelType, globalProgramInformation.constants, globalProgramInformation.globalBooleanVariables, globalProgramInformation.globalIntegerVariables, globalProgramInformation.formulas, globalProgramInformation.modules, globalProgramInformation.actionIndices, globalProgramInformation.rewardModels, globalProgramInformation.labels, secondRun && !globalProgramInformation.hasInitialConstruct ? boost::none : boost::make_optional(globalProgramInformation.initialConstruct), globalProgramInformation.systemCompositionConstruct, this->getFilename(), 1, this->secondRun); + } + + void PrismParser::removeInitialConstruct(GlobalProgramInformation& globalProgramInformation) const { + globalProgramInformation.hasInitialConstruct = false; } } // namespace parser } // namespace storm diff --git a/src/parser/PrismParser.h b/src/parser/PrismParser.h index 84a5b601e..2a83e3193 100644 --- a/src/parser/PrismParser.h +++ b/src/parser/PrismParser.h @@ -188,7 +188,7 @@ namespace storm { // Rules for variable definitions. qi::rule<Iterator, qi::unused_type(std::vector<storm::prism::BooleanVariable>&, std::vector<storm::prism::IntegerVariable>&), Skipper> variableDefinition; - qi::rule<Iterator, storm::prism::BooleanVariable(), Skipper> booleanVariableDefinition; + qi::rule<Iterator, storm::prism::BooleanVariable(), qi::locals<storm::expressions::Expression>, Skipper> booleanVariableDefinition; qi::rule<Iterator, storm::prism::IntegerVariable(), qi::locals<storm::expressions::Expression>, Skipper> integerVariableDefinition; // Rules for command definitions. @@ -241,7 +241,7 @@ namespace storm { // Helper methods used in the grammar. bool isValidIdentifier(std::string const& identifier); - bool addInitialStatesConstruct(storm::expressions::Expression initialStatesExpression, GlobalProgramInformation& globalProgramInformation); + bool addInitialStatesConstruct(storm::expressions::Expression const& initialStatesExpression, GlobalProgramInformation& globalProgramInformation); bool addSystemCompositionConstruct(std::shared_ptr<storm::prism::Composition> const& composition, GlobalProgramInformation& globalProgramInformation); @@ -274,6 +274,8 @@ namespace storm { storm::prism::Module createRenamedModule(std::string const& newModuleName, std::string const& oldModuleName, std::map<std::string, std::string> const& renaming, GlobalProgramInformation& globalProgramInformation) const; storm::prism::Program createProgram(GlobalProgramInformation const& globalProgramInformation) const; + void removeInitialConstruct(GlobalProgramInformation& globalProgramInformation) const; + // An error handler function. phoenix::function<SpiritErrorHandler> handler; }; diff --git a/src/storage/prism/BooleanVariable.cpp b/src/storage/prism/BooleanVariable.cpp index c38812ec6..422b2266f 100644 --- a/src/storage/prism/BooleanVariable.cpp +++ b/src/storage/prism/BooleanVariable.cpp @@ -1,5 +1,7 @@ #include "src/storage/prism/BooleanVariable.h" +#include "src/storage/expressions/ExpressionManager.h" + namespace storm { 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) { @@ -7,11 +9,21 @@ namespace storm { } 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) { - stream << variable.getName() << ": bool init " << variable.getInitialValueExpression() << ";"; + stream << variable.getName() << ": bool"; + if (variable.hasInitialValue()) { + stream << " init " << variable.getInitialValueExpression(); + } + stream << ";"; return stream; } diff --git a/src/storage/prism/BooleanVariable.h b/src/storage/prism/BooleanVariable.h index 5b43e191c..c5c3ba8e4 100644 --- a/src/storage/prism/BooleanVariable.h +++ b/src/storage/prism/BooleanVariable.h @@ -37,6 +37,8 @@ namespace storm { */ 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); }; diff --git a/src/storage/prism/IntegerVariable.cpp b/src/storage/prism/IntegerVariable.cpp index b2306ece0..8b60b0e56 100644 --- a/src/storage/prism/IntegerVariable.cpp +++ b/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 { - 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) { - 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; } } // namespace prism diff --git a/src/storage/prism/IntegerVariable.h b/src/storage/prism/IntegerVariable.h index fc1c6ecf5..335c2ce05 100644 --- a/src/storage/prism/IntegerVariable.h +++ b/src/storage/prism/IntegerVariable.h @@ -60,6 +60,8 @@ namespace storm { */ 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); private: diff --git a/src/storage/prism/Module.cpp b/src/storage/prism/Module.cpp index 755c4c78a..095ac3e11 100644 --- a/src/storage/prism/Module.cpp +++ b/src/storage/prism/Module.cpp @@ -42,7 +42,7 @@ namespace storm { std::vector<storm::prism::IntegerVariable> const& Module::getIntegerVariables() const { return this->integerVariables; } - + std::set<storm::expressions::Variable> Module::getAllExpressionVariables() const { std::set<storm::expressions::Variable> result; for (auto const& var : this->getBooleanVariables()) { @@ -221,6 +221,15 @@ namespace storm { 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) { stream << "module " << module.getName() << std::endl; for (auto const& booleanVariable : module.getBooleanVariables()) { diff --git a/src/storage/prism/Module.h b/src/storage/prism/Module.h index df8a61c21..c3179b407 100644 --- a/src/storage/prism/Module.h +++ b/src/storage/prism/Module.h @@ -225,6 +225,11 @@ namespace storm { */ 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); private: diff --git a/src/storage/prism/Program.cpp b/src/storage/prism/Program.cpp index cdc3d323a..3cf9df8ae 100644 --- a/src/storage/prism/Program.cpp +++ b/src/storage/prism/Program.cpp @@ -152,20 +152,26 @@ namespace storm { if (initialConstruct) { this->initialConstruct = initialConstruct.get(); } else { + // First, add all missing initial values. + this->createMissingInitialValues(); + for (auto& modules : this->modules) { + modules.createMissingInitialValues(); + } + // Create a new initial construct if none was given. storm::expressions::Expression newInitialExpression = manager->boolean(true); - for (auto const& booleanVariable : this->getGlobalBooleanVariables()) { + for (auto& booleanVariable : this->getGlobalBooleanVariables()) { newInitialExpression = newInitialExpression && storm::expressions::iff(booleanVariable.getExpression(), booleanVariable.getInitialValueExpression()); } - for (auto const& integerVariable : this->getGlobalIntegerVariables()) { + for (auto& integerVariable : this->getGlobalIntegerVariables()) { newInitialExpression = newInitialExpression && integerVariable.getExpression() == integerVariable.getInitialValueExpression(); } - for (auto const& module : this->getModules()) { - for (auto const& booleanVariable : module.getBooleanVariables()) { + for (auto& module : this->getModules()) { + for (auto& booleanVariable : module.getBooleanVariables()) { newInitialExpression = newInitialExpression && storm::expressions::iff(booleanVariable.getExpression(), booleanVariable.getInitialValueExpression()); } - for (auto const& integerVariable : module.getIntegerVariables()) { + for (auto& integerVariable : module.getIntegerVariables()) { newInitialExpression = newInitialExpression && integerVariable.getExpression() == integerVariable.getInitialValueExpression(); } } @@ -241,13 +247,17 @@ namespace storm { // Now check initial value expressions of global variables. for (auto const& booleanVariable : this->getGlobalBooleanVariables()) { - if (booleanVariable.getInitialValueExpression().containsVariable(undefinedConstantVariables)) { - return false; + if (booleanVariable.hasInitialValue()) { + if (booleanVariable.getInitialValueExpression().containsVariable(undefinedConstantVariables)) { + return false; + } } } for (auto const& integerVariable : this->getGlobalIntegerVariables()) { - if (integerVariable.getInitialValueExpression().containsVariable(undefinedConstantVariables)) { - return false; + if (integerVariable.hasInitialValue()) { + if (integerVariable.getInitialValueExpression().containsVariable(undefinedConstantVariables)) { + return false; + } } if (integerVariable.getLowerBoundExpression().containsVariable(undefinedConstantVariables)) { return false; @@ -809,18 +819,20 @@ namespace storm { // Now we check the variable declarations. We start with the global variables. std::set<storm::expressions::Variable> variables; for (auto const& variable : this->getGlobalBooleanVariables()) { - // Check the initial value of the variable. - std::set<storm::expressions::Variable> containedVariables = variable.getInitialValueExpression().getVariables(); - std::set<storm::expressions::Variable> illegalVariables; - std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin())); - bool isValid = illegalVariables.empty(); - - if (!isValid) { - std::vector<std::string> illegalVariableNames; - for (auto const& var : illegalVariables) { - illegalVariableNames.push_back(var.getName()); + if (variable.hasInitialValue()) { + // Check the initial value of the variable. + std::set<storm::expressions::Variable> containedVariables = variable.getInitialValueExpression().getVariables(); + std::set<storm::expressions::Variable> illegalVariables; + std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin())); + bool isValid = illegalVariables.empty(); + + if (!isValid) { + 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. @@ -855,16 +867,18 @@ 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, ",") << "."); } - // Check the initial value of the variable. - containedVariables = variable.getInitialValueExpression().getVariables(); - std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin())); - isValid = illegalVariables.empty(); - if (!isValid) { - std::vector<std::string> illegalVariableNames; - for (auto const& var : illegalVariables) { - illegalVariableNames.push_back(var.getName()); + if (variable.hasInitialValue()) { + // Check the initial value of the variable. + containedVariables = variable.getInitialValueExpression().getVariables(); + std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin())); + isValid = illegalVariables.empty(); + if (!isValid) { + 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. @@ -877,17 +891,19 @@ namespace storm { // Now go through the variables of the modules. for (auto const& module : this->getModules()) { for (auto const& variable : module.getBooleanVariables()) { - // Check the initial value of the variable. - std::set<storm::expressions::Variable> containedVariables = variable.getInitialValueExpression().getVariables(); - std::set<storm::expressions::Variable> illegalVariables; - std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin())); - bool isValid = illegalVariables.empty(); - if (!isValid) { - std::vector<std::string> illegalVariableNames; - for (auto const& var : illegalVariables) { - illegalVariableNames.push_back(var.getName()); + if (variable.hasInitialValue()) { + // Check the initial value of the variable. + std::set<storm::expressions::Variable> containedVariables = variable.getInitialValueExpression().getVariables(); + std::set<storm::expressions::Variable> illegalVariables; + std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin())); + bool isValid = illegalVariables.empty(); + if (!isValid) { + 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. @@ -920,17 +936,19 @@ 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, ",") << "."); } - // Check the initial value of the variable. - containedVariables = variable.getInitialValueExpression().getVariables(); - illegalVariables.clear(); - std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin())); - isValid = illegalVariables.empty(); - if (!isValid) { - std::vector<std::string> illegalVariableNames; - for (auto const& var : illegalVariables) { - illegalVariableNames.push_back(var.getName()); + if (variable.hasInitialValue()) { + // Check the initial value of the variable. + containedVariables = variable.getInitialValueExpression().getVariables(); + illegalVariables.clear(); + std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(), std::inserter(illegalVariables, illegalVariables.begin())); + isValid = illegalVariables.empty(); + if (!isValid) { + 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. @@ -1571,7 +1589,7 @@ namespace storm { } storm::jani::Model janiModel("jani_from_prism", modelType, 1, manager); storm::expressions::Expression globalInitialStatesExpression; - + // Add all constants of the PRISM program to the JANI model. 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)); @@ -1580,13 +1598,17 @@ namespace storm { // Add all global variables of the PRISM program to the JANI model. for (auto const& variable : globalIntegerVariables) { janiModel.addBoundedIntegerVariable(storm::jani::BoundedIntegerVariable(variable.getName(), variable.getExpressionVariable(), variable.getLowerBoundExpression(), variable.getUpperBoundExpression())); - storm::expressions::Expression variableInitialExpression = variable.getExpressionVariable() == variable.getInitialValueExpression(); - globalInitialStatesExpression = globalInitialStatesExpression.isInitialized() ? globalInitialStatesExpression && variableInitialExpression : variableInitialExpression; + if (variable.hasInitialValue()) { + storm::expressions::Expression variableInitialExpression = variable.getExpressionVariable() == variable.getInitialValueExpression(); + globalInitialStatesExpression = globalInitialStatesExpression.isInitialized() ? globalInitialStatesExpression && variableInitialExpression : variableInitialExpression; + } } for (auto const& variable : globalBooleanVariables) { janiModel.addBooleanVariable(storm::jani::BooleanVariable(variable.getName(), variable.getExpressionVariable())); - storm::expressions::Expression variableInitialExpression = storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression()); - globalInitialStatesExpression = globalInitialStatesExpression.isInitialized() ? globalInitialStatesExpression && variableInitialExpression : variableInitialExpression; + if (variable.hasInitialValue()) { + storm::expressions::Expression variableInitialExpression = storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression()); + globalInitialStatesExpression = globalInitialStatesExpression.isInitialized() ? globalInitialStatesExpression && variableInitialExpression : variableInitialExpression; + } } // Add all actions of the PRISM program to the JANI model. @@ -1598,7 +1620,7 @@ namespace storm { } // 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. std::map<storm::expressions::Variable, std::set<uint_fast64_t>> variablesToAccessingModuleIndices; for (uint_fast64_t index = 0; index < modules.size(); ++index) { @@ -1627,20 +1649,24 @@ namespace storm { for (auto const& module : modules) { storm::jani::Automaton automaton(module.getName()); storm::expressions::Expression initialStatesExpression; - + for (auto const& variable : module.getIntegerVariables()) { storm::jani::BoundedIntegerVariable newIntegerVariable(variable.getName(), variable.getExpressionVariable(), variable.getLowerBoundExpression(), variable.getUpperBoundExpression()); 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 (!allVariablesGlobal && accessingModuleIndices.size() == 1) { automaton.addBoundedIntegerVariable(newIntegerVariable); - storm::expressions::Expression variableInitialExpression = variable.getExpressionVariable() == variable.getInitialValueExpression(); - initialStatesExpression = initialStatesExpression.isInitialized() ? initialStatesExpression && variableInitialExpression : variableInitialExpression; + if (variable.hasInitialValue()) { + storm::expressions::Expression variableInitialExpression = variable.getExpressionVariable() == variable.getInitialValueExpression(); + initialStatesExpression = initialStatesExpression.isInitialized() ? initialStatesExpression && variableInitialExpression : variableInitialExpression; + } } else if (!accessingModuleIndices.empty()) { // Otherwise, we need to make it global. janiModel.addBoundedIntegerVariable(newIntegerVariable); - storm::expressions::Expression variableInitialExpression = variable.getExpressionVariable() == variable.getInitialValueExpression(); - globalInitialStatesExpression = globalInitialStatesExpression.isInitialized() ? globalInitialStatesExpression && variableInitialExpression : variableInitialExpression; + if (variable.hasInitialValue()) { + storm::expressions::Expression variableInitialExpression = variable.getExpressionVariable() == variable.getInitialValueExpression(); + globalInitialStatesExpression = globalInitialStatesExpression.isInitialized() ? globalInitialStatesExpression && variableInitialExpression : variableInitialExpression; + } } } for (auto const& variable : module.getBooleanVariables()) { @@ -1649,13 +1675,17 @@ namespace storm { // 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) { automaton.addBooleanVariable(newBooleanVariable); - storm::expressions::Expression variableInitialExpression = storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression()); - initialStatesExpression = initialStatesExpression.isInitialized() ? initialStatesExpression && variableInitialExpression : variableInitialExpression; + if (variable.hasInitialValue()) { + storm::expressions::Expression variableInitialExpression = storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression()); + initialStatesExpression = initialStatesExpression.isInitialized() ? initialStatesExpression && variableInitialExpression : variableInitialExpression; + } } else if (!accessingModuleIndices.empty()) { // Otherwise, we need to make it global. janiModel.addBooleanVariable(newBooleanVariable); - storm::expressions::Expression variableInitialExpression = storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression()); - globalInitialStatesExpression = globalInitialStatesExpression.isInitialized() ? globalInitialStatesExpression && variableInitialExpression : variableInitialExpression; + if (variable.hasInitialValue()) { + storm::expressions::Expression variableInitialExpression = storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression()); + globalInitialStatesExpression = globalInitialStatesExpression.isInitialized() ? globalInitialStatesExpression && variableInitialExpression : variableInitialExpression; + } } } @@ -1713,6 +1743,19 @@ namespace storm { 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) { switch (type) { case Program::ModelType::UNDEFINED: out << "undefined"; break; diff --git a/src/storage/prism/Program.h b/src/storage/prism/Program.h index 8c30079e0..50bd84603 100644 --- a/src/storage/prism/Program.h +++ b/src/storage/prism/Program.h @@ -175,7 +175,7 @@ namespace storm { * @return The global boolean variables of the program. */ std::vector<BooleanVariable> const& getGlobalBooleanVariables() const; - + /*! * Retrieves a the global boolean variable with the given name. * @@ -587,6 +587,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; + /*! + * 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. std::shared_ptr<storm::expressions::ExpressionManager> manager; diff --git a/src/storage/prism/Variable.cpp b/src/storage/prism/Variable.cpp index 7d347bcec..cda8317a5 100644 --- a/src/storage/prism/Variable.cpp +++ b/src/storage/prism/Variable.cpp @@ -5,11 +5,11 @@ namespace storm { 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. } - 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. } @@ -17,14 +17,18 @@ namespace storm { return this->variable.getName(); } - bool Variable::hasDefaultInitialValue() const { - return this->defaultInitialValue; + bool Variable::hasInitialValue() const { + return this->initialValueExpression.isInitialized(); } storm::expressions::Expression const& Variable::getInitialValueExpression() const { return this->initialValueExpression; } + void Variable::setInitialValueExpression(storm::expressions::Expression const& initialValueExpression) { + this->initialValueExpression = initialValueExpression; + } + storm::expressions::Variable const& Variable::getExpressionVariable() const { return this->variable; } diff --git a/src/storage/prism/Variable.h b/src/storage/prism/Variable.h index 3a19c2b75..40f47eb27 100644 --- a/src/storage/prism/Variable.h +++ b/src/storage/prism/Variable.h @@ -28,19 +28,27 @@ namespace storm { 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. */ 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. * @@ -55,6 +63,10 @@ namespace storm { */ 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. protected: @@ -90,9 +102,6 @@ namespace storm { // The constant expression defining the initial value of the variable. storm::expressions::Expression initialValueExpression; - - // A flag that stores whether the variable has its default initial expression. - bool defaultInitialValue; }; } // namespace prism From 3d426798b3850cb239cf3c71f54c0920d0e86add Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Tue, 6 Sep 2016 15:28:16 +0200 Subject: [PATCH 21/34] added visitor that checks for syntatical equality of expressions Former-commit-id: b6753a48919f06e9bd6289c4c09e81221a2e371c [formerly 2b36b42bfae4b847781ff9bd504f0392ad4c30a1] Former-commit-id: f693de5f3067436af61304b5f412a5bc1226bcf3 --- src/adapters/AddExpressionAdapter.cpp | 54 +++--- src/adapters/AddExpressionAdapter.h | 20 +-- src/adapters/MathsatExpressionAdapter.h | 44 ++--- src/adapters/Z3ExpressionAdapter.cpp | 44 ++--- src/adapters/Z3ExpressionAdapter.h | 20 +-- src/storage/expressions/BaseExpression.cpp | 82 +++++++++ src/storage/expressions/BaseExpression.h | 46 +++++- .../BinaryBooleanFunctionExpression.cpp | 4 +- .../BinaryBooleanFunctionExpression.h | 2 +- .../BinaryNumericalFunctionExpression.cpp | 4 +- .../BinaryNumericalFunctionExpression.h | 2 +- .../expressions/BinaryRelationExpression.cpp | 4 +- .../expressions/BinaryRelationExpression.h | 2 +- .../expressions/BooleanLiteralExpression.cpp | 4 +- .../expressions/BooleanLiteralExpression.h | 2 +- src/storage/expressions/Expression.cpp | 13 +- src/storage/expressions/Expression.h | 9 +- src/storage/expressions/ExpressionVisitor.h | 20 +-- .../expressions/IfThenElseExpression.cpp | 4 +- .../expressions/IfThenElseExpression.h | 2 +- .../expressions/IntegerLiteralExpression.cpp | 4 +- .../expressions/IntegerLiteralExpression.h | 2 +- .../expressions/LinearCoefficientVisitor.cpp | 28 ++-- .../expressions/LinearCoefficientVisitor.h | 20 +-- .../expressions/LinearityCheckVisitor.cpp | 28 ++-- .../expressions/LinearityCheckVisitor.h | 20 +-- .../expressions/RationalLiteralExpression.cpp | 4 +- .../expressions/RationalLiteralExpression.h | 2 +- .../expressions/SubstitutionVisitor.cpp | 44 ++--- src/storage/expressions/SubstitutionVisitor.h | 20 +-- .../SyntacticalEqualityCheckVisitor.cpp | 155 ++++++++++++++++++ .../SyntacticalEqualityCheckVisitor.h | 27 +++ .../expressions/ToExprtkStringVisitor.cpp | 108 ++++++------ .../expressions/ToExprtkStringVisitor.h | 20 +-- .../expressions/ToRationalFunctionVisitor.cpp | 26 +-- .../expressions/ToRationalFunctionVisitor.h | 20 +-- .../expressions/ToRationalNumberVisitor.cpp | 26 +-- .../expressions/ToRationalNumberVisitor.h | 20 +-- .../UnaryBooleanFunctionExpression.cpp | 4 +- .../UnaryBooleanFunctionExpression.h | 2 +- .../UnaryNumericalFunctionExpression.cpp | 4 +- .../UnaryNumericalFunctionExpression.h | 2 +- .../expressions/VariableExpression.cpp | 4 +- src/storage/expressions/VariableExpression.h | 2 +- src/storage/jani/Assignment.cpp | 4 + src/storage/jani/Assignment.h | 2 + src/storage/jani/Edge.cpp | 8 + src/storage/jani/Edge.h | 16 ++ 48 files changed, 677 insertions(+), 327 deletions(-) create mode 100644 src/storage/expressions/SyntacticalEqualityCheckVisitor.cpp create mode 100644 src/storage/expressions/SyntacticalEqualityCheckVisitor.h diff --git a/src/adapters/AddExpressionAdapter.cpp b/src/adapters/AddExpressionAdapter.cpp index 2f0dc7190..f8a8f200e 100644 --- a/src/adapters/AddExpressionAdapter.cpp +++ b/src/adapters/AddExpressionAdapter.cpp @@ -19,37 +19,37 @@ namespace storm { template<storm::dd::DdType Type, typename ValueType> storm::dd::Add<Type, ValueType> AddExpressionAdapter<Type, ValueType>::translateExpression(storm::expressions::Expression const& expression) { if (expression.hasBooleanType()) { - return boost::any_cast<storm::dd::Bdd<Type>>(expression.accept(*this)).template toAdd<ValueType>(); + return boost::any_cast<storm::dd::Bdd<Type>>(expression.accept(*this, boost::none)).template toAdd<ValueType>(); } else { - return boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.accept(*this)); + return boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.accept(*this, boost::none)); } } template<storm::dd::DdType Type, typename ValueType> storm::dd::Bdd<Type> AddExpressionAdapter<Type, ValueType>::translateBooleanExpression(storm::expressions::Expression const& expression) { STORM_LOG_THROW(expression.hasBooleanType(), storm::exceptions::InvalidArgumentException, "Expected expression of boolean type."); - return boost::any_cast<storm::dd::Bdd<Type>>(expression.accept(*this)); + return boost::any_cast<storm::dd::Bdd<Type>>(expression.accept(*this, boost::none)); } template<storm::dd::DdType Type, typename ValueType> - boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::IfThenElseExpression const& expression) { + boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) { if (expression.hasBooleanType()) { - storm::dd::Bdd<Type> elseDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getElseExpression()->accept(*this)); - storm::dd::Bdd<Type> thenDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getThenExpression()->accept(*this)); - storm::dd::Bdd<Type> conditionDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getCondition()->accept(*this)); + storm::dd::Bdd<Type> elseDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getElseExpression()->accept(*this, data)); + storm::dd::Bdd<Type> thenDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getThenExpression()->accept(*this, data)); + storm::dd::Bdd<Type> conditionDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getCondition()->accept(*this, data)); return conditionDd.ite(thenDd, elseDd); } else { - storm::dd::Add<Type, ValueType> elseDd = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getElseExpression()->accept(*this)); - storm::dd::Add<Type, ValueType> thenDd = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getThenExpression()->accept(*this)); - storm::dd::Bdd<Type> conditionDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getCondition()->accept(*this)); + storm::dd::Add<Type, ValueType> elseDd = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getElseExpression()->accept(*this, data)); + storm::dd::Add<Type, ValueType> thenDd = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getThenExpression()->accept(*this, data)); + storm::dd::Bdd<Type> conditionDd = boost::any_cast<storm::dd::Bdd<Type>>(expression.getCondition()->accept(*this, data)); return conditionDd.ite(thenDd, elseDd); } } template<storm::dd::DdType Type, typename ValueType> - boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression) { - storm::dd::Bdd<Type> leftResult = boost::any_cast<storm::dd::Bdd<Type>>(expression.getFirstOperand()->accept(*this)); - storm::dd::Bdd<Type> rightResult = boost::any_cast<storm::dd::Bdd<Type>>(expression.getSecondOperand()->accept(*this)); + boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) { + storm::dd::Bdd<Type> leftResult = boost::any_cast<storm::dd::Bdd<Type>>(expression.getFirstOperand()->accept(*this, data)); + storm::dd::Bdd<Type> rightResult = boost::any_cast<storm::dd::Bdd<Type>>(expression.getSecondOperand()->accept(*this, data)); storm::dd::Bdd<Type> result; switch (expression.getOperatorType()) { @@ -74,9 +74,9 @@ namespace storm { } template<storm::dd::DdType Type, typename ValueType> - boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression) { - storm::dd::Add<Type, ValueType> leftResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getFirstOperand()->accept(*this)); - storm::dd::Add<Type, ValueType> rightResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getSecondOperand()->accept(*this)); + boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) { + storm::dd::Add<Type, ValueType> leftResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getFirstOperand()->accept(*this, data)); + storm::dd::Add<Type, ValueType> rightResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getSecondOperand()->accept(*this, data)); storm::dd::Add<Type, ValueType> result; switch (expression.getOperatorType()) { @@ -109,9 +109,9 @@ namespace storm { } template<storm::dd::DdType Type, typename ValueType> - boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryRelationExpression const& expression) { - storm::dd::Add<Type, ValueType> leftResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getFirstOperand()->accept(*this)); - storm::dd::Add<Type, ValueType> rightResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getSecondOperand()->accept(*this)); + boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) { + storm::dd::Add<Type, ValueType> leftResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getFirstOperand()->accept(*this, data)); + storm::dd::Add<Type, ValueType> rightResult = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getSecondOperand()->accept(*this, data)); storm::dd::Bdd<Type> result; switch (expression.getRelationType()) { @@ -139,7 +139,7 @@ namespace storm { } template<storm::dd::DdType Type, typename ValueType> - boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::VariableExpression const& expression) { + boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::VariableExpression const& expression, boost::any const& data) { auto const& variablePair = variableMapping->find(expression.getVariable()); STORM_LOG_THROW(variablePair != variableMapping->end(), storm::exceptions::InvalidArgumentException, "Cannot translate the given expression, because it contains the variable '" << expression.getVariableName() << "' for which no DD counterpart is known."); if (expression.hasBooleanType()) { @@ -150,8 +150,8 @@ namespace storm { } template<storm::dd::DdType Type, typename ValueType> - boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression) { - storm::dd::Bdd<Type> result = boost::any_cast<storm::dd::Bdd<Type>>(expression.getOperand()->accept(*this)); + boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) { + storm::dd::Bdd<Type> result = boost::any_cast<storm::dd::Bdd<Type>>(expression.getOperand()->accept(*this, data)); switch (expression.getOperatorType()) { case storm::expressions::UnaryBooleanFunctionExpression::OperatorType::Not: @@ -163,8 +163,8 @@ namespace storm { } template<storm::dd::DdType Type, typename ValueType> - boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression) { - storm::dd::Add<Type, ValueType> result = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getOperand()->accept(*this)); + boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) { + storm::dd::Add<Type, ValueType> result = boost::any_cast<storm::dd::Add<Type, ValueType>>(expression.getOperand()->accept(*this, data)); switch (expression.getOperatorType()) { case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Minus: @@ -184,17 +184,17 @@ namespace storm { } template<storm::dd::DdType Type, typename ValueType> - boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BooleanLiteralExpression const& expression) { + boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data) { return expression.getValue() ? ddManager->getBddOne() : ddManager->getBddZero(); } template<storm::dd::DdType Type, typename ValueType> - boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::IntegerLiteralExpression const& expression) { + boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) { return ddManager->getConstant(static_cast<ValueType>(expression.getValue())); } template<storm::dd::DdType Type, typename ValueType> - boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::RationalLiteralExpression const& expression) { + boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) { return ddManager->getConstant(static_cast<ValueType>(expression.getValueAsDouble())); } diff --git a/src/adapters/AddExpressionAdapter.h b/src/adapters/AddExpressionAdapter.h index dfb13a315..cac29156f 100644 --- a/src/adapters/AddExpressionAdapter.h +++ b/src/adapters/AddExpressionAdapter.h @@ -22,16 +22,16 @@ namespace storm { storm::dd::Add<Type, ValueType> translateExpression(storm::expressions::Expression const& expression); storm::dd::Bdd<Type> translateBooleanExpression(storm::expressions::Expression const& expression); - virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression) override; - virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression) override; - virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression) override; - virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression) override; - virtual boost::any visit(storm::expressions::VariableExpression const& expression) override; - virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression) override; - virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression) override; - virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression) override; - virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression) override; - virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression) override; + virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override; + virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override; + virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override; + virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) override; private: // The manager responsible for the DDs built by this adapter. diff --git a/src/adapters/MathsatExpressionAdapter.h b/src/adapters/MathsatExpressionAdapter.h index 77b39cc68..8fad6a8af 100644 --- a/src/adapters/MathsatExpressionAdapter.h +++ b/src/adapters/MathsatExpressionAdapter.h @@ -57,7 +57,7 @@ namespace storm { * @return An equivalent term for MathSAT. */ msat_term translateExpression(storm::expressions::Expression const& expression) { - msat_term result = boost::any_cast<msat_term>(expression.getBaseExpression().accept(*this)); + msat_term result = boost::any_cast<msat_term>(expression.getBaseExpression().accept(*this, boost::none)); STORM_LOG_THROW(!MSAT_ERROR_TERM(result), storm::exceptions::ExpressionEvaluationException, "Could not translate expression to MathSAT's format."); return result; } @@ -90,9 +90,9 @@ namespace storm { return declarationVariablePair->second; } - virtual boost::any visit(expressions::BinaryBooleanFunctionExpression const& expression) override { - msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this)); - msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this)); + virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override { + msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this, data)); + msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data)); switch (expression.getOperatorType()) { case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::And: @@ -108,9 +108,9 @@ namespace storm { } } - virtual boost::any visit(expressions::BinaryNumericalFunctionExpression const& expression) override { - msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this)); - msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this)); + virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override { + msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this, data)); + msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data)); switch (expression.getOperatorType()) { case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Plus: @@ -130,9 +130,9 @@ namespace storm { } } - virtual boost::any visit(expressions::BinaryRelationExpression const& expression) override { - msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this)); - msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this)); + virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override { + msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this, data)); + msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data)); switch (expression.getRelationType()) { case storm::expressions::BinaryRelationExpression::RelationType::Equal: @@ -160,27 +160,27 @@ namespace storm { } } - virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression) override { - msat_term conditionResult = boost::any_cast<msat_term>(expression.getCondition()->accept(*this)); - msat_term thenResult = boost::any_cast<msat_term>(expression.getThenExpression()->accept(*this)); - msat_term elseResult = boost::any_cast<msat_term>(expression.getElseExpression()->accept(*this)); + virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override { + msat_term conditionResult = boost::any_cast<msat_term>(expression.getCondition()->accept(*this, data)); + msat_term thenResult = boost::any_cast<msat_term>(expression.getThenExpression()->accept(*this, data)); + msat_term elseResult = boost::any_cast<msat_term>(expression.getElseExpression()->accept(*this, data)); return msat_make_term_ite(env, conditionResult, thenResult, elseResult); } - virtual boost::any visit(expressions::BooleanLiteralExpression const& expression) override { + virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data) override { return expression.getValue() ? msat_make_true(env) : msat_make_false(env); } - virtual boost::any visit(expressions::RationalLiteralExpression const& expression) override { + virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) override { return msat_make_number(env, std::to_string(expression.getValueAsDouble()).c_str()); } - virtual boost::any visit(expressions::IntegerLiteralExpression const& expression) override { + virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) override { return msat_make_number(env, std::to_string(static_cast<int>(expression.getValue())).c_str()); } - virtual boost::any visit(expressions::UnaryBooleanFunctionExpression const& expression) override { - msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this)); + virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override { + msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this, data)); switch (expression.getOperatorType()) { case storm::expressions::UnaryBooleanFunctionExpression::OperatorType::Not: @@ -191,8 +191,8 @@ namespace storm { } } - virtual boost::any visit(expressions::UnaryNumericalFunctionExpression const& expression) override { - msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this)); + virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override { + msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this, data)); switch (expression.getOperatorType()) { case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Minus: @@ -209,7 +209,7 @@ namespace storm { } } - virtual boost::any visit(expressions::VariableExpression const& expression) override { + virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override { return translateExpression(expression.getVariable()); } diff --git a/src/adapters/Z3ExpressionAdapter.cpp b/src/adapters/Z3ExpressionAdapter.cpp index a80355422..8258f42f5 100644 --- a/src/adapters/Z3ExpressionAdapter.cpp +++ b/src/adapters/Z3ExpressionAdapter.cpp @@ -16,7 +16,7 @@ namespace storm { z3::expr Z3ExpressionAdapter::translateExpression(storm::expressions::Expression const& expression) { STORM_LOG_ASSERT(expression.getManager() == this->manager, "Invalid expression for solver."); - z3::expr result = boost::any_cast<z3::expr>(expression.getBaseExpression().accept(*this)); + z3::expr result = boost::any_cast<z3::expr>(expression.getBaseExpression().accept(*this, boost::none)); for (z3::expr const& assertion : additionalAssertions) { result = result && assertion; @@ -139,9 +139,9 @@ namespace storm { } } - boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression) { - z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this)); - z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this)); + boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) { + z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this, data)); + z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this, data)); switch(expression.getOperatorType()) { case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::And: @@ -160,9 +160,9 @@ namespace storm { } - boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression) { - z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this)); - z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this)); + boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) { + z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this, data)); + z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this, data)); switch(expression.getOperatorType()) { case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Plus: @@ -184,9 +184,9 @@ namespace storm { } } - boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryRelationExpression const& expression) { - z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this)); - z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this)); + boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) { + z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this, data)); + z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this, data)); switch(expression.getRelationType()) { case storm::expressions::BinaryRelationExpression::RelationType::Equal: @@ -206,22 +206,22 @@ namespace storm { } } - boost::any Z3ExpressionAdapter::visit(storm::expressions::BooleanLiteralExpression const& expression) { + boost::any Z3ExpressionAdapter::visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data) { return context.bool_val(expression.getValue()); } - boost::any Z3ExpressionAdapter::visit(storm::expressions::RationalLiteralExpression const& expression) { + boost::any Z3ExpressionAdapter::visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) { std::stringstream fractionStream; fractionStream << expression.getValue(); return context.real_val(fractionStream.str().c_str()); } - boost::any Z3ExpressionAdapter::visit(storm::expressions::IntegerLiteralExpression const& expression) { + boost::any Z3ExpressionAdapter::visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) { return context.int_val(static_cast<int>(expression.getValue())); } - boost::any Z3ExpressionAdapter::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression) { - z3::expr childResult = boost::any_cast<z3::expr>(expression.getOperand()->accept(*this)); + boost::any Z3ExpressionAdapter::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) { + z3::expr childResult = boost::any_cast<z3::expr>(expression.getOperand()->accept(*this, data)); switch (expression.getOperatorType()) { case storm::expressions::UnaryBooleanFunctionExpression::OperatorType::Not: @@ -231,8 +231,8 @@ namespace storm { } } - boost::any Z3ExpressionAdapter::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression) { - z3::expr childResult = boost::any_cast<z3::expr>(expression.getOperand()->accept(*this)); + boost::any Z3ExpressionAdapter::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) { + z3::expr childResult = boost::any_cast<z3::expr>(expression.getOperand()->accept(*this, data)); switch(expression.getOperatorType()) { case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Minus: @@ -253,14 +253,14 @@ namespace storm { } } - boost::any Z3ExpressionAdapter::visit(storm::expressions::IfThenElseExpression const& expression) { - z3::expr conditionResult = boost::any_cast<z3::expr>(expression.getCondition()->accept(*this)); - z3::expr thenResult = boost::any_cast<z3::expr>(expression.getThenExpression()->accept(*this)); - z3::expr elseResult = boost::any_cast<z3::expr>(expression.getElseExpression()->accept(*this)); + boost::any Z3ExpressionAdapter::visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) { + z3::expr conditionResult = boost::any_cast<z3::expr>(expression.getCondition()->accept(*this, data)); + z3::expr thenResult = boost::any_cast<z3::expr>(expression.getThenExpression()->accept(*this, data)); + z3::expr elseResult = boost::any_cast<z3::expr>(expression.getElseExpression()->accept(*this, data)); return z3::expr(context, Z3_mk_ite(context, conditionResult, thenResult, elseResult)); } - boost::any Z3ExpressionAdapter::visit(storm::expressions::VariableExpression const& expression) { + boost::any Z3ExpressionAdapter::visit(storm::expressions::VariableExpression const& expression, boost::any const& data) { return this->translateExpression(expression.getVariable()); } diff --git a/src/adapters/Z3ExpressionAdapter.h b/src/adapters/Z3ExpressionAdapter.h index 2735f5713..70cfac18b 100644 --- a/src/adapters/Z3ExpressionAdapter.h +++ b/src/adapters/Z3ExpressionAdapter.h @@ -55,25 +55,25 @@ namespace storm { */ storm::expressions::Variable const& getVariable(z3::func_decl z3Declaration); - virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression) override; + virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override; - virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression) override; + virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override; - virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression) override; + virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override; - virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression) override; + virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data) override; - virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression) override; + virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) override; - virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression) override; + virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) override; - virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression) override; + virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override; - virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression) override; + virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override; - virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression) override; + virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override; - virtual boost::any visit(storm::expressions::VariableExpression const& expression) override; + virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override; private: /*! diff --git a/src/storage/expressions/BaseExpression.cpp b/src/storage/expressions/BaseExpression.cpp index 9d44215d0..d37b61e50 100644 --- a/src/storage/expressions/BaseExpression.cpp +++ b/src/storage/expressions/BaseExpression.cpp @@ -4,6 +4,8 @@ #include "src/exceptions/InvalidTypeException.h" #include "src/exceptions/InvalidAccessException.h" +#include "src/storage/expressions/Expressions.h" + namespace storm { namespace expressions { BaseExpression::BaseExpression(ExpressionManager const& manager, Type const& type) : manager(manager), type(type) { @@ -94,6 +96,86 @@ namespace storm { return this->shared_from_this(); } + bool BaseExpression::isIfThenElseExpression() const { + return false; + } + + IfThenElseExpression const& BaseExpression::asIfThenElseExpression() const { + return static_cast<IfThenElseExpression const&>(*this); + } + + bool BaseExpression::isBinaryBooleanFunctionExpression() const { + return false; + } + + BinaryBooleanFunctionExpression const& BaseExpression::asBinaryBooleanFunctionExpression() const { + return static_cast<BinaryBooleanFunctionExpression const&>(*this); + } + + bool BaseExpression::isBinaryNumericalFunctionExpression() const { + return false; + } + + BinaryNumericalFunctionExpression const& BaseExpression::asBinaryNumericalFunctionExpression() const { + return static_cast<BinaryNumericalFunctionExpression const&>(*this); + } + + bool BaseExpression::isBinaryRelationExpression() const { + return false; + } + + BinaryRelationExpression const& BaseExpression::asBinaryRelationExpression() const { + return static_cast<BinaryRelationExpression const&>(*this); + } + + bool BaseExpression::isBooleanLiteralExpression() const { + return false; + } + + BooleanLiteralExpression const& BaseExpression::asBooleanLiteralExpression() const { + return static_cast<BooleanLiteralExpression const&>(*this); + } + + bool BaseExpression::isIntegerLiteralExpression() const { + return false; + } + + IntegerLiteralExpression const& BaseExpression::asIntegerLiteralExpression() const { + return static_cast<IntegerLiteralExpression const&>(*this); + } + + bool BaseExpression::isRationalLiteralExpression() const { + return false; + } + + RationalLiteralExpression const& BaseExpression::asRationalLiteralExpression() const { + return static_cast<RationalLiteralExpression const&>(*this); + } + + bool BaseExpression::isUnaryBooleanFunctionExpression() const { + return false; + } + + UnaryBooleanFunctionExpression const& BaseExpression::asUnaryBooleanFunctionExpression() const { + return static_cast<UnaryBooleanFunctionExpression const&>(*this); + } + + bool BaseExpression::isUnaryNumericalFunctionExpression() const { + return false; + } + + UnaryNumericalFunctionExpression const& BaseExpression::asUnaryNumericalFunctionExpression() const { + return static_cast<UnaryNumericalFunctionExpression const&>(*this); + } + + bool BaseExpression::isVariableExpression() const { + return false; + } + + VariableExpression const& BaseExpression::asVariableExpression() const { + return static_cast<VariableExpression const&>(*this); + } + std::ostream& operator<<(std::ostream& stream, BaseExpression const& expression) { expression.printToStream(stream); return stream; diff --git a/src/storage/expressions/BaseExpression.h b/src/storage/expressions/BaseExpression.h index f9b2792f4..7b5b2d973 100644 --- a/src/storage/expressions/BaseExpression.h +++ b/src/storage/expressions/BaseExpression.h @@ -13,12 +13,24 @@ namespace storm { namespace expressions { - // Forward-declare expression manager. + // Forward-declare expression classes. class ExpressionManager; class Variable; class Valuation; class ExpressionVisitor; enum struct OperatorType; + + class IfThenElseExpression; + class BinaryBooleanFunctionExpression; + class BinaryNumericalFunctionExpression; + class BinaryRelationExpression; + class BooleanLiteralExpression; + class IntegerLiteralExpression; + class RationalLiteralExpression; + class UnaryBooleanFunctionExpression; + class UnaryNumericalFunctionExpression; + class VariableExpression; + /*! * The base class of all expression classes. */ @@ -164,7 +176,7 @@ namespace storm { * * @param visitor The visitor that is to be accepted. */ - virtual boost::any accept(ExpressionVisitor& visitor) const = 0; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const = 0; /*! * Retrieves whether the expression has a numerical type, i.e., integer or double. @@ -224,6 +236,36 @@ namespace storm { friend std::ostream& operator<<(std::ostream& stream, BaseExpression const& expression); + virtual bool isIfThenElseExpression() const; + IfThenElseExpression const& asIfThenElseExpression() const; + + virtual bool isBinaryBooleanFunctionExpression() const; + BinaryBooleanFunctionExpression const& asBinaryBooleanFunctionExpression() const; + + virtual bool isBinaryNumericalFunctionExpression() const; + BinaryNumericalFunctionExpression const& asBinaryNumericalFunctionExpression() const; + + virtual bool isBinaryRelationExpression() const; + BinaryRelationExpression const& asBinaryRelationExpression() const; + + virtual bool isBooleanLiteralExpression() const; + BooleanLiteralExpression const& asBooleanLiteralExpression() const; + + virtual bool isIntegerLiteralExpression() const; + IntegerLiteralExpression const& asIntegerLiteralExpression() const; + + virtual bool isRationalLiteralExpression() const; + RationalLiteralExpression const& asRationalLiteralExpression() const; + + virtual bool isUnaryBooleanFunctionExpression() const; + UnaryBooleanFunctionExpression const& asUnaryBooleanFunctionExpression() const; + + virtual bool isUnaryNumericalFunctionExpression() const; + UnaryNumericalFunctionExpression const& asUnaryNumericalFunctionExpression() const; + + virtual bool isVariableExpression() const; + VariableExpression const& asVariableExpression() const; + protected: /*! * Prints the expression to the given stream. diff --git a/src/storage/expressions/BinaryBooleanFunctionExpression.cpp b/src/storage/expressions/BinaryBooleanFunctionExpression.cpp index 6cb550609..0b832db09 100644 --- a/src/storage/expressions/BinaryBooleanFunctionExpression.cpp +++ b/src/storage/expressions/BinaryBooleanFunctionExpression.cpp @@ -119,8 +119,8 @@ namespace storm { } } - boost::any BinaryBooleanFunctionExpression::accept(ExpressionVisitor& visitor) const { - return visitor.visit(*this); + boost::any BinaryBooleanFunctionExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + return visitor.visit(*this, data); } void BinaryBooleanFunctionExpression::printToStream(std::ostream& stream) const { diff --git a/src/storage/expressions/BinaryBooleanFunctionExpression.h b/src/storage/expressions/BinaryBooleanFunctionExpression.h index d49658c7e..27a035cca 100644 --- a/src/storage/expressions/BinaryBooleanFunctionExpression.h +++ b/src/storage/expressions/BinaryBooleanFunctionExpression.h @@ -37,7 +37,7 @@ namespace storm { virtual storm::expressions::OperatorType getOperator() const override; virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override; virtual std::shared_ptr<BaseExpression const> simplify() const override; - virtual boost::any accept(ExpressionVisitor& visitor) const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; /*! * Retrieves the operator associated with the expression. diff --git a/src/storage/expressions/BinaryNumericalFunctionExpression.cpp b/src/storage/expressions/BinaryNumericalFunctionExpression.cpp index 7c4367952..eda2d0377 100644 --- a/src/storage/expressions/BinaryNumericalFunctionExpression.cpp +++ b/src/storage/expressions/BinaryNumericalFunctionExpression.cpp @@ -113,8 +113,8 @@ namespace storm { } } - boost::any BinaryNumericalFunctionExpression::accept(ExpressionVisitor& visitor) const { - return visitor.visit(*this); + boost::any BinaryNumericalFunctionExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + return visitor.visit(*this, data); } void BinaryNumericalFunctionExpression::printToStream(std::ostream& stream) const { diff --git a/src/storage/expressions/BinaryNumericalFunctionExpression.h b/src/storage/expressions/BinaryNumericalFunctionExpression.h index e3c7d227a..1320ab56b 100644 --- a/src/storage/expressions/BinaryNumericalFunctionExpression.h +++ b/src/storage/expressions/BinaryNumericalFunctionExpression.h @@ -38,7 +38,7 @@ namespace storm { virtual int_fast64_t evaluateAsInt(Valuation const* valuation = nullptr) const override; virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override; virtual std::shared_ptr<BaseExpression const> simplify() const override; - virtual boost::any accept(ExpressionVisitor& visitor) const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; /*! * Retrieves the operator associated with the expression. diff --git a/src/storage/expressions/BinaryRelationExpression.cpp b/src/storage/expressions/BinaryRelationExpression.cpp index 858536d0c..04a8f7895 100644 --- a/src/storage/expressions/BinaryRelationExpression.cpp +++ b/src/storage/expressions/BinaryRelationExpression.cpp @@ -81,8 +81,8 @@ namespace storm { } } - boost::any BinaryRelationExpression::accept(ExpressionVisitor& visitor) const { - return visitor.visit(*this); + boost::any BinaryRelationExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + return visitor.visit(*this, data); } BinaryRelationExpression::RelationType BinaryRelationExpression::getRelationType() const { diff --git a/src/storage/expressions/BinaryRelationExpression.h b/src/storage/expressions/BinaryRelationExpression.h index 079a935a6..6dd73179c 100644 --- a/src/storage/expressions/BinaryRelationExpression.h +++ b/src/storage/expressions/BinaryRelationExpression.h @@ -37,7 +37,7 @@ namespace storm { virtual storm::expressions::OperatorType getOperator() const override; virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override; virtual std::shared_ptr<BaseExpression const> simplify() const override; - virtual boost::any accept(ExpressionVisitor& visitor) const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; /*! * Retrieves the relation associated with the expression. diff --git a/src/storage/expressions/BooleanLiteralExpression.cpp b/src/storage/expressions/BooleanLiteralExpression.cpp index 9e4986b04..086d22abd 100644 --- a/src/storage/expressions/BooleanLiteralExpression.cpp +++ b/src/storage/expressions/BooleanLiteralExpression.cpp @@ -32,8 +32,8 @@ namespace storm { return this->shared_from_this(); } - boost::any BooleanLiteralExpression::accept(ExpressionVisitor& visitor) const { - return visitor.visit(*this); + boost::any BooleanLiteralExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + return visitor.visit(*this, data); } bool BooleanLiteralExpression::getValue() const { diff --git a/src/storage/expressions/BooleanLiteralExpression.h b/src/storage/expressions/BooleanLiteralExpression.h index f5dcb78a1..cea09a295 100644 --- a/src/storage/expressions/BooleanLiteralExpression.h +++ b/src/storage/expressions/BooleanLiteralExpression.h @@ -32,7 +32,7 @@ namespace storm { virtual bool isFalse() const override; virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override; virtual std::shared_ptr<BaseExpression const> simplify() const override; - virtual boost::any accept(ExpressionVisitor& visitor) const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; /*! * Retrieves the value of the boolean literal. diff --git a/src/storage/expressions/Expression.cpp b/src/storage/expressions/Expression.cpp index 3d6094d8b..97df87d28 100644 --- a/src/storage/expressions/Expression.cpp +++ b/src/storage/expressions/Expression.cpp @@ -5,6 +5,7 @@ #include "src/storage/expressions/ExpressionManager.h" #include "src/storage/expressions/SubstitutionVisitor.h" #include "src/storage/expressions/LinearityCheckVisitor.h" +#include "src/storage/expressions/SyntacticalEqualityCheckVisitor.h" #include "src/storage/expressions/Expressions.h" #include "src/exceptions/InvalidTypeException.h" #include "src/exceptions/InvalidArgumentException.h" @@ -158,8 +159,8 @@ namespace storm { return this->getBaseExpression().hasBitVectorType(); } - boost::any Expression::accept(ExpressionVisitor& visitor) const { - return this->getBaseExpression().accept(visitor); + boost::any Expression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + return this->getBaseExpression().accept(visitor, data); } bool Expression::isInitialized() const { @@ -168,6 +169,14 @@ namespace storm { } return false; } + + bool Expression::isSyntacticallyEqual(storm::expressions::Expression const& other) const { + if (this->getBaseExpressionPointer() == other.getBaseExpressionPointer()) { + return true; + } + SyntacticalEqualityCheckVisitor checker; + return checker.isSyntaticallyEqual(*this, other); + } std::string Expression::toString() const { std::stringstream stream; diff --git a/src/storage/expressions/Expression.h b/src/storage/expressions/Expression.h index 40fcaa572..e6b3cdf8d 100644 --- a/src/storage/expressions/Expression.h +++ b/src/storage/expressions/Expression.h @@ -298,7 +298,7 @@ namespace storm { * * @param visitor The visitor to accept. */ - boost::any accept(ExpressionVisitor& visitor) const; + boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const; /*! * Converts the expression into a string. @@ -307,11 +307,16 @@ namespace storm { */ std::string toString() const; - /** + /*! * Checks whether the object encapsulates a base-expression. */ bool isInitialized() const; + /*! + * Checks whether the two expressions are syntatically the same. + */ + bool isSyntacticallyEqual(storm::expressions::Expression const& other) const; + friend std::ostream& operator<<(std::ostream& stream, Expression const& expression); private: diff --git a/src/storage/expressions/ExpressionVisitor.h b/src/storage/expressions/ExpressionVisitor.h index 1abafc2a6..cfe2ce9b6 100644 --- a/src/storage/expressions/ExpressionVisitor.h +++ b/src/storage/expressions/ExpressionVisitor.h @@ -19,16 +19,16 @@ namespace storm { class ExpressionVisitor { public: - virtual boost::any visit(IfThenElseExpression const& expression) = 0; - virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) = 0; - virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) = 0; - virtual boost::any visit(BinaryRelationExpression const& expression) = 0; - virtual boost::any visit(VariableExpression const& expression) = 0; - virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) = 0; - virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) = 0; - virtual boost::any visit(BooleanLiteralExpression const& expression) = 0; - virtual boost::any visit(IntegerLiteralExpression const& expression) = 0; - virtual boost::any visit(RationalLiteralExpression const& expression) = 0; + virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(VariableExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) = 0; }; } } diff --git a/src/storage/expressions/IfThenElseExpression.cpp b/src/storage/expressions/IfThenElseExpression.cpp index adde41a2d..8441fbeb0 100644 --- a/src/storage/expressions/IfThenElseExpression.cpp +++ b/src/storage/expressions/IfThenElseExpression.cpp @@ -88,8 +88,8 @@ namespace storm { } } - boost::any IfThenElseExpression::accept(ExpressionVisitor& visitor) const { - return visitor.visit(*this); + boost::any IfThenElseExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + return visitor.visit(*this, data); } std::shared_ptr<BaseExpression const> IfThenElseExpression::getCondition() const { diff --git a/src/storage/expressions/IfThenElseExpression.h b/src/storage/expressions/IfThenElseExpression.h index d2503116b..347feba12 100644 --- a/src/storage/expressions/IfThenElseExpression.h +++ b/src/storage/expressions/IfThenElseExpression.h @@ -38,7 +38,7 @@ namespace storm { virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override; virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override; virtual std::shared_ptr<BaseExpression const> simplify() const override; - virtual boost::any accept(ExpressionVisitor& visitor) const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; /*! * Retrieves the condition expression of the if-then-else expression. diff --git a/src/storage/expressions/IntegerLiteralExpression.cpp b/src/storage/expressions/IntegerLiteralExpression.cpp index 35ae07ee7..d8b7077b5 100644 --- a/src/storage/expressions/IntegerLiteralExpression.cpp +++ b/src/storage/expressions/IntegerLiteralExpression.cpp @@ -29,8 +29,8 @@ namespace storm { return this->shared_from_this(); } - boost::any IntegerLiteralExpression::accept(ExpressionVisitor& visitor) const { - return visitor.visit(*this); + boost::any IntegerLiteralExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + return visitor.visit(*this, data); } int_fast64_t IntegerLiteralExpression::getValue() const { diff --git a/src/storage/expressions/IntegerLiteralExpression.h b/src/storage/expressions/IntegerLiteralExpression.h index b4f732b83..3dc06e4ef 100644 --- a/src/storage/expressions/IntegerLiteralExpression.h +++ b/src/storage/expressions/IntegerLiteralExpression.h @@ -31,7 +31,7 @@ namespace storm { virtual bool isLiteral() const override; virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override; virtual std::shared_ptr<BaseExpression const> simplify() const override; - virtual boost::any accept(ExpressionVisitor& visitor) const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; /*! * Retrieves the value of the integer literal. diff --git a/src/storage/expressions/LinearCoefficientVisitor.cpp b/src/storage/expressions/LinearCoefficientVisitor.cpp index dc9a909f9..6a8701610 100644 --- a/src/storage/expressions/LinearCoefficientVisitor.cpp +++ b/src/storage/expressions/LinearCoefficientVisitor.cpp @@ -85,20 +85,20 @@ namespace storm { } LinearCoefficientVisitor::VariableCoefficients LinearCoefficientVisitor::getLinearCoefficients(Expression const& expression) { - return boost::any_cast<VariableCoefficients>(expression.getBaseExpression().accept(*this)); + return boost::any_cast<VariableCoefficients>(expression.getBaseExpression().accept(*this, boost::none)); } - boost::any LinearCoefficientVisitor::visit(IfThenElseExpression const& expression) { + boost::any LinearCoefficientVisitor::visit(IfThenElseExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear."); } - boost::any LinearCoefficientVisitor::visit(BinaryBooleanFunctionExpression const& expression) { + boost::any LinearCoefficientVisitor::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear."); } - boost::any LinearCoefficientVisitor::visit(BinaryNumericalFunctionExpression const& expression) { - VariableCoefficients leftResult = boost::any_cast<VariableCoefficients>(expression.getFirstOperand()->accept(*this)); - VariableCoefficients rightResult = boost::any_cast<VariableCoefficients>(expression.getSecondOperand()->accept(*this)); + boost::any LinearCoefficientVisitor::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) { + VariableCoefficients leftResult = boost::any_cast<VariableCoefficients>(expression.getFirstOperand()->accept(*this, data)); + VariableCoefficients rightResult = boost::any_cast<VariableCoefficients>(expression.getSecondOperand()->accept(*this, data)); if (expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Plus) { leftResult += std::move(rightResult); @@ -114,11 +114,11 @@ namespace storm { return leftResult; } - boost::any LinearCoefficientVisitor::visit(BinaryRelationExpression const& expression) { + boost::any LinearCoefficientVisitor::visit(BinaryRelationExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear."); } - boost::any LinearCoefficientVisitor::visit(VariableExpression const& expression) { + boost::any LinearCoefficientVisitor::visit(VariableExpression const& expression, boost::any const& data) { VariableCoefficients coefficients; if (expression.getType().isNumericalType()) { coefficients.setCoefficient(expression.getVariable(), 1); @@ -128,12 +128,12 @@ namespace storm { return coefficients; } - boost::any LinearCoefficientVisitor::visit(UnaryBooleanFunctionExpression const& expression) { + boost::any LinearCoefficientVisitor::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear."); } - boost::any LinearCoefficientVisitor::visit(UnaryNumericalFunctionExpression const& expression) { - VariableCoefficients childResult = boost::any_cast<VariableCoefficients>(expression.getOperand()->accept(*this)); + boost::any LinearCoefficientVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) { + VariableCoefficients childResult = boost::any_cast<VariableCoefficients>(expression.getOperand()->accept(*this, data)); if (expression.getOperatorType() == UnaryNumericalFunctionExpression::OperatorType::Minus) { childResult.negate(); @@ -143,15 +143,15 @@ namespace storm { } } - boost::any LinearCoefficientVisitor::visit(BooleanLiteralExpression const& expression) { + boost::any LinearCoefficientVisitor::visit(BooleanLiteralExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear."); } - boost::any LinearCoefficientVisitor::visit(IntegerLiteralExpression const& expression) { + boost::any LinearCoefficientVisitor::visit(IntegerLiteralExpression const& expression, boost::any const& data) { return VariableCoefficients(static_cast<double>(expression.getValue())); } - boost::any LinearCoefficientVisitor::visit(RationalLiteralExpression const& expression) { + boost::any LinearCoefficientVisitor::visit(RationalLiteralExpression const& expression, boost::any const& data) { return VariableCoefficients(expression.getValueAsDouble()); } } diff --git a/src/storage/expressions/LinearCoefficientVisitor.h b/src/storage/expressions/LinearCoefficientVisitor.h index dea1bfc2e..b0c85a800 100644 --- a/src/storage/expressions/LinearCoefficientVisitor.h +++ b/src/storage/expressions/LinearCoefficientVisitor.h @@ -66,16 +66,16 @@ namespace storm { */ VariableCoefficients getLinearCoefficients(Expression const& expression); - virtual boost::any visit(IfThenElseExpression const& expression) override; - virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override; - virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override; - virtual boost::any visit(BinaryRelationExpression const& expression) override; - virtual boost::any visit(VariableExpression const& expression) override; - virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override; - virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; - virtual boost::any visit(BooleanLiteralExpression const& expression) override; - virtual boost::any visit(IntegerLiteralExpression const& expression) override; - virtual boost::any visit(RationalLiteralExpression const& expression) override; + virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override; + virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override; }; } } diff --git a/src/storage/expressions/LinearityCheckVisitor.cpp b/src/storage/expressions/LinearityCheckVisitor.cpp index 7a33a501a..b762f9cf1 100644 --- a/src/storage/expressions/LinearityCheckVisitor.cpp +++ b/src/storage/expressions/LinearityCheckVisitor.cpp @@ -12,27 +12,27 @@ namespace storm { } bool LinearityCheckVisitor::check(Expression const& expression) { - LinearityStatus result = boost::any_cast<LinearityStatus>(expression.getBaseExpression().accept(*this)); + LinearityStatus result = boost::any_cast<LinearityStatus>(expression.getBaseExpression().accept(*this, boost::none)); return result == LinearityStatus::LinearWithoutVariables || result == LinearityStatus::LinearContainsVariables; } - boost::any LinearityCheckVisitor::visit(IfThenElseExpression const& expression) { + boost::any LinearityCheckVisitor::visit(IfThenElseExpression const& expression, boost::any const& data) { // An if-then-else expression is never linear. return LinearityStatus::NonLinear; } - boost::any LinearityCheckVisitor::visit(BinaryBooleanFunctionExpression const& expression) { + boost::any LinearityCheckVisitor::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) { // Boolean function applications are not allowed in linear expressions. return LinearityStatus::NonLinear; } - boost::any LinearityCheckVisitor::visit(BinaryNumericalFunctionExpression const& expression) { - LinearityStatus leftResult = boost::any_cast<LinearityStatus>(expression.getFirstOperand()->accept(*this)); + boost::any LinearityCheckVisitor::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) { + LinearityStatus leftResult = boost::any_cast<LinearityStatus>(expression.getFirstOperand()->accept(*this, data)); if (leftResult == LinearityStatus::NonLinear) { return LinearityStatus::NonLinear; } - LinearityStatus rightResult = boost::any_cast<LinearityStatus>(expression.getSecondOperand()->accept(*this)); + LinearityStatus rightResult = boost::any_cast<LinearityStatus>(expression.getSecondOperand()->accept(*this, data)); if (rightResult == LinearityStatus::NonLinear) { return LinearityStatus::NonLinear; } @@ -55,37 +55,37 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Illegal binary numerical expression operator."); } - boost::any LinearityCheckVisitor::visit(BinaryRelationExpression const& expression) { + boost::any LinearityCheckVisitor::visit(BinaryRelationExpression const& expression, boost::any const& data) { return LinearityStatus::NonLinear; } - boost::any LinearityCheckVisitor::visit(VariableExpression const& expression) { + boost::any LinearityCheckVisitor::visit(VariableExpression const& expression, boost::any const& data) { return LinearityStatus::LinearContainsVariables; } - boost::any LinearityCheckVisitor::visit(UnaryBooleanFunctionExpression const& expression) { + boost::any LinearityCheckVisitor::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) { // Boolean function applications are not allowed in linear expressions. return LinearityStatus::NonLinear; } - boost::any LinearityCheckVisitor::visit(UnaryNumericalFunctionExpression const& expression) { + boost::any LinearityCheckVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) { switch (expression.getOperatorType()) { - case UnaryNumericalFunctionExpression::OperatorType::Minus: return expression.getOperand()->accept(*this); + case UnaryNumericalFunctionExpression::OperatorType::Minus: return expression.getOperand()->accept(*this, data); case UnaryNumericalFunctionExpression::OperatorType::Floor: case UnaryNumericalFunctionExpression::OperatorType::Ceil: return LinearityStatus::NonLinear; } STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Illegal unary numerical expression operator."); } - boost::any LinearityCheckVisitor::visit(BooleanLiteralExpression const& expression) { + boost::any LinearityCheckVisitor::visit(BooleanLiteralExpression const& expression, boost::any const& data) { return LinearityStatus::NonLinear; } - boost::any LinearityCheckVisitor::visit(IntegerLiteralExpression const& expression) { + boost::any LinearityCheckVisitor::visit(IntegerLiteralExpression const& expression, boost::any const& data) { return LinearityStatus::LinearWithoutVariables; } - boost::any LinearityCheckVisitor::visit(RationalLiteralExpression const& expression) { + boost::any LinearityCheckVisitor::visit(RationalLiteralExpression const& expression, boost::any const& data) { return LinearityStatus::LinearWithoutVariables; } } diff --git a/src/storage/expressions/LinearityCheckVisitor.h b/src/storage/expressions/LinearityCheckVisitor.h index 6bb35b7e8..b2a465871 100644 --- a/src/storage/expressions/LinearityCheckVisitor.h +++ b/src/storage/expressions/LinearityCheckVisitor.h @@ -20,16 +20,16 @@ namespace storm { */ bool check(Expression const& expression); - virtual boost::any visit(IfThenElseExpression const& expression) override; - virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override; - virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override; - virtual boost::any visit(BinaryRelationExpression const& expression) override; - virtual boost::any visit(VariableExpression const& expression) override; - virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override; - virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; - virtual boost::any visit(BooleanLiteralExpression const& expression) override; - virtual boost::any visit(IntegerLiteralExpression const& expression) override; - virtual boost::any visit(RationalLiteralExpression const& expression) override; + virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override; + virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override; private: enum class LinearityStatus { NonLinear, LinearContainsVariables, LinearWithoutVariables }; diff --git a/src/storage/expressions/RationalLiteralExpression.cpp b/src/storage/expressions/RationalLiteralExpression.cpp index 3fa226a8a..6c6ee88ff 100644 --- a/src/storage/expressions/RationalLiteralExpression.cpp +++ b/src/storage/expressions/RationalLiteralExpression.cpp @@ -34,8 +34,8 @@ namespace storm { return this->shared_from_this(); } - boost::any RationalLiteralExpression::accept(ExpressionVisitor& visitor) const { - return visitor.visit(*this); + boost::any RationalLiteralExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + return visitor.visit(*this, data); } double RationalLiteralExpression::getValueAsDouble() const { diff --git a/src/storage/expressions/RationalLiteralExpression.h b/src/storage/expressions/RationalLiteralExpression.h index 4eff900b2..e18cf8c43 100644 --- a/src/storage/expressions/RationalLiteralExpression.h +++ b/src/storage/expressions/RationalLiteralExpression.h @@ -48,7 +48,7 @@ namespace storm { virtual bool isLiteral() const override; virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override; virtual std::shared_ptr<BaseExpression const> simplify() const override; - virtual boost::any accept(ExpressionVisitor& visitor) const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; /*! * Retrieves the value of the double literal. diff --git a/src/storage/expressions/SubstitutionVisitor.cpp b/src/storage/expressions/SubstitutionVisitor.cpp index 1490e6f59..c2b4ff419 100644 --- a/src/storage/expressions/SubstitutionVisitor.cpp +++ b/src/storage/expressions/SubstitutionVisitor.cpp @@ -14,14 +14,14 @@ namespace storm { template<typename MapType> Expression SubstitutionVisitor<MapType>::substitute(Expression const& expression) { - return Expression(boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getBaseExpression().accept(*this))); + return Expression(boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getBaseExpression().accept(*this, boost::none))); } template<typename MapType> - boost::any SubstitutionVisitor<MapType>::visit(IfThenElseExpression const& expression) { - std::shared_ptr<BaseExpression const> conditionExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getCondition()->accept(*this)); - std::shared_ptr<BaseExpression const> thenExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getThenExpression()->accept(*this)); - std::shared_ptr<BaseExpression const> elseExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getElseExpression()->accept(*this)); + boost::any SubstitutionVisitor<MapType>::visit(IfThenElseExpression const& expression, boost::any const& data) { + std::shared_ptr<BaseExpression const> conditionExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getCondition()->accept(*this, data)); + std::shared_ptr<BaseExpression const> thenExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getThenExpression()->accept(*this, data)); + std::shared_ptr<BaseExpression const> elseExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getElseExpression()->accept(*this, data)); // If the arguments did not change, we simply push the expression itself. if (conditionExpression.get() == expression.getCondition().get() && thenExpression.get() == expression.getThenExpression().get() && elseExpression.get() == expression.getElseExpression().get()) { @@ -32,9 +32,9 @@ namespace storm { } template<typename MapType> - boost::any SubstitutionVisitor<MapType>::visit(BinaryBooleanFunctionExpression const& expression) { - std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this)); - std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this)); + boost::any SubstitutionVisitor<MapType>::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) { + std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this, data)); + std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this, data)); // If the arguments did not change, we simply push the expression itself. if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { @@ -45,9 +45,9 @@ namespace storm { } template<typename MapType> - boost::any SubstitutionVisitor<MapType>::visit(BinaryNumericalFunctionExpression const& expression) { - std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this)); - std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this)); + boost::any SubstitutionVisitor<MapType>::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) { + std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this, data)); + std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this, data)); // If the arguments did not change, we simply push the expression itself. if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { @@ -58,9 +58,9 @@ namespace storm { } template<typename MapType> - boost::any SubstitutionVisitor<MapType>::visit(BinaryRelationExpression const& expression) { - std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this)); - std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this)); + boost::any SubstitutionVisitor<MapType>::visit(BinaryRelationExpression const& expression, boost::any const& data) { + std::shared_ptr<BaseExpression const> firstExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getFirstOperand()->accept(*this, data)); + std::shared_ptr<BaseExpression const> secondExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getSecondOperand()->accept(*this, data)); // If the arguments did not change, we simply push the expression itself. if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { @@ -71,7 +71,7 @@ namespace storm { } template<typename MapType> - boost::any SubstitutionVisitor<MapType>::visit(VariableExpression const& expression) { + boost::any SubstitutionVisitor<MapType>::visit(VariableExpression const& expression, boost::any const& data) { // If the variable is in the key set of the substitution, we need to replace it. auto const& nameExpressionPair = this->variableToExpressionMapping.find(expression.getVariable()); if (nameExpressionPair != this->variableToExpressionMapping.end()) { @@ -82,8 +82,8 @@ namespace storm { } template<typename MapType> - boost::any SubstitutionVisitor<MapType>::visit(UnaryBooleanFunctionExpression const& expression) { - std::shared_ptr<BaseExpression const> operandExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getOperand()->accept(*this)); + boost::any SubstitutionVisitor<MapType>::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) { + std::shared_ptr<BaseExpression const> operandExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getOperand()->accept(*this, data)); // If the argument did not change, we simply push the expression itself. if (operandExpression.get() == expression.getOperand().get()) { @@ -94,8 +94,8 @@ namespace storm { } template<typename MapType> - boost::any SubstitutionVisitor<MapType>::visit(UnaryNumericalFunctionExpression const& expression) { - std::shared_ptr<BaseExpression const> operandExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getOperand()->accept(*this)); + boost::any SubstitutionVisitor<MapType>::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) { + std::shared_ptr<BaseExpression const> operandExpression = boost::any_cast<std::shared_ptr<BaseExpression const>>(expression.getOperand()->accept(*this, data)); // If the argument did not change, we simply push the expression itself. if (operandExpression.get() == expression.getOperand().get()) { @@ -106,17 +106,17 @@ namespace storm { } template<typename MapType> - boost::any SubstitutionVisitor<MapType>::visit(BooleanLiteralExpression const& expression) { + boost::any SubstitutionVisitor<MapType>::visit(BooleanLiteralExpression const& expression, boost::any const& data) { return expression.getSharedPointer(); } template<typename MapType> - boost::any SubstitutionVisitor<MapType>::visit(IntegerLiteralExpression const& expression) { + boost::any SubstitutionVisitor<MapType>::visit(IntegerLiteralExpression const& expression, boost::any const& data) { return expression.getSharedPointer(); } template<typename MapType> - boost::any SubstitutionVisitor<MapType>::visit(RationalLiteralExpression const& expression) { + boost::any SubstitutionVisitor<MapType>::visit(RationalLiteralExpression const& expression, boost::any const& data) { return expression.getSharedPointer(); } diff --git a/src/storage/expressions/SubstitutionVisitor.h b/src/storage/expressions/SubstitutionVisitor.h index 5f1a93cb2..2131696c4 100644 --- a/src/storage/expressions/SubstitutionVisitor.h +++ b/src/storage/expressions/SubstitutionVisitor.h @@ -28,16 +28,16 @@ namespace storm { */ Expression substitute(Expression const& expression); - virtual boost::any visit(IfThenElseExpression const& expression) override; - virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override; - virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override; - virtual boost::any visit(BinaryRelationExpression const& expression) override; - virtual boost::any visit(VariableExpression const& expression) override; - virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override; - virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; - virtual boost::any visit(BooleanLiteralExpression const& expression) override; - virtual boost::any visit(IntegerLiteralExpression const& expression) override; - virtual boost::any visit(RationalLiteralExpression const& expression) override; + virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override; + virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override; private: // A mapping of variables to expressions with which they shall be replaced. diff --git a/src/storage/expressions/SyntacticalEqualityCheckVisitor.cpp b/src/storage/expressions/SyntacticalEqualityCheckVisitor.cpp new file mode 100644 index 000000000..4277a7dbb --- /dev/null +++ b/src/storage/expressions/SyntacticalEqualityCheckVisitor.cpp @@ -0,0 +1,155 @@ +#include "src/storage/expressions/SyntacticalEqualityCheckVisitor.h" + +#include "src/storage/expressions/Expressions.h" + +namespace storm { + namespace expressions { + + bool SyntacticalEqualityCheckVisitor::isSyntaticallyEqual(storm::expressions::Expression const& expression1, storm::expressions::Expression const& expression2) { + return boost::any_cast<bool>(expression1.accept(*this, std::ref(expression2.getBaseExpression()))); + } + + boost::any SyntacticalEqualityCheckVisitor::visit(IfThenElseExpression const& expression, boost::any const& data) { + BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get(); + if (otherBaseExpression.isIfThenElseExpression()) { + IfThenElseExpression const& otherExpression = otherBaseExpression.asIfThenElseExpression(); + + bool result = boost::any_cast<bool>(expression.getCondition()->accept(*this, std::ref(*otherExpression.getCondition()))); + if (result) { + result = boost::any_cast<bool>(expression.getThenExpression()->accept(*this, std::ref(*otherExpression.getThenExpression()))); + } + if (result) { + result = boost::any_cast<bool>(expression.getElseExpression()->accept(*this, std::ref(*otherExpression.getElseExpression()))); + } + return result; + } else { + return false; + } + } + + boost::any SyntacticalEqualityCheckVisitor::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) { + BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get(); + if (otherBaseExpression.isBinaryBooleanFunctionExpression()) { + BinaryBooleanFunctionExpression const& otherExpression = otherBaseExpression.asBinaryBooleanFunctionExpression(); + + bool result = expression.getOperatorType() == otherExpression.getOperatorType(); + if (result) { + result = boost::any_cast<bool>(expression.getFirstOperand()->accept(*this, std::ref(*otherExpression.getFirstOperand()))); + } + if (result) { + result = boost::any_cast<bool>(expression.getSecondOperand()->accept(*this, std::ref(*otherExpression.getSecondOperand()))); + } + return result; + } else { + return false; + } + } + + boost::any SyntacticalEqualityCheckVisitor::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) { + BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get(); + if (otherBaseExpression.isBinaryNumericalFunctionExpression()) { + BinaryNumericalFunctionExpression const& otherExpression = otherBaseExpression.asBinaryNumericalFunctionExpression(); + + bool result = expression.getOperatorType() == otherExpression.getOperatorType(); + if (result) { + result = boost::any_cast<bool>(expression.getFirstOperand()->accept(*this, std::ref(*otherExpression.getFirstOperand()))); + } + if (result) { + result = boost::any_cast<bool>(expression.getSecondOperand()->accept(*this, std::ref(*otherExpression.getSecondOperand()))); + } + return result; + } else { + return false; + } + } + + boost::any SyntacticalEqualityCheckVisitor::visit(BinaryRelationExpression const& expression, boost::any const& data) { + BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get(); + if (otherBaseExpression.isBinaryRelationExpression()) { + BinaryRelationExpression const& otherExpression = otherBaseExpression.asBinaryRelationExpression(); + + bool result = expression.getRelationType() == otherExpression.getRelationType(); + if (result) { + result = boost::any_cast<bool>(expression.getFirstOperand()->accept(*this, std::ref(*otherExpression.getFirstOperand()))); + } + if (result) { + result = boost::any_cast<bool>(expression.getSecondOperand()->accept(*this, std::ref(*otherExpression.getSecondOperand()))); + } + return result; + } else { + return false; + } + } + + boost::any SyntacticalEqualityCheckVisitor::visit(VariableExpression const& expression, boost::any const& data) { + BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get(); + if (otherBaseExpression.isVariableExpression()) { + VariableExpression const& otherExpression = otherBaseExpression.asVariableExpression(); + return expression.getVariable() == otherExpression.getVariable(); + } else { + return false; + } + } + + boost::any SyntacticalEqualityCheckVisitor::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) { + BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get(); + if (otherBaseExpression.isBinaryBooleanFunctionExpression()) { + UnaryBooleanFunctionExpression const& otherExpression = otherBaseExpression.asUnaryBooleanFunctionExpression(); + + bool result = expression.getOperatorType() == otherExpression.getOperatorType(); + if (result) { + result = boost::any_cast<bool>(expression.getOperand()->accept(*this, std::ref(*otherExpression.getOperand()))); + } + return result; + } else { + return false; + } + } + + boost::any SyntacticalEqualityCheckVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) { + BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get(); + if (otherBaseExpression.isBinaryBooleanFunctionExpression()) { + UnaryNumericalFunctionExpression const& otherExpression = otherBaseExpression.asUnaryNumericalFunctionExpression(); + + bool result = expression.getOperatorType() == otherExpression.getOperatorType(); + if (result) { + result = boost::any_cast<bool>(expression.getOperand()->accept(*this, std::ref(*otherExpression.getOperand()))); + } + return result; + } else { + return false; + } + } + + boost::any SyntacticalEqualityCheckVisitor::visit(BooleanLiteralExpression const& expression, boost::any const& data) { + BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get(); + if (otherBaseExpression.isBooleanLiteralExpression()) { + BooleanLiteralExpression const& otherExpression = otherBaseExpression.asBooleanLiteralExpression(); + return expression.getValue() == otherExpression.getValue(); + } else { + return false; + } + } + + boost::any SyntacticalEqualityCheckVisitor::visit(IntegerLiteralExpression const& expression, boost::any const& data) { + BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get(); + if (otherBaseExpression.isIntegerLiteralExpression()) { + IntegerLiteralExpression const& otherExpression = otherBaseExpression.asIntegerLiteralExpression(); + return expression.getValue() == otherExpression.getValue(); + } else { + return false; + } + } + + boost::any SyntacticalEqualityCheckVisitor::visit(RationalLiteralExpression const& expression, boost::any const& data) { + BaseExpression const& otherBaseExpression = boost::any_cast<std::reference_wrapper<BaseExpression const>>(data).get(); + if (otherBaseExpression.isRationalLiteralExpression()) { + RationalLiteralExpression const& otherExpression = otherBaseExpression.asRationalLiteralExpression(); + return expression.getValue() == otherExpression.getValue(); + } else { + return false; + } + } + + } +} \ No newline at end of file diff --git a/src/storage/expressions/SyntacticalEqualityCheckVisitor.h b/src/storage/expressions/SyntacticalEqualityCheckVisitor.h new file mode 100644 index 000000000..82366e507 --- /dev/null +++ b/src/storage/expressions/SyntacticalEqualityCheckVisitor.h @@ -0,0 +1,27 @@ +#pragma once + +#include "src/storage/expressions/ExpressionVisitor.h" + +namespace storm { + namespace expressions { + + class Expression; + + class SyntacticalEqualityCheckVisitor : public ExpressionVisitor { + public: + bool isSyntaticallyEqual(storm::expressions::Expression const& expression1, storm::expressions::Expression const& expression2); + + virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override; + virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override; + }; + + } +} \ No newline at end of file diff --git a/src/storage/expressions/ToExprtkStringVisitor.cpp b/src/storage/expressions/ToExprtkStringVisitor.cpp index 1492aeae5..88ab1132a 100644 --- a/src/storage/expressions/ToExprtkStringVisitor.cpp +++ b/src/storage/expressions/ToExprtkStringVisitor.cpp @@ -9,210 +9,210 @@ namespace storm { std::string ToExprtkStringVisitor::toString(BaseExpression const* expression) { stream.str(""); stream.clear(); - expression->accept(*this); + expression->accept(*this, boost::none); return stream.str(); } - boost::any ToExprtkStringVisitor::visit(IfThenElseExpression const& expression) { + boost::any ToExprtkStringVisitor::visit(IfThenElseExpression const& expression, boost::any const& data) { stream << "if("; - expression.getCondition()->accept(*this); + expression.getCondition()->accept(*this, data); stream << ","; - expression.getThenExpression()->accept(*this); + expression.getThenExpression()->accept(*this, data); stream << ","; - expression.getElseExpression()->accept(*this); + expression.getElseExpression()->accept(*this, data); stream << ")"; return boost::any(); } - boost::any ToExprtkStringVisitor::visit(BinaryBooleanFunctionExpression const& expression) { + boost::any ToExprtkStringVisitor::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) { switch (expression.getOperatorType()) { case BinaryBooleanFunctionExpression::OperatorType::And: stream << "("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << " and "; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryBooleanFunctionExpression::OperatorType::Or: stream << "("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << " or "; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryBooleanFunctionExpression::OperatorType::Xor: stream << "("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << " xor "; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryBooleanFunctionExpression::OperatorType::Implies: stream << "(not("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << ") or "; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryBooleanFunctionExpression::OperatorType::Iff: - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << "=="; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); break; } return boost::any(); } - boost::any ToExprtkStringVisitor::visit(BinaryNumericalFunctionExpression const& expression) { + boost::any ToExprtkStringVisitor::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) { switch (expression.getOperatorType()) { case BinaryNumericalFunctionExpression::OperatorType::Plus: stream << "("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << "+"; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryNumericalFunctionExpression::OperatorType::Minus: stream << "("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << "-"; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryNumericalFunctionExpression::OperatorType::Times: stream << "("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << "*"; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryNumericalFunctionExpression::OperatorType::Divide: stream << "("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << "/"; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryNumericalFunctionExpression::OperatorType::Power: stream << "("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << "^"; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryNumericalFunctionExpression::OperatorType::Max: stream << "max("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << ","; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryNumericalFunctionExpression::OperatorType::Min: stream << "min("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << ","; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; } return boost::any(); } - boost::any ToExprtkStringVisitor::visit(BinaryRelationExpression const& expression) { + boost::any ToExprtkStringVisitor::visit(BinaryRelationExpression const& expression, boost::any const& data) { switch (expression.getRelationType()) { case BinaryRelationExpression::RelationType::Equal: stream << "("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << "=="; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryRelationExpression::RelationType::NotEqual: stream << "("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << "!="; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryRelationExpression::RelationType::Less: stream << "("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << "<"; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryRelationExpression::RelationType::LessOrEqual: stream << "("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << "<="; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryRelationExpression::RelationType::Greater: stream << "("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << ">"; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; case BinaryRelationExpression::RelationType::GreaterOrEqual: stream << "("; - expression.getFirstOperand()->accept(*this); + expression.getFirstOperand()->accept(*this, data); stream << ">="; - expression.getSecondOperand()->accept(*this); + expression.getSecondOperand()->accept(*this, data); stream << ")"; break; } return boost::any(); } - boost::any ToExprtkStringVisitor::visit(VariableExpression const& expression) { + boost::any ToExprtkStringVisitor::visit(VariableExpression const& expression, boost::any const& data) { stream << expression.getVariableName(); return boost::any(); } - boost::any ToExprtkStringVisitor::visit(UnaryBooleanFunctionExpression const& expression) { + boost::any ToExprtkStringVisitor::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) { switch (expression.getOperatorType()) { case UnaryBooleanFunctionExpression::OperatorType::Not: stream << "not("; - expression.getOperand()->accept(*this); + expression.getOperand()->accept(*this, data); stream << ")"; } return boost::any(); } - boost::any ToExprtkStringVisitor::visit(UnaryNumericalFunctionExpression const& expression) { + boost::any ToExprtkStringVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) { switch (expression.getOperatorType()) { case UnaryNumericalFunctionExpression::OperatorType::Minus: stream << "-("; - expression.getOperand()->accept(*this); + expression.getOperand()->accept(*this, data); stream << ")"; break; case UnaryNumericalFunctionExpression::OperatorType::Floor: stream << "floor("; - expression.getOperand()->accept(*this); + expression.getOperand()->accept(*this, data); stream << ")"; break; case UnaryNumericalFunctionExpression::OperatorType::Ceil: stream << "ceil("; - expression.getOperand()->accept(*this); + expression.getOperand()->accept(*this, data); stream << ")"; break; } return boost::any(); } - boost::any ToExprtkStringVisitor::visit(BooleanLiteralExpression const& expression) { + boost::any ToExprtkStringVisitor::visit(BooleanLiteralExpression const& expression, boost::any const& data) { stream << expression.getValue(); return boost::any(); } - boost::any ToExprtkStringVisitor::visit(IntegerLiteralExpression const& expression) { + boost::any ToExprtkStringVisitor::visit(IntegerLiteralExpression const& expression, boost::any const& data) { stream << expression.getValue(); return boost::any(); } - boost::any ToExprtkStringVisitor::visit(RationalLiteralExpression const& expression) { + boost::any ToExprtkStringVisitor::visit(RationalLiteralExpression const& expression, boost::any const& data) { stream << expression.getValue(); return boost::any(); } diff --git a/src/storage/expressions/ToExprtkStringVisitor.h b/src/storage/expressions/ToExprtkStringVisitor.h index d68da589d..efab0a176 100644 --- a/src/storage/expressions/ToExprtkStringVisitor.h +++ b/src/storage/expressions/ToExprtkStringVisitor.h @@ -16,16 +16,16 @@ namespace storm { std::string toString(Expression const& expression); std::string toString(BaseExpression const* expression); - virtual boost::any visit(IfThenElseExpression const& expression) override; - virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override; - virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override; - virtual boost::any visit(BinaryRelationExpression const& expression) override; - virtual boost::any visit(VariableExpression const& expression) override; - virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override; - virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; - virtual boost::any visit(BooleanLiteralExpression const& expression) override; - virtual boost::any visit(IntegerLiteralExpression const& expression) override; - virtual boost::any visit(RationalLiteralExpression const& expression) override; + virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override; + virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override; private: std::stringstream stream; diff --git a/src/storage/expressions/ToRationalFunctionVisitor.cpp b/src/storage/expressions/ToRationalFunctionVisitor.cpp index a219066e4..91a3cdc94 100644 --- a/src/storage/expressions/ToRationalFunctionVisitor.cpp +++ b/src/storage/expressions/ToRationalFunctionVisitor.cpp @@ -17,23 +17,23 @@ namespace storm { template<typename RationalFunctionType> RationalFunctionType ToRationalFunctionVisitor<RationalFunctionType>::toRationalFunction(Expression const& expression) { - return boost::any_cast<RationalFunctionType>(expression.accept(*this)); + return boost::any_cast<RationalFunctionType>(expression.accept(*this, boost::none)); } template<typename RationalFunctionType> - boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(IfThenElseExpression const& expression) { + boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(IfThenElseExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function."); } template<typename RationalFunctionType> - boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryBooleanFunctionExpression const& expression) { + boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function."); } template<typename RationalFunctionType> - boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryNumericalFunctionExpression const& expression) { - RationalFunctionType firstOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getFirstOperand()->accept(*this)); - RationalFunctionType secondOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getSecondOperand()->accept(*this)); + boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) { + RationalFunctionType firstOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getFirstOperand()->accept(*this, data)); + RationalFunctionType secondOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getSecondOperand()->accept(*this, data)); uint_fast64_t exponentAsInteger = 0; switch(expression.getOperatorType()) { case BinaryNumericalFunctionExpression::OperatorType::Plus: @@ -62,12 +62,12 @@ namespace storm { } template<typename RationalFunctionType> - boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryRelationExpression const& expression) { + boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryRelationExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function."); } template<typename RationalFunctionType> - boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(VariableExpression const& expression) { + boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(VariableExpression const& expression, boost::any const& data) { auto variablePair = variableToVariableMap.find(expression.getVariable()); if (variablePair != variableToVariableMap.end()) { return convertVariableToPolynomial(variablePair->second); @@ -79,27 +79,27 @@ namespace storm { } template<typename RationalFunctionType> - boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(UnaryBooleanFunctionExpression const& expression) { + boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function."); } template<typename RationalFunctionType> - boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(UnaryNumericalFunctionExpression const& expression) { + boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function."); } template<typename RationalFunctionType> - boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BooleanLiteralExpression const& expression) { + boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BooleanLiteralExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function."); } template<typename RationalFunctionType> - boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(IntegerLiteralExpression const& expression) { + boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(IntegerLiteralExpression const& expression, boost::any const& data) { return RationalFunctionType(carl::rationalize<storm::RationalNumber>(static_cast<size_t>(expression.getValue()))); } template<typename RationalFunctionType> - boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(RationalLiteralExpression const& expression) { + boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(RationalLiteralExpression const& expression, boost::any const& data) { return storm::utility::convertNumber<storm::RationalFunction>(expression.getValue()); } diff --git a/src/storage/expressions/ToRationalFunctionVisitor.h b/src/storage/expressions/ToRationalFunctionVisitor.h index 1cda5028f..0a30d7793 100644 --- a/src/storage/expressions/ToRationalFunctionVisitor.h +++ b/src/storage/expressions/ToRationalFunctionVisitor.h @@ -18,16 +18,16 @@ namespace storm { RationalFunctionType toRationalFunction(Expression const& expression); - virtual boost::any visit(IfThenElseExpression const& expression) override; - virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override; - virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override; - virtual boost::any visit(BinaryRelationExpression const& expression) override; - virtual boost::any visit(VariableExpression const& expression) override; - virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override; - virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; - virtual boost::any visit(BooleanLiteralExpression const& expression) override; - virtual boost::any visit(IntegerLiteralExpression const& expression) override; - virtual boost::any visit(RationalLiteralExpression const& expression) override; + virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override; + virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override; private: template<typename TP = typename RationalFunctionType::PolyType, carl::EnableIf<carl::needs_cache<TP>> = carl::dummy> diff --git a/src/storage/expressions/ToRationalNumberVisitor.cpp b/src/storage/expressions/ToRationalNumberVisitor.cpp index 1b7319927..cfe2cbb35 100644 --- a/src/storage/expressions/ToRationalNumberVisitor.cpp +++ b/src/storage/expressions/ToRationalNumberVisitor.cpp @@ -14,23 +14,23 @@ namespace storm { template<typename RationalNumberType> RationalNumberType ToRationalNumberVisitor<RationalNumberType>::toRationalNumber(Expression const& expression) { - return boost::any_cast<RationalNumberType>(expression.accept(*this)); + return boost::any_cast<RationalNumberType>(expression.accept(*this, boost::none)); } template<typename RationalNumberType> - boost::any ToRationalNumberVisitor<RationalNumberType>::visit(IfThenElseExpression const& expression) { + boost::any ToRationalNumberVisitor<RationalNumberType>::visit(IfThenElseExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number."); } template<typename RationalNumberType> - boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryBooleanFunctionExpression const& expression) { + boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number."); } template<typename RationalNumberType> - boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryNumericalFunctionExpression const& expression) { - RationalNumberType firstOperandAsRationalNumber = boost::any_cast<RationalNumberType>(expression.getFirstOperand()->accept(*this)); - RationalNumberType secondOperandAsRationalNumber = boost::any_cast<RationalNumberType>(expression.getSecondOperand()->accept(*this)); + boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) { + RationalNumberType firstOperandAsRationalNumber = boost::any_cast<RationalNumberType>(expression.getFirstOperand()->accept(*this, data)); + RationalNumberType secondOperandAsRationalNumber = boost::any_cast<RationalNumberType>(expression.getSecondOperand()->accept(*this, data)); switch(expression.getOperatorType()) { case BinaryNumericalFunctionExpression::OperatorType::Plus: return firstOperandAsRationalNumber + secondOperandAsRationalNumber; @@ -63,32 +63,32 @@ namespace storm { } template<typename RationalNumberType> - boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryRelationExpression const& expression) { + boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryRelationExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number."); } template<typename RationalNumberType> - boost::any ToRationalNumberVisitor<RationalNumberType>::visit(VariableExpression const& expression) { + boost::any ToRationalNumberVisitor<RationalNumberType>::visit(VariableExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot transform expressions containing variables to a rational number."); } template<typename RationalNumberType> - boost::any ToRationalNumberVisitor<RationalNumberType>::visit(UnaryBooleanFunctionExpression const& expression) { + boost::any ToRationalNumberVisitor<RationalNumberType>::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number."); } template<typename RationalNumberType> - boost::any ToRationalNumberVisitor<RationalNumberType>::visit(UnaryNumericalFunctionExpression const& expression) { + boost::any ToRationalNumberVisitor<RationalNumberType>::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number."); } template<typename RationalNumberType> - boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BooleanLiteralExpression const& expression) { + boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BooleanLiteralExpression const& expression, boost::any const& data) { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number."); } template<typename RationalNumberType> - boost::any ToRationalNumberVisitor<RationalNumberType>::visit(IntegerLiteralExpression const& expression) { + boost::any ToRationalNumberVisitor<RationalNumberType>::visit(IntegerLiteralExpression const& expression, boost::any const& data) { #ifdef STORM_HAVE_CARL return RationalNumberType(carl::rationalize<storm::RationalNumber>(static_cast<size_t>(expression.getValue()))); #else @@ -97,7 +97,7 @@ namespace storm { } template<typename RationalNumberType> - boost::any ToRationalNumberVisitor<RationalNumberType>::visit(RationalLiteralExpression const& expression) { + boost::any ToRationalNumberVisitor<RationalNumberType>::visit(RationalLiteralExpression const& expression, boost::any const& data) { #ifdef STORM_HAVE_CARL return expression.getValue(); #else diff --git a/src/storage/expressions/ToRationalNumberVisitor.h b/src/storage/expressions/ToRationalNumberVisitor.h index 3d53b8a87..da803cf23 100644 --- a/src/storage/expressions/ToRationalNumberVisitor.h +++ b/src/storage/expressions/ToRationalNumberVisitor.h @@ -16,16 +16,16 @@ namespace storm { RationalNumberType toRationalNumber(Expression const& expression); - virtual boost::any visit(IfThenElseExpression const& expression) override; - virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) override; - virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) override; - virtual boost::any visit(BinaryRelationExpression const& expression) override; - virtual boost::any visit(VariableExpression const& expression) override; - virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) override; - virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) override; - virtual boost::any visit(BooleanLiteralExpression const& expression) override; - virtual boost::any visit(IntegerLiteralExpression const& expression) override; - virtual boost::any visit(RationalLiteralExpression const& expression) override; + virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override; + virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override; }; } } diff --git a/src/storage/expressions/UnaryBooleanFunctionExpression.cpp b/src/storage/expressions/UnaryBooleanFunctionExpression.cpp index 7c45e081d..825d3debc 100644 --- a/src/storage/expressions/UnaryBooleanFunctionExpression.cpp +++ b/src/storage/expressions/UnaryBooleanFunctionExpression.cpp @@ -49,8 +49,8 @@ namespace storm { } } - boost::any UnaryBooleanFunctionExpression::accept(ExpressionVisitor& visitor) const { - return visitor.visit(*this); + boost::any UnaryBooleanFunctionExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + return visitor.visit(*this, data); } void UnaryBooleanFunctionExpression::printToStream(std::ostream& stream) const { diff --git a/src/storage/expressions/UnaryBooleanFunctionExpression.h b/src/storage/expressions/UnaryBooleanFunctionExpression.h index d13761c26..1f1974fa1 100644 --- a/src/storage/expressions/UnaryBooleanFunctionExpression.h +++ b/src/storage/expressions/UnaryBooleanFunctionExpression.h @@ -36,7 +36,7 @@ namespace storm { virtual storm::expressions::OperatorType getOperator() const override; virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override; virtual std::shared_ptr<BaseExpression const> simplify() const override; - virtual boost::any accept(ExpressionVisitor& visitor) const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; /*! * Retrieves the operator associated with this expression. diff --git a/src/storage/expressions/UnaryNumericalFunctionExpression.cpp b/src/storage/expressions/UnaryNumericalFunctionExpression.cpp index f5178fb6f..988b17a12 100644 --- a/src/storage/expressions/UnaryNumericalFunctionExpression.cpp +++ b/src/storage/expressions/UnaryNumericalFunctionExpression.cpp @@ -98,8 +98,8 @@ namespace storm { } } - boost::any UnaryNumericalFunctionExpression::accept(ExpressionVisitor& visitor) const { - return visitor.visit(*this); + boost::any UnaryNumericalFunctionExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + return visitor.visit(*this, data); } void UnaryNumericalFunctionExpression::printToStream(std::ostream& stream) const { diff --git a/src/storage/expressions/UnaryNumericalFunctionExpression.h b/src/storage/expressions/UnaryNumericalFunctionExpression.h index f9e2ab148..38d29d142 100644 --- a/src/storage/expressions/UnaryNumericalFunctionExpression.h +++ b/src/storage/expressions/UnaryNumericalFunctionExpression.h @@ -37,7 +37,7 @@ namespace storm { virtual int_fast64_t evaluateAsInt(Valuation const* valuation = nullptr) const override; virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override; virtual std::shared_ptr<BaseExpression const> simplify() const override; - virtual boost::any accept(ExpressionVisitor& visitor) const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; /*! * Retrieves the operator associated with this expression. diff --git a/src/storage/expressions/VariableExpression.cpp b/src/storage/expressions/VariableExpression.cpp index 8ac6cb8b2..a3fe0ae38 100644 --- a/src/storage/expressions/VariableExpression.cpp +++ b/src/storage/expressions/VariableExpression.cpp @@ -63,8 +63,8 @@ namespace storm { return this->shared_from_this(); } - boost::any VariableExpression::accept(ExpressionVisitor& visitor) const { - return visitor.visit(*this); + boost::any VariableExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + return visitor.visit(*this, data); } void VariableExpression::printToStream(std::ostream& stream) const { diff --git a/src/storage/expressions/VariableExpression.h b/src/storage/expressions/VariableExpression.h index cfc65fd31..f1f5bca16 100644 --- a/src/storage/expressions/VariableExpression.h +++ b/src/storage/expressions/VariableExpression.h @@ -35,7 +35,7 @@ namespace storm { virtual bool isVariable() const override; virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override; virtual std::shared_ptr<BaseExpression const> simplify() const override; - virtual boost::any accept(ExpressionVisitor& visitor) const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; /*! * Retrieves the name of the variable associated with this expression. diff --git a/src/storage/jani/Assignment.cpp b/src/storage/jani/Assignment.cpp index 469446729..7c97d367c 100644 --- a/src/storage/jani/Assignment.cpp +++ b/src/storage/jani/Assignment.cpp @@ -7,6 +7,10 @@ namespace storm { // Intentionally left empty. } + bool Assignment::operator==(Assignment const& other) const { + return this->getExpressionVariable() == other.getExpressionVariable() && this->getAssignedExpression().isSyntacticallyEqual(other.getAssignedExpression()); + } + storm::jani::Variable const& Assignment::getVariable() const { return variable.get(); } diff --git a/src/storage/jani/Assignment.h b/src/storage/jani/Assignment.h index e4b562863..dbdfb7edd 100644 --- a/src/storage/jani/Assignment.h +++ b/src/storage/jani/Assignment.h @@ -15,6 +15,8 @@ namespace storm { */ Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression); + bool operator==(Assignment const& other) const; + /*! * Retrieves the expression variable that is written in this assignment. */ diff --git a/src/storage/jani/Edge.cpp b/src/storage/jani/Edge.cpp index 347140b1b..40f64e537 100644 --- a/src/storage/jani/Edge.cpp +++ b/src/storage/jani/Edge.cpp @@ -59,6 +59,14 @@ namespace storm { } } + void Edge::addTransientAssignment(Assignment const& assignment) { + transientAssignments.push_back(assignment); + } + + void Edge::liftTransientDestinationAssignments() { + + } + boost::container::flat_set<storm::expressions::Variable> const& Edge::getWrittenGlobalVariables() const { return writtenGlobalVariables; } diff --git a/src/storage/jani/Edge.h b/src/storage/jani/Edge.h index cb872ebbe..f56685984 100644 --- a/src/storage/jani/Edge.h +++ b/src/storage/jani/Edge.h @@ -76,6 +76,19 @@ namespace storm { */ boost::container::flat_set<storm::expressions::Variable> const& getWrittenGlobalVariables() const; + /*! + * Adds a transient assignment to this edge. + * + * @param assignment The transient assignment to add. + */ + void addTransientAssignment(Assignment const& assignment); + + /*! + * Finds the transient assignments common to all destinations and lifts them to the edge. Afterwards, these + * assignments are no longer contained in the destination. + */ + void liftTransientDestinationAssignments(); + private: /// The index of the source location. uint64_t sourceLocationIndex; @@ -93,6 +106,9 @@ namespace storm { /// The destinations of this edge. std::vector<EdgeDestination> destinations; + /// The transient assignments made when taking this edge. + std::vector<Assignment> transientAssignments; + /// A set of global variables that is written by at least one of the edge's destinations. This set is /// initialized by the call to <code>finalize</code>. boost::container::flat_set<storm::expressions::Variable> writtenGlobalVariables; From 9a5d11a5e0a32972883236bdbdbba84f6f91d9f9 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Tue, 6 Sep 2016 17:01:09 +0200 Subject: [PATCH 22/34] adding real variables to JANI models. started to encapsulate PRISM to JANI converter Former-commit-id: a7892b3d23a78908349c15977ae6945bd2c3ed4c [formerly 411e830ca5053819b0b81a65bc772c069d597fea] Former-commit-id: 49ee7034936d1b9d68e4ab65e1f92d7066591750 --- src/storage/jani/Assignment.cpp | 2 +- src/storage/jani/Automaton.cpp | 24 ++-- src/storage/jani/Automaton.h | 11 +- src/storage/jani/Edge.cpp | 23 +++- src/storage/jani/EdgeDestination.cpp | 32 +++++ src/storage/jani/EdgeDestination.h | 21 +++ src/storage/jani/Model.cpp | 24 ++-- src/storage/jani/Model.h | 11 +- src/storage/jani/RealVariable.cpp | 19 +++ src/storage/jani/RealVariable.h | 25 ++++ src/storage/jani/Variable.cpp | 25 +++- src/storage/jani/Variable.h | 4 + src/storage/jani/VariableSet.cpp | 28 +++- src/storage/jani/VariableSet.h | 30 ++++- src/storage/prism/Program.cpp | 173 +----------------------- src/storage/prism/Program.h | 12 +- src/storage/prism/ToJaniConverter.cpp | 187 ++++++++++++++++++++++++++ src/storage/prism/ToJaniConverter.h | 20 +++ 18 files changed, 450 insertions(+), 221 deletions(-) create mode 100644 src/storage/jani/RealVariable.cpp create mode 100644 src/storage/jani/RealVariable.h create mode 100644 src/storage/prism/ToJaniConverter.cpp create mode 100644 src/storage/prism/ToJaniConverter.h diff --git a/src/storage/jani/Assignment.cpp b/src/storage/jani/Assignment.cpp index 7c97d367c..cea0b9eec 100644 --- a/src/storage/jani/Assignment.cpp +++ b/src/storage/jani/Assignment.cpp @@ -8,7 +8,7 @@ namespace storm { } bool Assignment::operator==(Assignment const& other) const { - return this->getExpressionVariable() == other.getExpressionVariable() && this->getAssignedExpression().isSyntacticallyEqual(other.getAssignedExpression()); + return this->isTransientAssignment() == other.isTransientAssignment() && this->getExpressionVariable() == other.getExpressionVariable() && this->getAssignedExpression().isSyntacticallyEqual(other.getAssignedExpression()); } storm::jani::Variable const& Assignment::getVariable() const { diff --git a/src/storage/jani/Automaton.cpp b/src/storage/jani/Automaton.cpp index c6d8600e3..9227a4c5b 100644 --- a/src/storage/jani/Automaton.cpp +++ b/src/storage/jani/Automaton.cpp @@ -61,26 +61,32 @@ namespace storm { Variable const& Automaton::addVariable(Variable const &variable) { if (variable.isBooleanVariable()) { - return addBooleanVariable(variable.asBooleanVariable()); + return addVariable(variable.asBooleanVariable()); } else if (variable.isBoundedIntegerVariable()) { - return addBoundedIntegerVariable(variable.asBoundedIntegerVariable()); + return addVariable(variable.asBoundedIntegerVariable()); } else if (variable.isUnboundedIntegerVariable()) { - return addUnboundedIntegerVariable(variable.asUnboundedIntegerVariable()); + return addVariable(variable.asUnboundedIntegerVariable()); + } else if (variable.isRealVariable()) { + return addVariable(variable.asRealVariable()); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Variable has invalid type."); } } - BooleanVariable const& Automaton::addBooleanVariable(BooleanVariable const& variable) { - return variables.addBooleanVariable(variable); + BooleanVariable const& Automaton::addVariable(BooleanVariable const& variable) { + return variables.addVariable(variable); } - BoundedIntegerVariable const& Automaton::addBoundedIntegerVariable(BoundedIntegerVariable const& variable) { - return variables.addBoundedIntegerVariable(variable); + BoundedIntegerVariable const& Automaton::addVariable(BoundedIntegerVariable const& variable) { + return variables.addVariable(variable); } - UnboundedIntegerVariable const& Automaton::addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable) { - return variables.addUnboundedIntegerVariable(variable); + UnboundedIntegerVariable const& Automaton::addVariable(UnboundedIntegerVariable const& variable) { + return variables.addVariable(variable); + } + + RealVariable const& Automaton::addVariable(RealVariable const& variable) { + return variables.addVariable(variable); } VariableSet& Automaton::getVariables() { diff --git a/src/storage/jani/Automaton.h b/src/storage/jani/Automaton.h index 1a2ad61dc..e46fc44be 100644 --- a/src/storage/jani/Automaton.h +++ b/src/storage/jani/Automaton.h @@ -108,17 +108,22 @@ namespace storm { /*! * Adds the given Boolean variable to this automaton. */ - BooleanVariable const& addBooleanVariable(BooleanVariable const& variable); + BooleanVariable const& addVariable(BooleanVariable const& variable); /*! * Adds the given bounded integer variable to this automaton. */ - BoundedIntegerVariable const& addBoundedIntegerVariable(BoundedIntegerVariable const& variable); + BoundedIntegerVariable const& addVariable(BoundedIntegerVariable const& variable); /*! * Adds the given unbounded integer variable to this automaton. */ - UnboundedIntegerVariable const& addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable); + UnboundedIntegerVariable const& addVariable(UnboundedIntegerVariable const& variable); + + /*! + * Adds the given real variable to this automaton. + */ + RealVariable const& addVariable(RealVariable const& variable); /*! * Retrieves the variables of this automaton. diff --git a/src/storage/jani/Edge.cpp b/src/storage/jani/Edge.cpp index 40f64e537..430838b61 100644 --- a/src/storage/jani/Edge.cpp +++ b/src/storage/jani/Edge.cpp @@ -64,7 +64,28 @@ namespace storm { } void Edge::liftTransientDestinationAssignments() { - + if (!destinations.empty()) { + auto const& destination = *destinations.begin(); + + for (auto const& assignment : destination.getTransientAssignments()) { + // Check if we can lift the assignment to the edge. + bool canBeLifted = true; + for (auto const& destination : destinations) { + if (!destination.hasAssignment(assignment)) { + canBeLifted = false; + break; + } + } + + // If so, remove the assignment from all destinations. + if (canBeLifted) { + this->addTransientAssignment(assignment); + for (auto& destination : destinations) { + destination.removeAssignment(assignment); + } + } + } + } } boost::container::flat_set<storm::expressions::Variable> const& Edge::getWrittenGlobalVariables() const { diff --git a/src/storage/jani/EdgeDestination.cpp b/src/storage/jani/EdgeDestination.cpp index c58a157e9..f49b15eac 100644 --- a/src/storage/jani/EdgeDestination.cpp +++ b/src/storage/jani/EdgeDestination.cpp @@ -72,6 +72,28 @@ namespace storm { return transientAssignments; } + bool EdgeDestination::hasAssignment(Assignment const& assignment) const { + for (auto const& containedAssignment : assignments) { + if (containedAssignment == assignment) { + return true; + } + } + return false; + } + + bool EdgeDestination::removeAssignment(Assignment const& assignment) { + bool toRemove = removeAssignment(assignment, assignments); + if (toRemove) { + if (assignment.isTransientAssignment()) { + removeAssignment(assignment, transientAssignments); + } else { + removeAssignment(assignment, nonTransientAssignments); + } + return true; + } + return false; + } + void EdgeDestination::sortAssignments(std::vector<Assignment>& assignments) { std::sort(assignments.begin(), assignments.end(), [] (storm::jani::Assignment const& assignment1, storm::jani::Assignment const& assignment2) { bool smaller = assignment1.getExpressionVariable().getType().isBooleanType() && !assignment2.getExpressionVariable().getType().isBooleanType(); @@ -82,5 +104,15 @@ namespace storm { }); } + bool EdgeDestination::removeAssignment(Assignment const& assignment, std::vector<Assignment>& assignments) { + for (auto it = assignments.begin(), ite = assignments.end(); it != ite; ++it) { + if (assignment == *it) { + assignments.erase(it); + return true; + } + } + return false; + } + } } \ No newline at end of file diff --git a/src/storage/jani/EdgeDestination.h b/src/storage/jani/EdgeDestination.h index d22e09ab3..9d3f8326d 100644 --- a/src/storage/jani/EdgeDestination.h +++ b/src/storage/jani/EdgeDestination.h @@ -66,6 +66,20 @@ namespace storm { */ std::vector<Assignment> const& getTransientAssignments() const; + /*! + * Retrieves whether this assignment is made when choosing this destination. + * + * @return True iff the assignment is made. + */ + bool hasAssignment(Assignment const& assignment) const; + + /*! + * Removes the given assignment from this destination. + * + * @return True if the assignment was found and removed. + */ + bool removeAssignment(Assignment const& assignment); + private: /*! * Sorts the assignments to make all assignments to boolean variables precede all others and order the @@ -73,6 +87,13 @@ namespace storm { */ static void sortAssignments(std::vector<Assignment>& assignments); + /*! + * Removes the given assignment from the provided list of assignments if found. + * + * @return True if the assignment was removed. + */ + static bool removeAssignment(Assignment const& assignment, std::vector<Assignment>& assignments); + // The index of the destination location. uint64_t locationIndex; diff --git a/src/storage/jani/Model.cpp b/src/storage/jani/Model.cpp index a9fb3f25e..08a243c06 100644 --- a/src/storage/jani/Model.cpp +++ b/src/storage/jani/Model.cpp @@ -107,26 +107,32 @@ namespace storm { Variable const& Model::addVariable(Variable const& variable) { if (variable.isBooleanVariable()) { - return addBooleanVariable(variable.asBooleanVariable()); + return addVariable(variable.asBooleanVariable()); } else if (variable.isBoundedIntegerVariable()) { - return addBoundedIntegerVariable(variable.asBoundedIntegerVariable()); + return addVariable(variable.asBoundedIntegerVariable()); } else if (variable.isUnboundedIntegerVariable()) { - return addUnboundedIntegerVariable(variable.asUnboundedIntegerVariable()); + return addVariable(variable.asUnboundedIntegerVariable()); + } else if (variable.isRealVariable()) { + return addVariable(variable.asRealVariable()); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Variable has invalid type."); } } - BooleanVariable const& Model::addBooleanVariable(BooleanVariable const& variable) { - return globalVariables.addBooleanVariable(variable); + BooleanVariable const& Model::addVariable(BooleanVariable const& variable) { + return globalVariables.addVariable(variable); } - BoundedIntegerVariable const& Model::addBoundedIntegerVariable(BoundedIntegerVariable const& variable) { - return globalVariables.addBoundedIntegerVariable(variable); + BoundedIntegerVariable const& Model::addVariable(BoundedIntegerVariable const& variable) { + return globalVariables.addVariable(variable); } - UnboundedIntegerVariable const& Model::addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable) { - return globalVariables.addUnboundedIntegerVariable(variable); + UnboundedIntegerVariable const& Model::addVariable(UnboundedIntegerVariable const& variable) { + return globalVariables.addVariable(variable); + } + + RealVariable const& Model::addVariable(RealVariable const& variable) { + return globalVariables.addVariable(variable); } VariableSet& Model::getGlobalVariables() { diff --git a/src/storage/jani/Model.h b/src/storage/jani/Model.h index 0379cd5dd..20ca41486 100644 --- a/src/storage/jani/Model.h +++ b/src/storage/jani/Model.h @@ -115,17 +115,22 @@ namespace storm { /*! * Adds the given boolean variable to this model. */ - BooleanVariable const& addBooleanVariable(BooleanVariable const& variable); + BooleanVariable const& addVariable(BooleanVariable const& variable); /*! * Adds the given bounded integer variable to this model. */ - BoundedIntegerVariable const& addBoundedIntegerVariable(BoundedIntegerVariable const& variable); + BoundedIntegerVariable const& addVariable(BoundedIntegerVariable const& variable); /*! * Adds the given unbounded integer variable to this model. */ - UnboundedIntegerVariable const& addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable); + UnboundedIntegerVariable const& addVariable(UnboundedIntegerVariable const& variable); + + /*! + * Adds the given real variable to this model. + */ + RealVariable const& addVariable(RealVariable const& variable); /*! * Retrieves the variables of this automaton. diff --git a/src/storage/jani/RealVariable.cpp b/src/storage/jani/RealVariable.cpp new file mode 100644 index 000000000..8880a9a0a --- /dev/null +++ b/src/storage/jani/RealVariable.cpp @@ -0,0 +1,19 @@ +#include "src/storage/jani/RealVariable.h" + +namespace storm { + namespace jani { + + RealVariable::RealVariable(std::string const& name, storm::expressions::Variable const& variable, bool transient) : storm::jani::Variable(name, variable, transient) { + // Intentionally left empty. + } + + RealVariable::RealVariable(std::string const& name, storm::expressions::Variable const& variable, storm::expressions::Expression const& initValue, bool transient) : storm::jani::Variable(name, variable, initValue, transient) { + // Intentionally left empty. + } + + bool RealVariable::isRealVariable() const { + return true; + } + + } +} \ No newline at end of file diff --git a/src/storage/jani/RealVariable.h b/src/storage/jani/RealVariable.h new file mode 100644 index 000000000..74c337ed9 --- /dev/null +++ b/src/storage/jani/RealVariable.h @@ -0,0 +1,25 @@ +#pragma once + +#include "src/storage/jani/Variable.h" + +namespace storm { + namespace jani { + + class RealVariable : public Variable { + public: + /*! + * Creates a real variable without initial value. + */ + RealVariable(std::string const& name, storm::expressions::Variable const& variable, bool transient=false); + + /*! + * Creates a real variable with initial value. + */ + RealVariable(std::string const& name, storm::expressions::Variable const& variable, storm::expressions::Expression const& initValue, bool transient=false); + + virtual bool isRealVariable() const override; + }; + + + } +} \ No newline at end of file diff --git a/src/storage/jani/Variable.cpp b/src/storage/jani/Variable.cpp index 57a9289a4..4027ea112 100644 --- a/src/storage/jani/Variable.cpp +++ b/src/storage/jani/Variable.cpp @@ -3,6 +3,7 @@ #include "src/storage/jani/BooleanVariable.h" #include "src/storage/jani/BoundedIntegerVariable.h" #include "src/storage/jani/UnboundedIntegerVariable.h" +#include "src/storage/jani/RealVariable.h" namespace storm { namespace jani { @@ -36,6 +37,10 @@ namespace storm { return false; } + bool Variable::isRealVariable() const { + return false; + } + bool Variable::isTransientVariable() const { return transient; } @@ -53,27 +58,35 @@ namespace storm { } BooleanVariable& Variable::asBooleanVariable() { - return dynamic_cast<BooleanVariable&>(*this); + return static_cast<BooleanVariable&>(*this); } BooleanVariable const& Variable::asBooleanVariable() const { - return dynamic_cast<BooleanVariable const&>(*this); + return static_cast<BooleanVariable const&>(*this); } BoundedIntegerVariable& Variable::asBoundedIntegerVariable() { - return dynamic_cast<BoundedIntegerVariable&>(*this); + return static_cast<BoundedIntegerVariable&>(*this); } BoundedIntegerVariable const& Variable::asBoundedIntegerVariable() const { - return dynamic_cast<BoundedIntegerVariable const&>(*this); + return static_cast<BoundedIntegerVariable const&>(*this); } UnboundedIntegerVariable& Variable::asUnboundedIntegerVariable() { - return dynamic_cast<UnboundedIntegerVariable&>(*this); + return static_cast<UnboundedIntegerVariable&>(*this); } UnboundedIntegerVariable const& Variable::asUnboundedIntegerVariable() const { - return dynamic_cast<UnboundedIntegerVariable const&>(*this); + return static_cast<UnboundedIntegerVariable const&>(*this); + } + + RealVariable& Variable::asRealVariable() { + return static_cast<RealVariable&>(*this); + } + + RealVariable const& Variable::asRealVariable() const { + return static_cast<RealVariable const&>(*this); } } diff --git a/src/storage/jani/Variable.h b/src/storage/jani/Variable.h index 820014b03..8d25bfd36 100644 --- a/src/storage/jani/Variable.h +++ b/src/storage/jani/Variable.h @@ -13,6 +13,7 @@ namespace storm { class BooleanVariable; class BoundedIntegerVariable; class UnboundedIntegerVariable; + class RealVariable; class Variable { public: @@ -58,6 +59,7 @@ namespace storm { virtual bool isBooleanVariable() const; virtual bool isBoundedIntegerVariable() const; virtual bool isUnboundedIntegerVariable() const; + virtual bool isRealVariable() const; virtual bool isTransientVariable() const; @@ -68,6 +70,8 @@ namespace storm { BoundedIntegerVariable const& asBoundedIntegerVariable() const; UnboundedIntegerVariable& asUnboundedIntegerVariable(); UnboundedIntegerVariable const& asUnboundedIntegerVariable() const; + RealVariable& asRealVariable(); + RealVariable const& asRealVariable() const; private: // The name of the variable. diff --git a/src/storage/jani/VariableSet.cpp b/src/storage/jani/VariableSet.cpp index fe7ef300c..27806a132 100644 --- a/src/storage/jani/VariableSet.cpp +++ b/src/storage/jani/VariableSet.cpp @@ -74,7 +74,15 @@ namespace storm { return detail::ConstVariables<UnboundedIntegerVariable>(unboundedIntegerVariables.begin(), unboundedIntegerVariables.end()); } - BooleanVariable const& VariableSet::addBooleanVariable(BooleanVariable const& variable) { + detail::Variables<RealVariable> VariableSet::getRealVariables() { + return detail::Variables<RealVariable>(realVariables.begin(), realVariables.end()); + } + + detail::ConstVariables<RealVariable> VariableSet::getRealVariables() const { + return detail::ConstVariables<RealVariable>(realVariables.begin(), realVariables.end()); + } + + BooleanVariable const& VariableSet::addVariable(BooleanVariable const& variable) { STORM_LOG_THROW(!this->hasVariable(variable.getName()), storm::exceptions::WrongFormatException, "Cannot add variable with name '" << variable.getName() << "', because a variable with that name already exists."); std::shared_ptr<BooleanVariable> newVariable = std::make_shared<BooleanVariable>(variable); variables.push_back(newVariable); @@ -84,7 +92,7 @@ namespace storm { return *newVariable; } - BoundedIntegerVariable const& VariableSet::addBoundedIntegerVariable(BoundedIntegerVariable const& variable) { + BoundedIntegerVariable const& VariableSet::addVariable(BoundedIntegerVariable const& variable) { STORM_LOG_THROW(!this->hasVariable(variable.getName()), storm::exceptions::WrongFormatException, "Cannot add variable with name '" << variable.getName() << "', because a variable with that name already exists."); std::shared_ptr<BoundedIntegerVariable> newVariable = std::make_shared<BoundedIntegerVariable>(variable); variables.push_back(newVariable); @@ -94,7 +102,7 @@ namespace storm { return *newVariable; } - UnboundedIntegerVariable const& VariableSet::addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable) { + UnboundedIntegerVariable const& VariableSet::addVariable(UnboundedIntegerVariable const& variable) { STORM_LOG_THROW(!this->hasVariable(variable.getName()), storm::exceptions::WrongFormatException, "Cannot add variable with name '" << variable.getName() << "', because a variable with that name already exists."); std::shared_ptr<UnboundedIntegerVariable> newVariable = std::make_shared<UnboundedIntegerVariable>(variable); variables.push_back(newVariable); @@ -104,6 +112,16 @@ namespace storm { return *newVariable; } + RealVariable const& VariableSet::addVariable(RealVariable const& variable) { + STORM_LOG_THROW(!this->hasVariable(variable.getName()), storm::exceptions::WrongFormatException, "Cannot add variable with name '" << variable.getName() << "', because a variable with that name already exists."); + std::shared_ptr<RealVariable> newVariable = std::make_shared<RealVariable>(variable); + variables.push_back(newVariable); + realVariables.push_back(newVariable); + nameToVariable.emplace(variable.getName(), variable.getExpressionVariable()); + variableToVariable.emplace(variable.getExpressionVariable(), newVariable); + return *newVariable; + } + bool VariableSet::hasVariable(std::string const& name) const { return nameToVariable.find(name) != nameToVariable.end(); } @@ -152,6 +170,10 @@ namespace storm { return !unboundedIntegerVariables.empty(); } + bool VariableSet::containsRealVariables() const { + return !realVariables.empty(); + } + bool VariableSet::empty() const { return !(containsBooleanVariable() || containsBoundedIntegerVariable() || containsUnboundedIntegerVariables()); } diff --git a/src/storage/jani/VariableSet.h b/src/storage/jani/VariableSet.h index 84e265ed1..651787df5 100644 --- a/src/storage/jani/VariableSet.h +++ b/src/storage/jani/VariableSet.h @@ -8,6 +8,7 @@ #include "src/storage/jani/BooleanVariable.h" #include "src/storage/jani/UnboundedIntegerVariable.h" #include "src/storage/jani/BoundedIntegerVariable.h" +#include "src/storage/jani/RealVariable.h" namespace storm { namespace jani { @@ -97,20 +98,35 @@ namespace storm { */ detail::ConstVariables<UnboundedIntegerVariable> getUnboundedIntegerVariables() const; + /*! + * Retrieves the real variables in this set. + */ + detail::Variables<RealVariable> getRealVariables(); + + /*! + * Retrieves the real variables in this set. + */ + detail::ConstVariables<RealVariable> getRealVariables() const; + /*! * Adds the given boolean variable to this set. */ - BooleanVariable const& addBooleanVariable(BooleanVariable const& variable); + BooleanVariable const& addVariable(BooleanVariable const& variable); /*! * Adds the given bounded integer variable to this set. */ - BoundedIntegerVariable const& addBoundedIntegerVariable(BoundedIntegerVariable const& variable); + BoundedIntegerVariable const& addVariable(BoundedIntegerVariable const& variable); /*! * Adds the given unbounded integer variable to this set. */ - UnboundedIntegerVariable const& addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable); + UnboundedIntegerVariable const& addVariable(UnboundedIntegerVariable const& variable); + + /*! + * Adds the given real variable to this set. + */ + RealVariable const& addVariable(RealVariable const& variable); /*! * Retrieves whether this variable set contains a variable with the given name. @@ -167,6 +183,11 @@ namespace storm { */ bool containsUnboundedIntegerVariables() const; + /*! + * Retrieves whether the set of variables contains an unbounded integer variable. + */ + bool containsRealVariables() const; + /*! * Retrieves whether this variable set is empty. */ @@ -185,6 +206,9 @@ namespace storm { /// The unbounded integer variables in this set. std::vector<std::shared_ptr<UnboundedIntegerVariable>> unboundedIntegerVariables; + /// The real variables in this set. + std::vector<std::shared_ptr<RealVariable>> realVariables; + /// A set of all variable names currently in use. std::map<std::string, storm::expressions::Variable> nameToVariable; diff --git a/src/storage/prism/Program.cpp b/src/storage/prism/Program.cpp index a836b5879..c92226c84 100644 --- a/src/storage/prism/Program.cpp +++ b/src/storage/prism/Program.cpp @@ -20,7 +20,6 @@ #include "src/storage/prism/CompositionVisitor.h" #include "src/storage/prism/Compositions.h" -#include "src/storage/prism/CompositionToJaniVisitor.h" namespace storm { namespace prism { @@ -1610,180 +1609,10 @@ namespace storm { return this->indexToActionMap.rbegin()->first; } - storm::expressions::ExpressionManager const& Program::getManager() const { + storm::expressions::ExpressionManager& Program::getManager() const { return *this->manager; } - storm::expressions::ExpressionManager& Program::getManager() { - return *this->manager; - } - - storm::jani::Model Program::toJani(bool allVariablesGlobal) const { - // Start by creating an empty JANI model. - storm::jani::ModelType modelType; - switch (this->getModelType()) { - case Program::ModelType::DTMC: modelType = storm::jani::ModelType::DTMC; - break; - case Program::ModelType::CTMC: modelType = storm::jani::ModelType::CTMC; - break; - case Program::ModelType::MDP: modelType = storm::jani::ModelType::MDP; - break; - case Program::ModelType::CTMDP: modelType = storm::jani::ModelType::CTMDP; - break; - case Program::ModelType::MA: modelType = storm::jani::ModelType::MA; - break; - default: modelType = storm::jani::ModelType::UNDEFINED; - } - storm::jani::Model janiModel("jani_from_prism", modelType, 1, manager); - - // Add all constants of the PRISM program to the JANI model. - 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)); - } - - // Maintain a mapping from expression variables to JANI variables so we can fill in the correct objects when - // creating assignments. - std::map<storm::expressions::Variable, std::reference_wrapper<storm::jani::Variable const>> variableToVariableMap; - - // Add all global variables of the PRISM program to the JANI model. - for (auto const& variable : globalIntegerVariables) { - if (variable.hasInitialValue()) { - 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) { - if (variable.hasInitialValue()) { - 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. - for (auto const& action : indexToActionMap) { - // Ignore the empty action as every JANI program has predefined tau action. - if (!action.second.empty()) { - janiModel.addAction(storm::jani::Action(action.second)); - } - } - - // 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. - std::map<storm::expressions::Variable, std::set<uint_fast64_t>> variablesToAccessingModuleIndices; - for (uint_fast64_t index = 0; index < modules.size(); ++index) { - storm::prism::Module const& module = modules[index]; - - for (auto const& command : module.getCommands()) { - std::set<storm::expressions::Variable> variables = command.getGuardExpression().getVariables(); - for (auto const& variable : variables) { - variablesToAccessingModuleIndices[variable].insert(index); - } - - for (auto const& update : command.getUpdates()) { - for (auto const& assignment : update.getAssignments()) { - variables = assignment.getExpression().getVariables(); - for (auto const& variable : variables) { - variablesToAccessingModuleIndices[variable].insert(index); - } - variablesToAccessingModuleIndices[assignment.getVariable()].insert(index); - } - } - } - } - - // Now create the separate JANI automata from the modules of the PRISM program. While doing so, we use the - // previously built mapping to make variables global that are read by more than one module. - for (auto const& module : modules) { - storm::jani::Automaton automaton(module.getName()); - for (auto const& variable : module.getIntegerVariables()) { - 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()]; - // 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) { - storm::jani::BoundedIntegerVariable const& createdVariable = automaton.addBoundedIntegerVariable(newIntegerVariable); - variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); - } else if (!accessingModuleIndices.empty()) { - // Otherwise, we need to make it global. - storm::jani::BoundedIntegerVariable const& createdVariable = janiModel.addBoundedIntegerVariable(newIntegerVariable); - variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); - } - } - for (auto const& variable : module.getBooleanVariables()) { - 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()]; - // 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) { - storm::jani::BooleanVariable const& createdVariable = automaton.addBooleanVariable(newBooleanVariable); - variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); - } else if (!accessingModuleIndices.empty()) { - // Otherwise, we need to make it global. - storm::jani::BooleanVariable const& createdVariable = janiModel.addBooleanVariable(newBooleanVariable); - variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); - } - } - automaton.setInitialStatesRestriction(manager->boolean(true)); - - // Create a single location that will have all the edges. - uint64_t onlyLocation = automaton.addLocation(storm::jani::Location("l")); - automaton.addInitialLocation(onlyLocation); - - for (auto const& command : module.getCommands()) { - boost::optional<storm::expressions::Expression> rateExpression; - std::vector<storm::jani::EdgeDestination> destinations; - if (this->getModelType() == Program::ModelType::CTMC || this->getModelType() == Program::ModelType::CTMDP) { - for (auto const& update : command.getUpdates()) { - if (rateExpression) { - rateExpression = rateExpression.get() + update.getLikelihoodExpression(); - } else { - rateExpression = update.getLikelihoodExpression(); - } - } - } - - for (auto const& update : command.getUpdates()) { - std::vector<storm::jani::Assignment> assignments; - for (auto const& assignment : update.getAssignments()) { - assignments.push_back(storm::jani::Assignment(variableToVariableMap.at(assignment.getVariable()).get(), assignment.getExpression())); - } - - if (rateExpression) { - destinations.push_back(storm::jani::EdgeDestination(onlyLocation, manager->integer(1) / rateExpression.get(), assignments)); - } else { - destinations.push_back(storm::jani::EdgeDestination(onlyLocation, update.getLikelihoodExpression(), assignments)); - } - } - automaton.addEdge(storm::jani::Edge(onlyLocation, janiModel.getActionIndex(command.getActionName()), rateExpression, command.getGuardExpression(), destinations)); - } - - janiModel.addAutomaton(automaton); - } - - 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. - if (this->specifiesSystemComposition()) { - CompositionToJaniVisitor visitor; - janiModel.setSystemComposition(visitor.toJani(this->getSystemCompositionConstruct().getSystemComposition(), janiModel)); - } else { - janiModel.setSystemComposition(janiModel.getStandardSystemComposition()); - } - - janiModel.finalize(); - - return janiModel; - } - void Program::createMissingInitialValues() { for (auto& variable : globalBooleanVariables) { if (!variable.hasInitialValue()) { diff --git a/src/storage/prism/Program.h b/src/storage/prism/Program.h index 41ef5f173..9233d5014 100644 --- a/src/storage/prism/Program.h +++ b/src/storage/prism/Program.h @@ -566,18 +566,8 @@ namespace storm { * * @return The manager responsible for the expressions of this program. */ - storm::expressions::ExpressionManager const& getManager() const; + storm::expressions::ExpressionManager& getManager() const; - /*! - * Retrieves the manager responsible for the expressions of this program. - * - * @return The manager responsible for the expressions of this program. - */ - storm::expressions::ExpressionManager& getManager(); - - /*! - * - */ std::unordered_map<uint_fast64_t, std::string> buildCommandIndexToActionNameMap() const; std::unordered_map<uint_fast64_t, uint_fast64_t> buildCommandIndexToActionIndex() const; diff --git a/src/storage/prism/ToJaniConverter.cpp b/src/storage/prism/ToJaniConverter.cpp new file mode 100644 index 000000000..c340035ee --- /dev/null +++ b/src/storage/prism/ToJaniConverter.cpp @@ -0,0 +1,187 @@ +#include "src/storage/prism/ToJaniConverter.h" + +#include "src/storage/expressions/ExpressionManager.h" + +#include "src/storage/prism/Program.h" +#include "src/storage/prism/CompositionToJaniVisitor.h" +#include "src/storage/jani/Model.h" + +namespace storm { + namespace prism { + + storm::jani::Model convert(storm::prism::Program const& program, bool allVariablesGlobal) { + std::shared_ptr<storm::expressions::ExpressionManager> manager = program.getManager().getSharedPointer(); + + // Start by creating an empty JANI model. + storm::jani::ModelType modelType; + switch (program.getModelType()) { + case Program::ModelType::DTMC: modelType = storm::jani::ModelType::DTMC; + break; + case Program::ModelType::CTMC: modelType = storm::jani::ModelType::CTMC; + break; + case Program::ModelType::MDP: modelType = storm::jani::ModelType::MDP; + break; + case Program::ModelType::CTMDP: modelType = storm::jani::ModelType::CTMDP; + break; + case Program::ModelType::MA: modelType = storm::jani::ModelType::MA; + break; + default: modelType = storm::jani::ModelType::UNDEFINED; + } + storm::jani::Model janiModel("jani_from_prism", modelType, 1, manager); + + // Add all constants of the PRISM program to the JANI model. + for (auto const& constant : program.getConstants()) { + janiModel.addConstant(storm::jani::Constant(constant.getName(), constant.getExpressionVariable(), constant.isDefined() ? boost::optional<storm::expressions::Expression>(constant.getExpression()) : boost::none)); + } + + // Maintain a mapping from expression variables to JANI variables so we can fill in the correct objects when + // creating assignments. + std::map<storm::expressions::Variable, std::reference_wrapper<storm::jani::Variable const>> variableToVariableMap; + + // Add all global variables of the PRISM program to the JANI model. + for (auto const& variable : program.getGlobalIntegerVariables()) { + if (variable.hasInitialValue()) { + storm::jani::BoundedIntegerVariable const& createdVariable = janiModel.addVariable(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.addVariable(storm::jani::BoundedIntegerVariable(variable.getName(), variable.getExpressionVariable(), false, variable.getLowerBoundExpression(), variable.getUpperBoundExpression())); + variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); + } + } + for (auto const& variable : program.getGlobalBooleanVariables()) { + if (variable.hasInitialValue()) { + storm::jani::BooleanVariable const& createdVariable = janiModel.addVariable(storm::jani::BooleanVariable(variable.getName(), variable.getExpressionVariable(), variable.getInitialValueExpression(), false)); + variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); + } else { + storm::jani::BooleanVariable const& createdVariable = janiModel.addVariable(storm::jani::BooleanVariable(variable.getName(), variable.getExpressionVariable(), false)); + variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); + } + } + + // Add all actions of the PRISM program to the JANI model. + for (auto const& action : indexToActionMap) { + // Ignore the empty action as every JANI program has predefined tau action. + if (!action.second.empty()) { + janiModel.addAction(storm::jani::Action(action.second)); + } + } + + // 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. + std::map<storm::expressions::Variable, std::set<uint_fast64_t>> variablesToAccessingModuleIndices; + for (uint_fast64_t index = 0; index < program.getNumberOfModules(); ++index) { + storm::prism::Module const& module = program.getModule(index); + + for (auto const& command : module.getCommands()) { + std::set<storm::expressions::Variable> variables = command.getGuardExpression().getVariables(); + for (auto const& variable : variables) { + variablesToAccessingModuleIndices[variable].insert(index); + } + + for (auto const& update : command.getUpdates()) { + for (auto const& assignment : update.getAssignments()) { + variables = assignment.getExpression().getVariables(); + for (auto const& variable : variables) { + variablesToAccessingModuleIndices[variable].insert(index); + } + variablesToAccessingModuleIndices[assignment.getVariable()].insert(index); + } + } + } + } + + // Now create the separate JANI automata from the modules of the PRISM program. While doing so, we use the + // previously built mapping to make variables global that are read by more than one module. + for (auto const& module : program.getModules()) { + storm::jani::Automaton automaton(module.getName()); + for (auto const& variable : module.getIntegerVariables()) { + 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()]; + // 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) { + storm::jani::BoundedIntegerVariable const& createdVariable = automaton.addVariable(newIntegerVariable); + variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); + } else if (!accessingModuleIndices.empty()) { + // Otherwise, we need to make it global. + storm::jani::BoundedIntegerVariable const& createdVariable = janiModel.addVariable(newIntegerVariable); + variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); + } + } + for (auto const& variable : module.getBooleanVariables()) { + 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()]; + // 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) { + storm::jani::BooleanVariable const& createdVariable = automaton.addVariable(newBooleanVariable); + variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); + } else if (!accessingModuleIndices.empty()) { + // Otherwise, we need to make it global. + storm::jani::BooleanVariable const& createdVariable = janiModel.addVariable(newBooleanVariable); + variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); + } + } + automaton.setInitialStatesRestriction(manager->boolean(true)); + + // Create a single location that will have all the edges. + uint64_t onlyLocation = automaton.addLocation(storm::jani::Location("l")); + automaton.addInitialLocation(onlyLocation); + + for (auto const& command : module.getCommands()) { + boost::optional<storm::expressions::Expression> rateExpression; + std::vector<storm::jani::EdgeDestination> destinations; + if (program.getModelType() == Program::ModelType::CTMC || program.getModelType() == Program::ModelType::CTMDP) { + for (auto const& update : command.getUpdates()) { + if (rateExpression) { + rateExpression = rateExpression.get() + update.getLikelihoodExpression(); + } else { + rateExpression = update.getLikelihoodExpression(); + } + } + } + + for (auto const& update : command.getUpdates()) { + std::vector<storm::jani::Assignment> assignments; + for (auto const& assignment : update.getAssignments()) { + assignments.push_back(storm::jani::Assignment(variableToVariableMap.at(assignment.getVariable()).get(), assignment.getExpression())); + } + + if (rateExpression) { + destinations.push_back(storm::jani::EdgeDestination(onlyLocation, manager->integer(1) / rateExpression.get(), assignments)); + } else { + destinations.push_back(storm::jani::EdgeDestination(onlyLocation, update.getLikelihoodExpression(), assignments)); + } + } + automaton.addEdge(storm::jani::Edge(onlyLocation, janiModel.getActionIndex(command.getActionName()), rateExpression, command.getGuardExpression(), destinations)); + } + + janiModel.addAutomaton(automaton); + } + + // Translate the reward models. + for (auto const& rewardModel : program.getRewardModels()) { + + } + + // Create an initial state restriction if there was an initial construct in the program. + if (program.hasInitialConstruct()) { + janiModel.setInitialStatesRestriction(program.getInitialConstruct().getInitialStatesExpression()); + } else { + janiModel.setInitialStatesRestriction(manager->boolean(true)); + } + + // Set the standard system composition. This is possible, because we reject non-standard compositions anyway. + if (program.specifiesSystemComposition()) { + CompositionToJaniVisitor visitor; + janiModel.setSystemComposition(visitor.toJani(program.getSystemCompositionConstruct().getSystemComposition(), janiModel)); + } else { + janiModel.setSystemComposition(janiModel.getStandardSystemComposition()); + } + + janiModel.finalize(); + + return janiModel; + } + + } +} \ No newline at end of file diff --git a/src/storage/prism/ToJaniConverter.h b/src/storage/prism/ToJaniConverter.h new file mode 100644 index 000000000..55bed5549 --- /dev/null +++ b/src/storage/prism/ToJaniConverter.h @@ -0,0 +1,20 @@ +#pragma once + +namespace storm { + namespace jani { + class Model; + } + + namespace prism { + + class Program; + + class ToJaniConverter { + public: + ToJaniConverter(); + + storm::jani::Model convert(storm::prism::Program const& program, bool allVariablesGlobal = false) const; + }; + + } +} \ No newline at end of file From c0d16284661dc0f11831f16ed402fe0731e73e4b Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Tue, 6 Sep 2016 19:53:09 +0200 Subject: [PATCH 23/34] made Prism to JANI conversion compile again Former-commit-id: 7775fd4a18457a6850ff1f49c61a7e38368f03f5 [formerly f7a542bf3e7aec2dea19a503abee62079a7e3e76] Former-commit-id: 0c0f7cf70b9160d2bfdd5c6b7c7ad92719469352 --- src/storage/prism/Program.cpp | 9 +++++---- src/storage/prism/Program.h | 4 +--- src/storage/prism/ToJaniConverter.cpp | 8 ++++---- src/storage/prism/ToJaniConverter.h | 2 -- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/storage/prism/Program.cpp b/src/storage/prism/Program.cpp index c92226c84..99f4d3e4f 100644 --- a/src/storage/prism/Program.cpp +++ b/src/storage/prism/Program.cpp @@ -20,6 +20,7 @@ #include "src/storage/prism/CompositionVisitor.h" #include "src/storage/prism/Compositions.h" +#include "src/storage/prism/ToJaniConverter.h" namespace storm { namespace prism { @@ -1600,13 +1601,13 @@ namespace storm { return Command(newCommandIndex, false, actionIndex, actionName, newGuard, newUpdates, this->getFilename(), 0); } - uint_fast64_t Program::numberOfActions() const { + uint_fast64_t Program::getNumberOfActions() const { return this->actions.size(); } - uint_fast64_t Program::largestActionIndex() const { - assert(numberOfActions() != 0); - return this->indexToActionMap.rbegin()->first; + storm::jani::Model Program::toJani(bool allVariablesGlobal) const { + ToJaniConverter converter; + return converter.convert(*this, allVariablesGlobal); } storm::expressions::ExpressionManager& Program::getManager() const { diff --git a/src/storage/prism/Program.h b/src/storage/prism/Program.h index 9233d5014..bc17072e1 100644 --- a/src/storage/prism/Program.h +++ b/src/storage/prism/Program.h @@ -574,9 +574,7 @@ namespace storm { std::unordered_map<uint_fast64_t, std::string> buildActionIndexToActionNameMap() const; - uint_fast64_t numberOfActions() const; - - uint_fast64_t largestActionIndex() const; + uint_fast64_t getNumberOfActions() const; /*! * Converts the PRISM model into an equivalent JANI model. diff --git a/src/storage/prism/ToJaniConverter.cpp b/src/storage/prism/ToJaniConverter.cpp index c340035ee..2e5631ebc 100644 --- a/src/storage/prism/ToJaniConverter.cpp +++ b/src/storage/prism/ToJaniConverter.cpp @@ -9,7 +9,7 @@ namespace storm { namespace prism { - storm::jani::Model convert(storm::prism::Program const& program, bool allVariablesGlobal) { + storm::jani::Model ToJaniConverter::convert(storm::prism::Program const& program, bool allVariablesGlobal) const { std::shared_ptr<storm::expressions::ExpressionManager> manager = program.getManager().getSharedPointer(); // Start by creating an empty JANI model. @@ -59,10 +59,10 @@ namespace storm { } // Add all actions of the PRISM program to the JANI model. - for (auto const& action : indexToActionMap) { + for (auto const& action : program.getActions()) { // Ignore the empty action as every JANI program has predefined tau action. - if (!action.second.empty()) { - janiModel.addAction(storm::jani::Action(action.second)); + if (!action.empty()) { + janiModel.addAction(storm::jani::Action(action)); } } diff --git a/src/storage/prism/ToJaniConverter.h b/src/storage/prism/ToJaniConverter.h index 55bed5549..bbabef568 100644 --- a/src/storage/prism/ToJaniConverter.h +++ b/src/storage/prism/ToJaniConverter.h @@ -11,8 +11,6 @@ namespace storm { class ToJaniConverter { public: - ToJaniConverter(); - storm::jani::Model convert(storm::prism::Program const& program, bool allVariablesGlobal = false) const; }; From 7af89f5a6f2e5616b453686aa30a800c6663c419 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Tue, 6 Sep 2016 22:50:44 +0200 Subject: [PATCH 24/34] real transient variables and assignments are now added in PRISM to JANI transformation Former-commit-id: 45ccd460710bc785a1b16b7a7e9311bf6fdd406f [formerly a8d1de9c6afbc0d45873c993307e5eeb381bbd9c] Former-commit-id: 6aa6dbae52d8596630cef396fcf28fa0600bdbab --- src/builder/DdJaniModelBuilder.cpp | 18 ++++- src/generator/JaniNextStateGenerator.cpp | 4 +- src/storage/jani/Assignment.cpp | 4 + src/storage/jani/Assignment.h | 5 ++ src/storage/jani/Automaton.cpp | 18 ++++- src/storage/jani/Automaton.h | 10 +++ src/storage/jani/BoundedIntegerVariable.cpp | 7 +- src/storage/jani/BoundedIntegerVariable.h | 5 ++ src/storage/jani/Edge.cpp | 21 +++++ src/storage/jani/Edge.h | 15 ++++ src/storage/jani/EdgeDestination.cpp | 13 ++++ src/storage/jani/EdgeDestination.h | 5 ++ src/storage/jani/Location.cpp | 4 + src/storage/jani/Location.h | 5 ++ src/storage/jani/Model.cpp | 25 +----- src/storage/jani/Variable.cpp | 7 +- src/storage/jani/Variable.h | 5 ++ src/storage/jani/VariableSet.cpp | 10 +++ src/storage/jani/VariableSet.h | 7 +- src/storage/prism/ToJaniConverter.cpp | 85 ++++++++++++++++++--- 20 files changed, 232 insertions(+), 41 deletions(-) diff --git a/src/builder/DdJaniModelBuilder.cpp b/src/builder/DdJaniModelBuilder.cpp index 9397ed925..4909245fa 100644 --- a/src/builder/DdJaniModelBuilder.cpp +++ b/src/builder/DdJaniModelBuilder.cpp @@ -188,11 +188,15 @@ namespace storm { this->model.getSystemComposition().accept(*this, boost::none); STORM_LOG_THROW(automata.size() == this->model.getNumberOfAutomata(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model whose system composition refers to a subset of automata."); - // Then, check that the model does not contain unbounded integer variables. + // Then, check that the model does not contain unbounded integer or non-transient real variables. STORM_LOG_THROW(!this->model.getGlobalVariables().containsUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model that contains global unbounded integer variables."); for (auto const& automaton : this->model.getAutomata()) { STORM_LOG_THROW(!automaton.getVariables().containsUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model that contains unbounded integer variables in automaton '" << automaton.getName() << "'."); } + STORM_LOG_THROW(!this->model.getGlobalVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model that contains global non-transient real variables."); + for (auto const& automaton : this->model.getAutomata()) { + STORM_LOG_THROW(!automaton.getVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model that contains non-transient real variables in automaton '" << automaton.getName() << "'."); + } // Based on this assumption, we create the variables. return createVariables(); @@ -256,6 +260,11 @@ namespace storm { // Create global variables. storm::dd::Bdd<Type> globalVariableRanges = result.manager->getBddOne(); for (auto const& variable : this->model.getGlobalVariables()) { + // Only create the variable if it's non-transient. + if (variable.isTransientVariable()) { + continue; + } + createVariable(variable, result); globalVariableRanges &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable())); } @@ -274,6 +283,11 @@ namespace storm { // Then create variables for the variables of the automaton. for (auto const& variable : automaton.getVariables()) { + // Only create the variable if it's non-transient. + if (variable.isTransientVariable()) { + continue; + } + createVariable(variable, result); identity &= result.variableToIdentityMap.at(variable.getExpressionVariable()).toBdd(); range &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable())); @@ -391,7 +405,7 @@ namespace storm { // Iterate over all assignments (boolean and integer) and build the DD for it. std::set<storm::expressions::Variable> assignedVariables; - for (auto const& assignment : destination.getAssignments()) { + for (auto const& assignment : destination.getNonTransientAssignments()) { // Record the variable as being written. STORM_LOG_TRACE("Assigning to variable " << variables.variableToRowMetaVariableMap->at(assignment.getExpressionVariable()).getName()); assignedVariables.insert(assignment.getExpressionVariable()); diff --git a/src/generator/JaniNextStateGenerator.cpp b/src/generator/JaniNextStateGenerator.cpp index 0b2fad41a..ba76f4e86 100644 --- a/src/generator/JaniNextStateGenerator.cpp +++ b/src/generator/JaniNextStateGenerator.cpp @@ -179,8 +179,8 @@ namespace storm { // within the types, the assignments to variables are ordered (in ascending order) by the expression variables. // This is guaranteed for JANI models, by sorting the assignments as soon as an edge destination is created. - auto assignmentIt = destination.getAssignments().begin(); - auto assignmentIte = destination.getAssignments().end(); + auto assignmentIt = destination.getNonTransientAssignments().begin(); + auto assignmentIte = destination.getNonTransientAssignments().end(); // Iterate over all boolean assignments and carry them out. auto boolIt = this->variableInformation.booleanVariables.begin(); diff --git a/src/storage/jani/Assignment.cpp b/src/storage/jani/Assignment.cpp index cea0b9eec..559fc685b 100644 --- a/src/storage/jani/Assignment.cpp +++ b/src/storage/jani/Assignment.cpp @@ -31,6 +31,10 @@ namespace storm { return this->variable.get().isTransientVariable(); } + void Assignment::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) { + this->setAssignedExpression(this->getAssignedExpression().substitute(substitution)); + } + std::ostream& operator<<(std::ostream& stream, Assignment const& assignment) { stream << assignment.getVariable().getName() << " := " << assignment.getAssignedExpression(); return stream; diff --git a/src/storage/jani/Assignment.h b/src/storage/jani/Assignment.h index dbdfb7edd..24cc9d10c 100644 --- a/src/storage/jani/Assignment.h +++ b/src/storage/jani/Assignment.h @@ -37,6 +37,11 @@ namespace storm { */ void setAssignedExpression(storm::expressions::Expression const& expression); + /*! + * Substitutes all variables in all expressions according to the given substitution. + */ + void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution); + /** * Retrieves whether the assignment assigns to a transient variable. */ diff --git a/src/storage/jani/Automaton.cpp b/src/storage/jani/Automaton.cpp index 9227a4c5b..1a38adea8 100644 --- a/src/storage/jani/Automaton.cpp +++ b/src/storage/jani/Automaton.cpp @@ -108,7 +108,11 @@ namespace storm { Location const& Automaton::getLocation(uint64_t index) const { return locations[index]; } - + + Location& Automaton::getLocation(uint64_t index) { + return locations[index]; + } + uint64_t Automaton::addLocation(Location const& location) { STORM_LOG_THROW(!this->hasLocation(location.getName()), storm::exceptions::WrongFormatException, "Cannot add location with name '" << location.getName() << "', because a location with this name already exists."); locationToIndex.emplace(location.getName(), locations.size()); @@ -358,6 +362,18 @@ namespace storm { return result; } + void Automaton::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) { + for (auto& variable : this->getVariables().getBoundedIntegerVariables()) { + variable.substitute(substitution); + } + + this->setInitialStatesRestriction(this->getInitialStatesRestriction().substitute(substitution)); + + for (auto& edge : this->getEdges()) { + edge.substitute(substitution); + } + } + void Automaton::finalize(Model const& containingModel) { for (auto& edge : edges) { edge.finalize(containingModel); diff --git a/src/storage/jani/Automaton.h b/src/storage/jani/Automaton.h index e46fc44be..d023fa36c 100644 --- a/src/storage/jani/Automaton.h +++ b/src/storage/jani/Automaton.h @@ -158,6 +158,11 @@ namespace storm { */ Location const& getLocation(uint64_t index) const; + /*! + * Retrieves the location with the given index. + */ + Location& getLocation(uint64_t index); + /*! * Adds the given location to the automaton. */ @@ -268,6 +273,11 @@ namespace storm { */ std::vector<storm::expressions::Expression> getAllRangeExpressions() const; + /*! + * Substitutes all variables in all expressions according to the given substitution. + */ + void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution); + /*! * Finalizes the building of this automaton. Subsequent changes to the automaton require another call to this * method. Note that this method is invoked by a call to <code>finalize</code> to the containing model. diff --git a/src/storage/jani/BoundedIntegerVariable.cpp b/src/storage/jani/BoundedIntegerVariable.cpp index 58173bb76..37b458ba4 100644 --- a/src/storage/jani/BoundedIntegerVariable.cpp +++ b/src/storage/jani/BoundedIntegerVariable.cpp @@ -21,7 +21,6 @@ namespace storm { // Intentionally left empty. } - storm::expressions::Expression const& BoundedIntegerVariable::getLowerBound() const { return lowerBound; } @@ -46,6 +45,12 @@ namespace storm { return true; } + void BoundedIntegerVariable::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) { + Variable::substitute(substitution); + this->setLowerBound(this->getLowerBound().substitute(substitution)); + this->setUpperBound(this->getUpperBound().substitute(substitution)); + } + std::shared_ptr<BoundedIntegerVariable> makeBoundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, boost::optional<storm::expressions::Expression> initValue, bool transient, boost::optional<storm::expressions::Expression> lowerBound, boost::optional<storm::expressions::Expression> upperBound) { STORM_LOG_THROW(lowerBound && upperBound, storm::exceptions::NotImplementedException, "Jani Bounded Integer variables (for now) have to be bounded from both sides"); if (initValue) { diff --git a/src/storage/jani/BoundedIntegerVariable.h b/src/storage/jani/BoundedIntegerVariable.h index 1c68bd239..733024b3d 100644 --- a/src/storage/jani/BoundedIntegerVariable.h +++ b/src/storage/jani/BoundedIntegerVariable.h @@ -52,6 +52,11 @@ namespace storm { virtual bool isBoundedIntegerVariable() const override; + /*! + * Substitutes all variables in all expressions according to the given substitution. + */ + virtual void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) override; + private: // The expression defining the lower bound of the variable. storm::expressions::Expression lowerBound; diff --git a/src/storage/jani/Edge.cpp b/src/storage/jani/Edge.cpp index 430838b61..e1ac1a274 100644 --- a/src/storage/jani/Edge.cpp +++ b/src/storage/jani/Edge.cpp @@ -49,6 +49,27 @@ namespace storm { destinations.push_back(destination); } + std::vector<Assignment>& Edge::getTransientAssignments() { + return transientAssignments; + } + + std::vector<Assignment> const& Edge::getTransientAssignments() const { + return transientAssignments; + } + + void Edge::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) { + this->setGuard(this->getGuard().substitute(substitution)); + if (this->hasRate()) { + this->setRate(this->getRate().substitute(substitution)); + } + for (auto& assignment : this->getTransientAssignments()) { + assignment.substitute(substitution); + } + for (auto& destination : this->getDestinations()) { + destination.substitute(substitution); + } + } + void Edge::finalize(Model const& containingModel) { for (auto const& destination : getDestinations()) { for (auto const& assignment : destination.getAssignments()) { diff --git a/src/storage/jani/Edge.h b/src/storage/jani/Edge.h index f56685984..47358bb05 100644 --- a/src/storage/jani/Edge.h +++ b/src/storage/jani/Edge.h @@ -64,6 +64,21 @@ namespace storm { */ void addDestination(EdgeDestination const& destination); + /*! + * Retrieves the transient assignments of this edge. + */ + std::vector<Assignment>& getTransientAssignments(); + + /*! + * Retrieves the transient assignments of this edge. + */ + std::vector<Assignment> const& getTransientAssignments() const; + + /*! + * Substitutes all variables in all expressions according to the given substitution. + */ + void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution); + /*! * Finalizes the building of this edge. Subsequent changes to the edge require another call to this * method. Note that this method is invoked by a call to <code>finalize</code> to the containing model. diff --git a/src/storage/jani/EdgeDestination.cpp b/src/storage/jani/EdgeDestination.cpp index f49b15eac..c59018e38 100644 --- a/src/storage/jani/EdgeDestination.cpp +++ b/src/storage/jani/EdgeDestination.cpp @@ -72,6 +72,19 @@ namespace storm { return transientAssignments; } + void EdgeDestination::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) { + this->setProbability(this->getProbability().substitute(substitution)); + for (auto& assignment : this->getAssignments()) { + assignment.substitute(substitution); + } + for (auto& assignment : this->getTransientAssignments()) { + assignment.substitute(substitution); + } + for (auto& assignment : this->getNonTransientAssignments()) { + assignment.substitute(substitution); + } + } + bool EdgeDestination::hasAssignment(Assignment const& assignment) const { for (auto const& containedAssignment : assignments) { if (containedAssignment == assignment) { diff --git a/src/storage/jani/EdgeDestination.h b/src/storage/jani/EdgeDestination.h index 9d3f8326d..02da155e1 100644 --- a/src/storage/jani/EdgeDestination.h +++ b/src/storage/jani/EdgeDestination.h @@ -66,6 +66,11 @@ namespace storm { */ std::vector<Assignment> const& getTransientAssignments() const; + /*! + * Substitutes all variables in all expressions according to the given substitution. + */ + void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution); + /*! * Retrieves whether this assignment is made when choosing this destination. * diff --git a/src/storage/jani/Location.cpp b/src/storage/jani/Location.cpp index 2f1f1f6b7..32d17531e 100644 --- a/src/storage/jani/Location.cpp +++ b/src/storage/jani/Location.cpp @@ -18,6 +18,10 @@ namespace storm { return transientAssignments; } + void Location::addTransientAssignment(storm::jani::Assignment const& assignment) { + transientAssignments.push_back(assignment); + } + void Location::checkValid() const { for(auto const& assignment : transientAssignments) { STORM_LOG_THROW(assignment.isTransientAssignment(), storm::exceptions::InvalidJaniException, "Only transient assignments are allowed in locations."); diff --git a/src/storage/jani/Location.h b/src/storage/jani/Location.h index 461b68e1f..e80faedf9 100644 --- a/src/storage/jani/Location.h +++ b/src/storage/jani/Location.h @@ -29,6 +29,11 @@ namespace storm { */ std::vector<Assignment> const& getTransientAssignments() const; + /*! + * Adds the given transient assignment to this location. + */ + void addTransientAssignment(storm::jani::Assignment const& assignment); + /*! * Checks whether the location is valid, that is, whether the assignments are indeed all transient assignments. */ diff --git a/src/storage/jani/Model.cpp b/src/storage/jani/Model.cpp index 08a243c06..9d0dcb7d0 100644 --- a/src/storage/jani/Model.cpp +++ b/src/storage/jani/Model.cpp @@ -310,9 +310,7 @@ namespace storm { // Substitute constants in all global variables. for (auto& variable : result.getGlobalVariables().getBoundedIntegerVariables()) { - variable.setInitExpression(variable.getInitExpression().substitute(constantSubstitution)); - variable.setLowerBound(variable.getLowerBound().substitute(constantSubstitution)); - variable.setUpperBound(variable.getUpperBound().substitute(constantSubstitution)); + variable.substitute(constantSubstitution); } // Substitute constants in initial states expression. @@ -320,26 +318,7 @@ namespace storm { // Substitute constants in variables of automata and their edges. for (auto& automaton : result.getAutomata()) { - for (auto& variable : automaton.getVariables().getBoundedIntegerVariables()) { - variable.setInitExpression(variable.getInitExpression().substitute(constantSubstitution)); - variable.setLowerBound(variable.getLowerBound().substitute(constantSubstitution)); - variable.setUpperBound(variable.getUpperBound().substitute(constantSubstitution)); - } - - automaton.setInitialStatesRestriction(automaton.getInitialStatesExpression().substitute(constantSubstitution)); - - for (auto& edge : automaton.getEdges()) { - edge.setGuard(edge.getGuard().substitute(constantSubstitution)); - if (edge.hasRate()) { - edge.setRate(edge.getRate().substitute(constantSubstitution)); - } - for (auto& destination : edge.getDestinations()) { - destination.setProbability(destination.getProbability().substitute(constantSubstitution)); - for (auto& assignment : destination.getAssignments()) { - assignment.setAssignedExpression(assignment.getAssignedExpression().substitute(constantSubstitution)); - } - } - } + automaton.substitute(constantSubstitution); } return result; diff --git a/src/storage/jani/Variable.cpp b/src/storage/jani/Variable.cpp index 4027ea112..763179013 100644 --- a/src/storage/jani/Variable.cpp +++ b/src/storage/jani/Variable.cpp @@ -16,7 +16,6 @@ namespace storm { // Intentionally left empty. } - storm::expressions::Variable const& Variable::getExpressionVariable() const { return variable; } @@ -89,5 +88,11 @@ namespace storm { return static_cast<RealVariable const&>(*this); } + void Variable::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) { + if (this->hasInitExpression()) { + this->setInitExpression(this->getInitExpression().substitute(substitution)); + } + } + } } \ No newline at end of file diff --git a/src/storage/jani/Variable.h b/src/storage/jani/Variable.h index 8d25bfd36..fa56e0a8d 100644 --- a/src/storage/jani/Variable.h +++ b/src/storage/jani/Variable.h @@ -73,6 +73,11 @@ namespace storm { RealVariable& asRealVariable(); RealVariable const& asRealVariable() const; + /*! + * Substitutes all variables in all expressions according to the given substitution. + */ + virtual void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution); + private: // The name of the variable. std::string name; diff --git a/src/storage/jani/VariableSet.cpp b/src/storage/jani/VariableSet.cpp index 27806a132..7b304e68d 100644 --- a/src/storage/jani/VariableSet.cpp +++ b/src/storage/jani/VariableSet.cpp @@ -174,6 +174,16 @@ namespace storm { return !realVariables.empty(); } + bool VariableSet::containsNonTransientRealVariables() const { + for (auto const& variable : realVariables) { + if (!variable->isTransientVariable()) { + std::cout << "var " << variable->getName() << "is non-transient " << std::endl; + return true; + } + } + return false; + } + bool VariableSet::empty() const { return !(containsBooleanVariable() || containsBoundedIntegerVariable() || containsUnboundedIntegerVariables()); } diff --git a/src/storage/jani/VariableSet.h b/src/storage/jani/VariableSet.h index 651787df5..4156faec1 100644 --- a/src/storage/jani/VariableSet.h +++ b/src/storage/jani/VariableSet.h @@ -184,10 +184,15 @@ namespace storm { bool containsUnboundedIntegerVariables() const; /*! - * Retrieves whether the set of variables contains an unbounded integer variable. + * Retrieves whether the set of variables contains a real variable. */ bool containsRealVariables() const; + /*! + * Retrieves whether the set of variables contains a non-transient real variable. + */ + bool containsNonTransientRealVariables() const; + /*! * Retrieves whether this variable set is empty. */ diff --git a/src/storage/prism/ToJaniConverter.cpp b/src/storage/prism/ToJaniConverter.cpp index 2e5631ebc..7c3d859b2 100644 --- a/src/storage/prism/ToJaniConverter.cpp +++ b/src/storage/prism/ToJaniConverter.cpp @@ -6,6 +6,9 @@ #include "src/storage/prism/CompositionToJaniVisitor.h" #include "src/storage/jani/Model.h" +#include "src/utility/macros.h" +#include "src/exceptions/NotImplementedException.h" + namespace storm { namespace prism { @@ -91,8 +94,53 @@ namespace storm { } } + // Go through the reward models and construct assignments to the transient variables that are to be added to + // edges and transient assignments that are added to the locations. + std::map<uint_fast64_t, std::vector<storm::jani::Assignment>> transientEdgeAssignments; + std::vector<storm::jani::Assignment> transientLocationAssignments; + for (auto const& rewardModel : program.getRewardModels()) { + auto newExpressionVariable = manager->declareRationalVariable(rewardModel.getName().empty() ? "default" : rewardModel.getName()); + storm::jani::RealVariable const& newTransientVariable = janiModel.addVariable(storm::jani::RealVariable(rewardModel.getName(), newExpressionVariable, true)); + + if (rewardModel.hasStateRewards()) { + storm::expressions::Expression transientLocationExpression; + for (auto const& stateReward : rewardModel.getStateRewards()) { + storm::expressions::Expression rewardTerm = stateReward.getStatePredicateExpression().isTrue() ? stateReward.getRewardValueExpression() : storm::expressions::ite(stateReward.getStatePredicateExpression(), stateReward.getRewardValueExpression(), manager->rational(0)); + if (transientLocationExpression.isInitialized()) { + transientLocationExpression = transientLocationExpression + rewardTerm; + } else { + transientLocationExpression = rewardTerm; + } + } + transientLocationAssignments.emplace_back(newTransientVariable, transientLocationExpression); + } + + std::map<uint_fast64_t, storm::expressions::Expression> actionIndexToExpression; + for (auto const& actionReward : rewardModel.getStateActionRewards()) { + storm::expressions::Expression rewardTerm = actionReward.getStatePredicateExpression().isTrue() ? actionReward.getRewardValueExpression() : storm::expressions::ite(actionReward.getStatePredicateExpression(), actionReward.getRewardValueExpression(), manager->rational(0)); + auto it = actionIndexToExpression.find(janiModel.getActionIndex(actionReward.getActionName())); + if (it != actionIndexToExpression.end()) { + it->second = it->second + rewardTerm; + } else { + actionIndexToExpression[janiModel.getActionIndex(actionReward.getActionName())] = rewardTerm; + } + } + + for (auto const& entry : actionIndexToExpression) { + auto it = transientEdgeAssignments.find(entry.first); + if (it != transientEdgeAssignments.end()) { + it->second.push_back(storm::jani::Assignment(newTransientVariable, entry.second)); + } else { + std::vector<storm::jani::Assignment> assignments = {storm::jani::Assignment(newTransientVariable, entry.second)}; + transientEdgeAssignments.emplace(entry.first, assignments); + } + } + STORM_LOG_THROW(!rewardModel.hasTransitionRewards(), storm::exceptions::NotImplementedException, "Transition reward translation currently not implemented."); + } + // Now create the separate JANI automata from the modules of the PRISM program. While doing so, we use the // previously built mapping to make variables global that are read by more than one module. + bool firstModule = true; for (auto const& module : program.getModules()) { storm::jani::Automaton automaton(module.getName()); for (auto const& variable : module.getIntegerVariables()) { @@ -124,8 +172,16 @@ namespace storm { automaton.setInitialStatesRestriction(manager->boolean(true)); // Create a single location that will have all the edges. - uint64_t onlyLocation = automaton.addLocation(storm::jani::Location("l")); - automaton.addInitialLocation(onlyLocation); + uint64_t onlyLocationIndex = automaton.addLocation(storm::jani::Location("l")); + automaton.addInitialLocation(onlyLocationIndex); + + // If we are translating the first module, we need to add the transient assignments to the location. + if (firstModule) { + storm::jani::Location& onlyLocation = automaton.getLocation(onlyLocationIndex); + for (auto const& assignment : transientLocationAssignments) { + onlyLocation.addTransientAssignment(assignment); + } + } for (auto const& command : module.getCommands()) { boost::optional<storm::expressions::Expression> rateExpression; @@ -147,20 +203,29 @@ namespace storm { } if (rateExpression) { - destinations.push_back(storm::jani::EdgeDestination(onlyLocation, manager->integer(1) / rateExpression.get(), assignments)); + destinations.push_back(storm::jani::EdgeDestination(onlyLocationIndex, manager->integer(1) / rateExpression.get(), assignments)); } else { - destinations.push_back(storm::jani::EdgeDestination(onlyLocation, update.getLikelihoodExpression(), assignments)); + destinations.push_back(storm::jani::EdgeDestination(onlyLocationIndex, update.getLikelihoodExpression(), assignments)); } } - automaton.addEdge(storm::jani::Edge(onlyLocation, janiModel.getActionIndex(command.getActionName()), rateExpression, command.getGuardExpression(), destinations)); + + // Create the edge object so we can add transient assignments. + storm::jani::Edge newEdge(onlyLocationIndex, janiModel.getActionIndex(command.getActionName()), rateExpression, command.getGuardExpression(), destinations); + + // Then add the transient assignments for the rewards. + auto transientEdgeAssignmentsToAdd = transientEdgeAssignments.find(janiModel.getActionIndex(command.getActionName())); + if (transientEdgeAssignmentsToAdd != transientEdgeAssignments.end()) { + for (auto const& assignment : transientEdgeAssignmentsToAdd->second) { + newEdge.addTransientAssignment(assignment); + } + } + + // Finally add the constructed edge. + automaton.addEdge(newEdge); } janiModel.addAutomaton(automaton); - } - - // Translate the reward models. - for (auto const& rewardModel : program.getRewardModels()) { - + firstModule = false; } // Create an initial state restriction if there was an initial construct in the program. From eed0a9889948a55712bb1189cd2e2e9f7e544445 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Wed, 7 Sep 2016 21:58:03 +0200 Subject: [PATCH 25/34] commit to switch workplace Former-commit-id: da2d6f8af30905171448c10ca352ed6f4630be61 [formerly f2157cac64652f329887fd114296904b9fbee9f7] Former-commit-id: 1b7b4b649664dbbb6653e122fb868fdcaad6d664 --- src/builder/DdJaniModelBuilder.cpp | 4 +-- src/generator/JaniNextStateGenerator.cpp | 32 ++++++++++++++++++++++-- src/generator/JaniNextStateGenerator.h | 4 +++ src/parser/JaniParser.cpp | 2 +- src/storage/jani/Assignment.cpp | 2 +- src/storage/jani/Automaton.cpp | 4 +++ src/storage/jani/Automaton.h | 5 ++++ src/storage/jani/Model.cpp | 17 +++++++++++++ src/storage/jani/Model.h | 15 +++++++++++ src/storage/jani/Variable.cpp | 2 +- src/storage/jani/Variable.h | 2 +- src/storage/jani/VariableSet.cpp | 11 +++++++- src/storage/jani/VariableSet.h | 5 ++++ 13 files changed, 96 insertions(+), 9 deletions(-) diff --git a/src/builder/DdJaniModelBuilder.cpp b/src/builder/DdJaniModelBuilder.cpp index 4909245fa..f62afa00f 100644 --- a/src/builder/DdJaniModelBuilder.cpp +++ b/src/builder/DdJaniModelBuilder.cpp @@ -261,7 +261,7 @@ namespace storm { storm::dd::Bdd<Type> globalVariableRanges = result.manager->getBddOne(); for (auto const& variable : this->model.getGlobalVariables()) { // Only create the variable if it's non-transient. - if (variable.isTransientVariable()) { + if (variable.isTransient()) { continue; } @@ -284,7 +284,7 @@ namespace storm { // Then create variables for the variables of the automaton. for (auto const& variable : automaton.getVariables()) { // Only create the variable if it's non-transient. - if (variable.isTransientVariable()) { + if (variable.isTransient()) { continue; } diff --git a/src/generator/JaniNextStateGenerator.cpp b/src/generator/JaniNextStateGenerator.cpp index ba76f4e86..f6dbfa618 100644 --- a/src/generator/JaniNextStateGenerator.cpp +++ b/src/generator/JaniNextStateGenerator.cpp @@ -11,6 +11,7 @@ #include "src/utility/solver.h" #include "src/exceptions/InvalidSettingsException.h" #include "src/exceptions/WrongFormatException.h" +#include "src/exceptions/InvalidArgumentException.h" namespace storm { namespace generator { @@ -21,11 +22,38 @@ namespace storm { } template<typename ValueType, typename StateType> - JaniNextStateGenerator<ValueType, StateType>::JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options, bool flag) : NextStateGenerator<ValueType, StateType>(model.getExpressionManager(), VariableInformation(model), options), model(model) { + JaniNextStateGenerator<ValueType, StateType>::JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options, bool flag) : NextStateGenerator<ValueType, StateType>(model.getExpressionManager(), VariableInformation(model), options), model(model), rewardVariables() { STORM_LOG_THROW(model.hasDefaultComposition(), storm::exceptions::WrongFormatException, "The explicit next-state generator currently does not support custom system compositions."); - STORM_LOG_THROW(!this->options.isBuildAllRewardModelsSet() && this->options.getRewardModelNames().empty(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support building reward models."); + STORM_LOG_THROW(!model.hasNonGlobalTransientVariable(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support automata-local transient variables."); STORM_LOG_THROW(!this->options.isBuildChoiceLabelsSet(), storm::exceptions::InvalidSettingsException, "JANI next-state generator cannot generate choice labels."); + if (this->options.isBuildAllRewardModelsSet()) { + for (auto const& variable : model.getGlobalVariables()) { + if (variable.isTransient()) { + rewardVariables.push_back(variable.getExpressionVariable()); + } + } + } else { + // Extract the reward models from the program based on the names we were given. + for (auto const& rewardModelName : this->options.getRewardModelNames()) { + auto const& globalVariables = model.getGlobalVariables(); + if (globalVariables.hasVariable(rewardModelName)) { + rewardVariables.push_back(globalVariables.getVariable(rewardModelName).getExpressionVariable()); + } else { + STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException, "Cannot build unknown reward model '" << rewardModelName << "'."); + STORM_LOG_THROW(globalVariables.getNumberOfTransientVariables() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous."); + STORM_LOG_THROW(this->program.getNumberOfRewardModels() > 0, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is invalid, because there is no reward model."); + } + } + + // If no reward model was yet added, but there was one that was given in the options, we try to build + // standard reward model. + if (rewardModels.empty() && !this->options.getRewardModelNames().empty()) { + rewardModels.push_back(this->program.getRewardModel(0)); + } + } + + // If there are terminal states we need to handle, we now need to translate all labels to expressions. if (this->options.hasTerminalStates()) { for (auto const& expressionOrLabelAndBool : this->options.getTerminalStates()) { diff --git a/src/generator/JaniNextStateGenerator.h b/src/generator/JaniNextStateGenerator.h index 316d6e074..be6033ebc 100644 --- a/src/generator/JaniNextStateGenerator.h +++ b/src/generator/JaniNextStateGenerator.h @@ -91,6 +91,10 @@ namespace storm { /// The model used for the generation of next states. storm::jani::Model model; + + // The transient variables of reward models that need to be considered. + std::vector<storm::expressions::Variable> rewardVariables; + }; } diff --git a/src/parser/JaniParser.cpp b/src/parser/JaniParser.cpp index 806a26a1f..b4d67fce2 100644 --- a/src/parser/JaniParser.cpp +++ b/src/parser/JaniParser.cpp @@ -571,7 +571,7 @@ namespace storm { STORM_LOG_THROW(transientValueEntry.count("ref") == 1, storm::exceptions::InvalidJaniException, "Transient values in location " << locName << " need exactly one ref that is assigned to"); STORM_LOG_THROW(transientValueEntry.count("value") == 1, storm::exceptions::InvalidJaniException, "Transient values in location " << locName << " need exactly one assigned value"); storm::jani::Variable const& lhs = getLValue(transientValueEntry.at("ref"), parentModel.getGlobalVariables(), automaton.getVariables(), "LHS of assignment in location " + locName + " (automaton '" + name + "')"); - STORM_LOG_THROW(lhs.isTransientVariable(), storm::exceptions::InvalidJaniException, "Assigned non-transient variable " + lhs.getName() + " in location " + locName + " (automaton: '" + name + "')"); + STORM_LOG_THROW(lhs.isTransient(), storm::exceptions::InvalidJaniException, "Assigned non-transient variable " + lhs.getName() + " in location " + locName + " (automaton: '" + name + "')"); storm::expressions::Expression rhs = parseExpression(transientValueEntry.at("value"), "Assignment of variable " + lhs.getName() + " in location " + locName + " (automaton: '" + name + "')"); transientAssignments.emplace_back(lhs, rhs); } diff --git a/src/storage/jani/Assignment.cpp b/src/storage/jani/Assignment.cpp index 559fc685b..0e1720a8d 100644 --- a/src/storage/jani/Assignment.cpp +++ b/src/storage/jani/Assignment.cpp @@ -28,7 +28,7 @@ namespace storm { } bool Assignment::isTransientAssignment() const { - return this->variable.get().isTransientVariable(); + return this->variable.get().isTransient(); } void Assignment::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) { diff --git a/src/storage/jani/Automaton.cpp b/src/storage/jani/Automaton.cpp index 1a38adea8..9e288695f 100644 --- a/src/storage/jani/Automaton.cpp +++ b/src/storage/jani/Automaton.cpp @@ -97,6 +97,10 @@ namespace storm { return variables; } + bool Automaton::hasTransientVariable() const { + return variables.hasTransientVariable(); + } + bool Automaton::hasLocation(std::string const& name) const { return locationToIndex.find(name) != locationToIndex.end(); } diff --git a/src/storage/jani/Automaton.h b/src/storage/jani/Automaton.h index d023fa36c..9ef3c57f2 100644 --- a/src/storage/jani/Automaton.h +++ b/src/storage/jani/Automaton.h @@ -135,6 +135,11 @@ namespace storm { */ VariableSet const& getVariables() const; + /*! + * Retrieves whether this automaton has a transient variable. + */ + bool hasTransientVariable() const; + /*! * Retrieves whether the automaton has a location with the given name. */ diff --git a/src/storage/jani/Model.cpp b/src/storage/jani/Model.cpp index 9d0dcb7d0..0bec35317 100644 --- a/src/storage/jani/Model.cpp +++ b/src/storage/jani/Model.cpp @@ -143,6 +143,23 @@ namespace storm { return globalVariables; } + bool Model::hasGlobalVariable(std::string const& name) const { + return globalVariables.hasVariable(name); + } + + Variable const& Model::getGlobalVariable(std::string const& name) const { + return globalVariables.getVariable(name); + } + + bool Model::hasNonGlobalTransientVariable() const { + for (auto const& automaton : automata) { + if (automaton.hasTransientVariable()) { + return true; + } + } + return false; + } + storm::expressions::ExpressionManager& Model::getExpressionManager() { return *expressionManager; } diff --git a/src/storage/jani/Model.h b/src/storage/jani/Model.h index 20ca41486..946871cc5 100644 --- a/src/storage/jani/Model.h +++ b/src/storage/jani/Model.h @@ -141,6 +141,21 @@ namespace storm { * Retrieves the variables of this automaton. */ VariableSet const& getGlobalVariables() const; + + /*! + * Retrieves whether this model has a global variable with the given name. + */ + bool hasGlobalVariable(std::string const& name) const; + + /*! + * Retrieves the global variable with the given name if one exists. + */ + Variable const& getGlobalVariable(std::string const& name) const; + + /*! + * Retrieves whether this model has a non-global transient variable. + */ + bool hasNonGlobalTransientVariable() const; /*! * Retrieves the manager responsible for the expressions in the JANI model. diff --git a/src/storage/jani/Variable.cpp b/src/storage/jani/Variable.cpp index 763179013..9280b7c8e 100644 --- a/src/storage/jani/Variable.cpp +++ b/src/storage/jani/Variable.cpp @@ -40,7 +40,7 @@ namespace storm { return false; } - bool Variable::isTransientVariable() const { + bool Variable::isTransient() const { return transient; } diff --git a/src/storage/jani/Variable.h b/src/storage/jani/Variable.h index fa56e0a8d..1add2768b 100644 --- a/src/storage/jani/Variable.h +++ b/src/storage/jani/Variable.h @@ -61,7 +61,7 @@ namespace storm { virtual bool isUnboundedIntegerVariable() const; virtual bool isRealVariable() const; - virtual bool isTransientVariable() const; + virtual bool isTransient() const; // Methods to get the variable as a different type. BooleanVariable& asBooleanVariable(); diff --git a/src/storage/jani/VariableSet.cpp b/src/storage/jani/VariableSet.cpp index 7b304e68d..c138686e8 100644 --- a/src/storage/jani/VariableSet.cpp +++ b/src/storage/jani/VariableSet.cpp @@ -158,6 +158,15 @@ namespace storm { return variableToVariable.find(variable) != variableToVariable.end(); } + bool VariableSet::hasTransientVariable() const { + for (auto const& variable : variables) { + if (variable->isTransient()) { + return true; + } + } + return false; + } + bool VariableSet::containsBooleanVariable() const { return !booleanVariables.empty(); } @@ -176,7 +185,7 @@ namespace storm { bool VariableSet::containsNonTransientRealVariables() const { for (auto const& variable : realVariables) { - if (!variable->isTransientVariable()) { + if (!variable->isTransient()) { std::cout << "var " << variable->getName() << "is non-transient " << std::endl; return true; } diff --git a/src/storage/jani/VariableSet.h b/src/storage/jani/VariableSet.h index 4156faec1..777292ba9 100644 --- a/src/storage/jani/VariableSet.h +++ b/src/storage/jani/VariableSet.h @@ -148,6 +148,11 @@ namespace storm { */ Variable const& getVariable(storm::expressions::Variable const& variable) const; + /*! + * Retrieves whether this variable set contains a transient variable. + */ + bool hasTransientVariable() const; + /*! * Retrieves an iterator to the variables in this set. */ From 2182beefcb019c4f82de813e6316fdf9b7bf2f22 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Thu, 8 Sep 2016 16:39:49 +0200 Subject: [PATCH 26/34] created storage class for JANI assignments that guarantees ordering Former-commit-id: 6cc43016a2605fbca29d4aef23f45b57faf1b9f8 [formerly aaa7b8a2131669ab8686ad68a740f829bfc4dfb2] Former-commit-id: 8eb1c8d54d417c3416fcc9ed88d68d6629c9bcbc --- src/adapters/DereferenceIteratorAdapter.h | 46 +++ src/generator/JaniNextStateGenerator.cpp | 10 +- src/generator/PrismNextStateGenerator.cpp | 3 +- src/storage/jani/Assignment.cpp | 31 +- src/storage/jani/Assignment.h | 22 +- src/storage/jani/Edge.cpp | 14 +- src/storage/jani/Edge.h | 23 +- src/storage/jani/EdgeDestination.cpp | 100 +---- src/storage/jani/EdgeDestination.h | 61 +-- src/storage/jani/Exporter.cpp | 438 ---------------------- src/storage/jani/Exporter.h | 48 --- src/storage/jani/Location.cpp | 14 +- src/storage/jani/Location.h | 8 +- src/storage/jani/OrderedAssignments.cpp | 116 ++++++ src/storage/jani/OrderedAssignments.h | 91 +++++ src/storage/jani/VariableSet.cpp | 90 ++--- src/storage/jani/VariableSet.h | 72 ++-- 17 files changed, 403 insertions(+), 784 deletions(-) create mode 100644 src/adapters/DereferenceIteratorAdapter.h delete mode 100644 src/storage/jani/Exporter.cpp delete mode 100644 src/storage/jani/Exporter.h create mode 100644 src/storage/jani/OrderedAssignments.cpp create mode 100644 src/storage/jani/OrderedAssignments.h diff --git a/src/adapters/DereferenceIteratorAdapter.h b/src/adapters/DereferenceIteratorAdapter.h new file mode 100644 index 000000000..ef1ab683d --- /dev/null +++ b/src/adapters/DereferenceIteratorAdapter.h @@ -0,0 +1,46 @@ +#pragma once + +#include <type_traits> + +#include <boost/iterator/transform_iterator.hpp> + +namespace storm { + namespace adapters { + + template<typename T> + struct Dereferencer { + decltype((*std::declval<T>())) operator()(T const& t) const { + return *t; + } + }; + + template<typename ContainerType> + class DereferenceIteratorAdapter { + public: + typedef typename ContainerType::value_type value_type; + typedef typename std::conditional<std::is_const<ContainerType>::value, typename ContainerType::const_iterator, typename ContainerType::iterator>::type input_iterator; + typedef typename boost::transform_iterator<Dereferencer<value_type>, input_iterator> iterator; + + DereferenceIteratorAdapter(input_iterator it, input_iterator ite) : it(it), ite(ite) { + // Intentionally left empty. + } + + iterator begin() { + return boost::make_transform_iterator(it, Dereferencer<value_type>()); + } + + iterator end() { + return boost::make_transform_iterator(ite, Dereferencer<value_type>()); + } + + static iterator make_iterator(input_iterator it) { + return boost::make_transform_iterator(it, Dereferencer<value_type>()); + } + + private: + input_iterator it; + input_iterator ite; + }; + + } +} \ No newline at end of file diff --git a/src/generator/JaniNextStateGenerator.cpp b/src/generator/JaniNextStateGenerator.cpp index f6dbfa618..510abbf5a 100644 --- a/src/generator/JaniNextStateGenerator.cpp +++ b/src/generator/JaniNextStateGenerator.cpp @@ -34,22 +34,22 @@ namespace storm { } } } else { + auto const& globalVariables = model.getGlobalVariables(); + // Extract the reward models from the program based on the names we were given. for (auto const& rewardModelName : this->options.getRewardModelNames()) { - auto const& globalVariables = model.getGlobalVariables(); if (globalVariables.hasVariable(rewardModelName)) { rewardVariables.push_back(globalVariables.getVariable(rewardModelName).getExpressionVariable()); } else { STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException, "Cannot build unknown reward model '" << rewardModelName << "'."); STORM_LOG_THROW(globalVariables.getNumberOfTransientVariables() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous."); - STORM_LOG_THROW(this->program.getNumberOfRewardModels() > 0, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is invalid, because there is no reward model."); } } - // If no reward model was yet added, but there was one that was given in the options, we try to build + // If no reward model was yet added, but there was one that was given in the options, we try to build the // standard reward model. - if (rewardModels.empty() && !this->options.getRewardModelNames().empty()) { - rewardModels.push_back(this->program.getRewardModel(0)); + if (rewardVariables.empty() && !this->options.getRewardModelNames().empty()) { + rewardVariables.push_back(globalVariables.getTransientVariables().front()->getExpressionVariable()); } } diff --git a/src/generator/PrismNextStateGenerator.cpp b/src/generator/PrismNextStateGenerator.cpp index 6e1aeafdb..1ecbec2ab 100644 --- a/src/generator/PrismNextStateGenerator.cpp +++ b/src/generator/PrismNextStateGenerator.cpp @@ -42,11 +42,10 @@ namespace storm { } else { STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException, "Cannot build unknown reward model '" << rewardModelName << "'."); STORM_LOG_THROW(this->program.getNumberOfRewardModels() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous."); - STORM_LOG_THROW(this->program.getNumberOfRewardModels() > 0, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is invalid, because there is no reward model."); } } - // If no reward model was yet added, but there was one that was given in the options, we try to build + // If no reward model was yet added, but there was one that was given in the options, we try to build the // standard reward model. if (rewardModels.empty() && !this->options.getRewardModelNames().empty()) { rewardModels.push_back(this->program.getRewardModel(0)); diff --git a/src/storage/jani/Assignment.cpp b/src/storage/jani/Assignment.cpp index 0e1720a8d..ddf65afe4 100644 --- a/src/storage/jani/Assignment.cpp +++ b/src/storage/jani/Assignment.cpp @@ -1,14 +1,18 @@ #include "src/storage/jani/Assignment.h" +#include "src/utility/macros.h" +#include "src/exceptions/NotImplementedException.h" + namespace storm { namespace jani { - Assignment::Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression) : variable(variable), expression(expression) { - // Intentionally left empty. + Assignment::Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression, uint64_t level) : variable(variable), expression(expression), level(level) { + STORM_LOG_THROW(level == 0, storm::exceptions::NotImplementedException, "Assignment levels other than 0 are currently not supported."); } bool Assignment::operator==(Assignment const& other) const { - return this->isTransientAssignment() == other.isTransientAssignment() && this->getExpressionVariable() == other.getExpressionVariable() && this->getAssignedExpression().isSyntacticallyEqual(other.getAssignedExpression()); + // FIXME: the level is currently ignored as we do not support it + return this->isTransient() == other.isTransient() && this->getExpressionVariable() == other.getExpressionVariable() && this->getAssignedExpression().isSyntacticallyEqual(other.getAssignedExpression()); } storm::jani::Variable const& Assignment::getVariable() const { @@ -27,7 +31,7 @@ namespace storm { this->expression = expression; } - bool Assignment::isTransientAssignment() const { + bool Assignment::isTransient() const { return this->variable.get().isTransient(); } @@ -35,10 +39,29 @@ namespace storm { this->setAssignedExpression(this->getAssignedExpression().substitute(substitution)); } + uint64_t Assignment::getLevel() const { + return level; + } + std::ostream& operator<<(std::ostream& stream, Assignment const& assignment) { stream << assignment.getVariable().getName() << " := " << assignment.getAssignedExpression(); return stream; } + bool AssignmentPartialOrderByVariable::operator()(Assignment const& left, Assignment const& right) const { + return left.getExpressionVariable() < right.getExpressionVariable(); + } + + bool AssignmentPartialOrderByVariable::operator()(Assignment const& left, std::shared_ptr<Assignment> const& right) const { + return left.getExpressionVariable() < right->getExpressionVariable(); + } + + bool AssignmentPartialOrderByVariable::operator()(std::shared_ptr<Assignment> const& left, std::shared_ptr<Assignment> const& right) const { + return left->getExpressionVariable() < right->getExpressionVariable(); + } + + bool AssignmentPartialOrderByVariable::operator()(std::shared_ptr<Assignment> const& left, Assignment const& right) const { + return left->getExpressionVariable() < right.getExpressionVariable(); + } } } \ No newline at end of file diff --git a/src/storage/jani/Assignment.h b/src/storage/jani/Assignment.h index 24cc9d10c..030c1f68f 100644 --- a/src/storage/jani/Assignment.h +++ b/src/storage/jani/Assignment.h @@ -13,7 +13,7 @@ namespace storm { /*! * Creates an assignment of the given expression to the given variable. */ - Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression); + Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression, uint64_t index = 0); bool operator==(Assignment const& other) const; @@ -45,7 +45,12 @@ namespace storm { /** * Retrieves whether the assignment assigns to a transient variable. */ - bool isTransientAssignment() const; + bool isTransient() const; + + /*! + * Retrieves the level of the assignment. + */ + uint64_t getLevel() const; friend std::ostream& operator<<(std::ostream& stream, Assignment const& assignment); @@ -55,7 +60,20 @@ namespace storm { // The expression that is being assigned to the variable. storm::expressions::Expression expression; + + // The level of the assignment. + uint64_t level; }; + /*! + * This functor enables ordering the assignments by variable. Note that this is a partial order. + */ + struct AssignmentPartialOrderByVariable { + bool operator()(Assignment const& left, Assignment const& right) const; + bool operator()(Assignment const& left, std::shared_ptr<Assignment> const& right) const; + bool operator()(std::shared_ptr<Assignment> const& left, std::shared_ptr<Assignment> const& right) const; + bool operator()(std::shared_ptr<Assignment> const& left, Assignment const& right) const; + }; + } } \ No newline at end of file diff --git a/src/storage/jani/Edge.cpp b/src/storage/jani/Edge.cpp index e1ac1a274..90b03fa16 100644 --- a/src/storage/jani/Edge.cpp +++ b/src/storage/jani/Edge.cpp @@ -2,6 +2,9 @@ #include "src/storage/jani/Model.h" +#include "src/utility/macros.h" +#include "src/exceptions/InvalidArgumentException.h" + namespace storm { namespace jani { @@ -49,11 +52,7 @@ namespace storm { destinations.push_back(destination); } - std::vector<Assignment>& Edge::getTransientAssignments() { - return transientAssignments; - } - - std::vector<Assignment> const& Edge::getTransientAssignments() const { + OrderedAssignments const& Edge::getTransientAssignments() const { return transientAssignments; } @@ -80,8 +79,9 @@ namespace storm { } } - void Edge::addTransientAssignment(Assignment const& assignment) { - transientAssignments.push_back(assignment); + bool Edge::addTransientAssignment(Assignment const& assignment) { + STORM_LOG_THROW(assignment.isTransient(), storm::exceptions::InvalidArgumentException, "Must not add non-transient assignment to location."); + return transientAssignments.add(assignment); } void Edge::liftTransientDestinationAssignments() { diff --git a/src/storage/jani/Edge.h b/src/storage/jani/Edge.h index 47358bb05..4e64b1b7f 100644 --- a/src/storage/jani/Edge.h +++ b/src/storage/jani/Edge.h @@ -4,6 +4,7 @@ #include <boost/container/flat_set.hpp> #include "src/storage/jani/EdgeDestination.h" +#include "src/storage/jani/OrderedAssignments.h" namespace storm { namespace jani { @@ -64,16 +65,6 @@ namespace storm { */ void addDestination(EdgeDestination const& destination); - /*! - * Retrieves the transient assignments of this edge. - */ - std::vector<Assignment>& getTransientAssignments(); - - /*! - * Retrieves the transient assignments of this edge. - */ - std::vector<Assignment> const& getTransientAssignments() const; - /*! * Substitutes all variables in all expressions according to the given substitution. */ @@ -90,14 +81,20 @@ namespace storm { * that prior to calling this, the edge has to be finalized. */ boost::container::flat_set<storm::expressions::Variable> const& getWrittenGlobalVariables() const; - + /*! * Adds a transient assignment to this edge. * * @param assignment The transient assignment to add. + * @return True if the assignment was added. */ - void addTransientAssignment(Assignment const& assignment); + bool addTransientAssignment(Assignment const& assignment); + /*! + * Retrieves the transient assignments of this edge. + */ + OrderedAssignments const& getTransientAssignments() const; + /*! * Finds the transient assignments common to all destinations and lifts them to the edge. Afterwards, these * assignments are no longer contained in the destination. @@ -122,7 +119,7 @@ namespace storm { std::vector<EdgeDestination> destinations; /// The transient assignments made when taking this edge. - std::vector<Assignment> transientAssignments; + OrderedAssignments transientAssignments; /// A set of global variables that is written by at least one of the edge's destinations. This set is /// initialized by the call to <code>finalize</code>. diff --git a/src/storage/jani/EdgeDestination.cpp b/src/storage/jani/EdgeDestination.cpp index c59018e38..c20a5d520 100644 --- a/src/storage/jani/EdgeDestination.cpp +++ b/src/storage/jani/EdgeDestination.cpp @@ -7,33 +7,11 @@ namespace storm { namespace jani { EdgeDestination::EdgeDestination(uint64_t locationIndex, storm::expressions::Expression const& probability, std::vector<Assignment> const& assignments) : locationIndex(locationIndex), probability(probability), assignments(assignments) { - for (auto const& assignment : assignments) { - if (assignment.isTransientAssignment()) { - transientAssignments.push_back(assignment); - } else { - nonTransientAssignments.push_back(assignment); - } - } - sortAssignments(this->assignments); - sortAssignments(transientAssignments); - sortAssignments(nonTransientAssignments); + // Intentionally left empty. } void EdgeDestination::addAssignment(Assignment const& assignment) { - // We make sure that there are no two assignments to the same variable. - for (auto const& oldAssignment : assignments) { - STORM_LOG_THROW(oldAssignment.getExpressionVariable() != assignment.getExpressionVariable(), storm::exceptions::WrongFormatException, "Cannot add assignment '" << assignment << "', because another assignment '" << assignment << "' writes to the same target variable."); - } - assignments.push_back(assignment); - sortAssignments(assignments); - - if (assignment.isTransientAssignment()) { - transientAssignments.push_back(assignment); - sortAssignments(transientAssignments); - } else { - nonTransientAssignments.push_back(assignment); - sortAssignments(nonTransientAssignments); - } + assignments.add(assignment); } uint64_t EdgeDestination::getLocationIndex() const { @@ -48,84 +26,30 @@ namespace storm { this->probability = probability; } - std::vector<Assignment>& EdgeDestination::getAssignments() { - return assignments; + storm::jani::detail::ConstAssignments EdgeDestination::getAssignments() const { + return assignments.getAllAssignments(); } - - std::vector<Assignment> const& EdgeDestination::getAssignments() const { - return assignments; - } - - std::vector<Assignment>& EdgeDestination::getNonTransientAssignments() { - return nonTransientAssignments; - } - - std::vector<Assignment> const& EdgeDestination::getNonTransientAssignments() const { - return nonTransientAssignments; - } - - std::vector<Assignment>& EdgeDestination::getTransientAssignments() { - return transientAssignments; + + storm::jani::detail::ConstAssignments EdgeDestination::getTransientAssignments() const { + return assignments.getTransientAssignments(); } - std::vector<Assignment> const& EdgeDestination::getTransientAssignments() const { - return transientAssignments; + storm::jani::detail::ConstAssignments EdgeDestination::getNonTransientAssignments() const { + return assignments.getNonTransientAssignments(); } void EdgeDestination::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) { this->setProbability(this->getProbability().substitute(substitution)); - for (auto& assignment : this->getAssignments()) { - assignment.substitute(substitution); - } - for (auto& assignment : this->getTransientAssignments()) { - assignment.substitute(substitution); - } - for (auto& assignment : this->getNonTransientAssignments()) { - assignment.substitute(substitution); - } + assignments.substitute(substitution); } bool EdgeDestination::hasAssignment(Assignment const& assignment) const { - for (auto const& containedAssignment : assignments) { - if (containedAssignment == assignment) { - return true; - } - } - return false; + return assignments.contains(assignment); } bool EdgeDestination::removeAssignment(Assignment const& assignment) { - bool toRemove = removeAssignment(assignment, assignments); - if (toRemove) { - if (assignment.isTransientAssignment()) { - removeAssignment(assignment, transientAssignments); - } else { - removeAssignment(assignment, nonTransientAssignments); - } - return true; - } - return false; - } - - void EdgeDestination::sortAssignments(std::vector<Assignment>& assignments) { - std::sort(assignments.begin(), assignments.end(), [] (storm::jani::Assignment const& assignment1, storm::jani::Assignment const& assignment2) { - bool smaller = assignment1.getExpressionVariable().getType().isBooleanType() && !assignment2.getExpressionVariable().getType().isBooleanType(); - if (!smaller) { - smaller = assignment1.getExpressionVariable() < assignment2.getExpressionVariable(); - } - return smaller; - }); + return assignments.remove(assignment); } - bool EdgeDestination::removeAssignment(Assignment const& assignment, std::vector<Assignment>& assignments) { - for (auto it = assignments.begin(), ite = assignments.end(); it != ite; ++it) { - if (assignment == *it) { - assignments.erase(it); - return true; - } - } - return false; - } - } } \ No newline at end of file diff --git a/src/storage/jani/EdgeDestination.h b/src/storage/jani/EdgeDestination.h index 02da155e1..a7e3fb672 100644 --- a/src/storage/jani/EdgeDestination.h +++ b/src/storage/jani/EdgeDestination.h @@ -4,7 +4,7 @@ #include "src/storage/expressions/Expression.h" -#include "src/storage/jani/Assignment.h" +#include "src/storage/jani/OrderedAssignments.h" namespace storm { namespace jani { @@ -39,81 +39,36 @@ namespace storm { /*! * Retrieves the assignments to make when choosing this destination. */ - std::vector<Assignment>& getAssignments(); + storm::jani::detail::ConstAssignments getAssignments() const; /*! - * Retrieves the assignments to make when choosing this destination. - */ - std::vector<Assignment> const& getAssignments() const; - - /*! - * Retrieves the non-transient assignments to make when choosing this destination. - */ - std::vector<Assignment>& getNonTransientAssignments(); - - /*! - * Retrieves the non-transient assignments to make when choosing this destination. + * Retrieves the transient assignments to make when choosing this destination. */ - std::vector<Assignment> const& getNonTransientAssignments() const; + storm::jani::detail::ConstAssignments getTransientAssignments() const; /*! * Retrieves the non-transient assignments to make when choosing this destination. */ - std::vector<Assignment>& getTransientAssignments(); - - /*! - * Retrieves the non-transient assignments to make when choosing this destination. - */ - std::vector<Assignment> const& getTransientAssignments() const; + storm::jani::detail::ConstAssignments getNonTransientAssignments() const; /*! * Substitutes all variables in all expressions according to the given substitution. */ void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution); - /*! - * Retrieves whether this assignment is made when choosing this destination. - * - * @return True iff the assignment is made. - */ + // Convenience methods to access the assignments. bool hasAssignment(Assignment const& assignment) const; - - /*! - * Removes the given assignment from this destination. - * - * @return True if the assignment was found and removed. - */ bool removeAssignment(Assignment const& assignment); private: - /*! - * Sorts the assignments to make all assignments to boolean variables precede all others and order the - * assignments within one variable group by the expression variables. - */ - static void sortAssignments(std::vector<Assignment>& assignments); - - /*! - * Removes the given assignment from the provided list of assignments if found. - * - * @return True if the assignment was removed. - */ - static bool removeAssignment(Assignment const& assignment, std::vector<Assignment>& assignments); - // The index of the destination location. uint64_t locationIndex; // The probability to go to the destination. storm::expressions::Expression probability; - // The assignments to make when choosing this destination. - std::vector<Assignment> assignments; - - // The assignments to make when choosing this destination. - std::vector<Assignment> nonTransientAssignments; - - // The assignments to make when choosing this destination. - std::vector<Assignment> transientAssignments; - + // The (ordered) assignments to make when choosing this destination. + OrderedAssignments assignments; }; } diff --git a/src/storage/jani/Exporter.cpp b/src/storage/jani/Exporter.cpp deleted file mode 100644 index 51635f10a..000000000 --- a/src/storage/jani/Exporter.cpp +++ /dev/null @@ -1,438 +0,0 @@ -#include "src/storage/jani/Exporter.h" - -#include <iostream> - -namespace storm { - namespace jani { - - void appendIndent(std::stringstream& out, uint64_t indent) { - for (uint64_t i = 0; i < indent; ++i) { - out << "\t"; - } - } - - void appendField(std::stringstream& out, std::string const& name) { - out << "\"" << name << "\": "; - } - - void appendValue(std::stringstream& out, std::string const& value) { - out << "\"" << value << "\""; - } - - void clearLine(std::stringstream& out) { - out << std::endl; - } - - std::string expressionToString(storm::expressions::Expression const& expression) { - std::stringstream s; - s << expression; - return s.str(); - } - - void Exporter::appendVersion(std::stringstream& out, uint64_t janiVersion, uint64_t indent) const { - appendIndent(out, indent); - appendField(out, "jani-version"); - } - - void Exporter::appendModelName(std::stringstream& out, std::string const& name, uint64_t indent) const { - appendIndent(out, indent); - appendField(out, "name"); - appendValue(out, name); - } - - void Exporter::appendModelType(std::stringstream& out, storm::jani::ModelType const& modelType, uint64_t indent) const { - appendIndent(out, indent); - appendField(out, "type"); - } - - void Exporter::appendAction(std::stringstream& out, storm::jani::Action const& action, uint64_t indent) const { - appendIndent(out, indent); - out << "{" << std::endl; - appendIndent(out, indent + 1); - appendField(out, "name"); - appendValue(out, action.getName()); - clearLine(out); - appendIndent(out, indent); - out << "}"; - } - - void Exporter::appendActions(std::stringstream& out, storm::jani::Model const& model, uint64_t indent) const { - appendIndent(out, indent); - appendField(out, "actions"); - out << " [" << std::endl; - - for (uint64_t index = 0; index < model.actions.size(); ++index) { - appendAction(out, model.actions[index], indent + 1); - if (index < model.actions.size() - 1) { - out << ","; - } - clearLine(out); - } - - appendIndent(out, indent); - out << "]"; - } - - void Exporter::appendVariable(std::stringstream& out, storm::jani::BooleanVariable const& variable, uint64_t indent) const { - appendIndent(out, indent); - out << "{"; - clearLine(out); - appendIndent(out, indent + 1); - appendField(out, "name"); - appendValue(out, variable.getName()); - out << ","; - clearLine(out); - appendIndent(out, indent + 1); - appendField(out, "type"); - appendValue(out, "bool"); - out << ","; - clearLine(out); - appendIndent(out, indent); - out << "}"; - } - - void Exporter::appendBoundedIntegerVariableType(std::stringstream& out, storm::jani::BoundedIntegerVariable const& variable, uint64_t indent) const { - out << " {"; - clearLine(out); - - appendIndent(out, indent); - appendField(out, "kind"); - appendValue(out, "bounded"); - clearLine(out); - - appendIndent(out, indent); - appendField(out, "base"); - appendValue(out, "int"); - clearLine(out); - - appendIndent(out, indent); - appendField(out, "lower-bound"); - appendValue(out, expressionToString(variable.getLowerBound())); - clearLine(out); - - appendIndent(out, indent); - appendField(out, "upper-bound"); - appendValue(out, expressionToString(variable.getLowerBound())); - clearLine(out); - - appendIndent(out, indent - 1); - out << "}"; - } - - void Exporter::appendVariable(std::stringstream& out, storm::jani::BoundedIntegerVariable const& variable, uint64_t indent) const { - appendIndent(out, indent); - out << "{"; - clearLine(out); - appendIndent(out, indent + 1); - appendField(out, "name"); - appendValue(out, variable.getName()); - out << ","; - clearLine(out); - appendIndent(out, indent + 1); - appendField(out, "type"); - appendBoundedIntegerVariableType(out, variable, indent + 2); - out << ","; - clearLine(out); - appendIndent(out, indent); - out << "}"; - } - - void Exporter::appendVariable(std::stringstream& out, storm::jani::UnboundedIntegerVariable const& variable, uint64_t indent) const { - appendIndent(out, indent); - out << "{"; - clearLine(out); - appendIndent(out, indent + 1); - appendField(out, "name"); - appendValue(out, variable.getName()); - out << ","; - clearLine(out); - appendIndent(out, indent + 1); - appendField(out, "type"); - appendValue(out, "int"); - out << ","; - clearLine(out); - appendIndent(out, indent); - out << "}"; - } - - void Exporter::appendVariables(std::stringstream& out, storm::jani::VariableSet const& variables, uint64_t indent) const { - appendIndent(out, indent); - appendField(out, "variables"); - out << " ["; - clearLine(out); - - for (auto const& variable : variables.getBooleanVariables()) { - appendVariable(out, variable, indent + 1); - clearLine(out); - } - for (auto const& variable : variables.getBoundedIntegerVariables()) { - appendVariable(out, variable, indent + 1); - clearLine(out); - } - for (auto const& variable : variables.getUnboundedIntegerVariables()) { - appendVariable(out, variable, indent + 1); - clearLine(out); - } - - appendIndent(out, indent); - out << "]"; - } - - void Exporter::appendLocation(std::stringstream& out, storm::jani::Location const& location, uint64_t indent) const { - appendIndent(out, indent); - out << "{"; - clearLine(out); - - appendIndent(out, indent + 1); - appendField(out, "name"); - appendValue(out, location.getName()); - clearLine(out); - - appendIndent(out, indent); - out << "}"; - } - - void Exporter::appendLocations(std::stringstream& out, storm::jani::Automaton const& automaton, uint64_t indent) const { - appendIndent(out, indent); - appendField(out, "locations"); - out << " ["; - clearLine(out); - - for (auto const& location : automaton.getLocations()) { - appendLocation(out, location, indent + 1); - out << ","; - clearLine(out); - } - - appendIndent(out, indent); - out << "]"; - } - - void Exporter::appendAssignment(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, storm::jani::Assignment const& assignment, uint64_t indent) const { - appendIndent(out, indent); - out << "{"; - clearLine(out); - - appendIndent(out, indent + 1); - appendField(out, "ref"); - storm::jani::Variable const& variable = model.getGlobalVariables().hasVariable(assignment.getExpressionVariable()) ? model.getGlobalVariables().getVariable(assignment.getExpressionVariable()) : automaton.getVariables().getVariable(assignment.getExpressionVariable()); - appendValue(out, variable.getName()); - out << ","; - clearLine(out); - - appendIndent(out, indent + 1); - appendField(out, "value"); - appendValue(out, expressionToString(assignment.getAssignedExpression())); - clearLine(out); - - appendIndent(out, indent); - out << "}"; - } - - void Exporter::appendEdgeDestination(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, storm::jani::EdgeDestination const& destination, uint64_t indent) const { - appendIndent(out, indent); - out << "{"; - clearLine(out); - - appendIndent(out, indent + 1); - appendField(out, "probability"); - appendValue(out, expressionToString(destination.getProbability())); - out << ","; - clearLine(out); - - appendIndent(out, indent + 1); - appendField(out, "location"); - appendValue(out, automaton.getLocation(destination.getLocationIndex()).getName()); - out << ","; - clearLine(out); - - appendIndent(out, indent + 1); - appendField(out, "assignments"); - out << " ["; - clearLine(out); - - for (uint64_t index = 0; index < destination.getAssignments().size(); ++index) { - appendAssignment(out, model, automaton, destination.getAssignments()[index], indent + 2); - if (index < destination.getAssignments().size() - 1) { - out << ","; - } - clearLine(out); - } - - appendIndent(out, indent + 1); - out << "]"; - clearLine(out); - - appendIndent(out, indent); - out << "}"; - clearLine(out); - } - - void Exporter::appendEdge(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, storm::jani::Edge const& edge, uint64_t indent) const { - appendIndent(out, indent); - out << "{"; - clearLine(out); - - appendIndent(out, indent + 1); - appendField(out, "location"); - appendValue(out, automaton.getLocation(edge.getSourceLocationIndex()).getName()); - out << ","; - clearLine(out); - - appendIndent(out, indent + 1); - appendField(out, "action"); - appendValue(out, model.getAction(edge.getActionIndex()).getName()); - out << ","; - clearLine(out); - - appendIndent(out, indent + 1); - appendField(out, "guard"); - appendValue(out, expressionToString(edge.getGuard())); - out << ","; - clearLine(out); - - appendIndent(out, indent + 1); - appendField(out, "destinations"); - out << " ["; - clearLine(out); - - for (auto const& destination : edge.getDestinations()) { - appendEdgeDestination(out, model, automaton, destination, indent + 2); - } - - appendIndent(out, indent + 1); - out << "]"; - clearLine(out); - - appendIndent(out, indent); - out << "}"; - } - - void Exporter::appendEdges(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, uint64_t indent) const { - appendIndent(out, indent); - appendField(out, "edges"); - out << " ["; - clearLine(out); - - for (uint64_t location = 0; location < automaton.getNumberOfLocations(); ++location) { - for (auto const& edge : automaton.getEdgesFromLocation(location)) { - appendEdge(out, model, automaton, edge, indent + 1); - out << ","; - clearLine(out); - } - } - - appendIndent(out, indent); - out << "]"; - clearLine(out); - } - - void Exporter::appendAutomaton(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, uint64_t indent) const { - appendIndent(out, indent); - out << "{"; - clearLine(out); - - appendIndent(out, indent + 1); - appendField(out, "name"); - appendValue(out, automaton.getName()); - clearLine(out); - appendVariables(out, automaton.getVariables(), indent + 1); - out << ","; - clearLine(out); - - appendLocations(out, automaton, indent + 1); - out << ","; - clearLine(out); - appendIndent(out, indent + 1); - appendField(out, "initial-locations"); - out << " ["; - clearLine(out); - for (auto const& index : automaton.getInitialLocationIndices()) { - appendIndent(out, indent + 2); - appendValue(out, automaton.getLocation(index).getName()); - clearLine(out); - } - appendIndent(out, indent + 1); - out << "]"; - clearLine(out); - if (automaton.hasInitialStatesRestriction()) { - appendIndent(out, indent + 1); - appendField(out, "initial-states"); - clearLine(out); - appendIndent(out, indent + 2); - out << "{"; - clearLine(out); - appendIndent(out, indent + 3); - appendField(out, "exp"); - appendValue(out, expressionToString(automaton.getInitialStatesExpression())); - clearLine(out); - appendIndent(out, indent + 2); - out << "}"; - clearLine(out); - } - - appendEdges(out, model, automaton, indent + 1); - - appendIndent(out, indent); - out << "}"; - } - - void Exporter::appendAutomata(std::stringstream& out, storm::jani::Model const& model, uint64_t indent) const { - appendIndent(out, indent); - appendField(out, "automata"); - out << " ["; - clearLine(out); - - for (uint64_t index = 0; index < model.automata.size(); ++index) { - appendAutomaton(out, model, model.automata[index], indent + 1); - if (index < model.automata.size() - 1) { - out << ","; - } - clearLine(out); - } - - appendIndent(out, indent); - out << "]"; - } - - std::string Exporter::toJaniString(storm::jani::Model const& model) const { - std::stringstream out; - - out << "{" << std::endl; - appendVersion(out, model.getJaniVersion(), 1); - out << ","; - clearLine(out); - appendModelName(out, model.getName(), 1); - out << ","; - clearLine(out); - appendModelType(out, model.getModelType(), 1); - out << ","; - clearLine(out); - appendActions(out, model, 1); - clearLine(out); - appendVariables(out, model.getGlobalVariables(), 1); - clearLine(out); - - appendIndent(out, 1); - appendField(out, "initial-states"); - clearLine(out); - appendIndent(out, 2); - out << "{"; - clearLine(out); - appendIndent(out, 3); - appendField(out, "exp"); - appendValue(out, expressionToString(model.getInitialStatesRestriction())); - clearLine(out); - appendIndent(out, 2); - out << "}"; - clearLine(out); - - appendAutomata(out, model, 1); - clearLine(out); - out << "}" << std::endl; - - return out.str(); - } - - } -} \ No newline at end of file diff --git a/src/storage/jani/Exporter.h b/src/storage/jani/Exporter.h deleted file mode 100644 index 7b0a1990b..000000000 --- a/src/storage/jani/Exporter.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include <sstream> -#include <cstdint> - -#include "src/storage/jani/Model.h" - -namespace storm { - namespace jani { - - class Exporter { - public: - Exporter() = default; - - std::string toJaniString(storm::jani::Model const& model) const; - - private: - void appendVersion(std::stringstream& out, uint64_t janiVersion, uint64_t indent) const; - - void appendModelName(std::stringstream& out, std::string const& name, uint64_t indent) const; - - void appendModelType(std::stringstream& out, storm::jani::ModelType const& modelType, uint64_t indent) const; - - void appendAction(std::stringstream& out, storm::jani::Action const& action, uint64_t indent) const; - - void appendActions(std::stringstream& out, storm::jani::Model const& model, uint64_t indent) const; - - void appendVariables(std::stringstream& out, storm::jani::VariableSet const& variables, uint64_t indent) const; - - void appendVariable(std::stringstream& out, storm::jani::BooleanVariable const& variable, uint64_t indent) const; - void appendVariable(std::stringstream& out, storm::jani::BoundedIntegerVariable const& variable, uint64_t indent) const; - void appendBoundedIntegerVariableType(std::stringstream& out, storm::jani::BoundedIntegerVariable const& variable, uint64_t indent) const; - void appendVariable(std::stringstream& out, storm::jani::UnboundedIntegerVariable const& variable, uint64_t indent) const; - - void appendAutomata(std::stringstream& out, storm::jani::Model const& model, uint64_t indent) const; - void appendAutomaton(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, uint64_t indent) const; - - void appendLocation(std::stringstream& out, storm::jani::Location const& location, uint64_t indent) const; - void appendLocations(std::stringstream& out, storm::jani::Automaton const& automaton, uint64_t indent) const; - - void appendAssignment(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, storm::jani::Assignment const& assignment, uint64_t indent) const; - void appendEdgeDestination(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, storm::jani::EdgeDestination const& destination, uint64_t indent) const; - void appendEdge(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, storm::jani::Edge const& edge, uint64_t indent) const; - void appendEdges(std::stringstream& out, storm::jani::Model const& model, storm::jani::Automaton const& automaton, uint64_t indent) const; - }; - - } -} \ No newline at end of file diff --git a/src/storage/jani/Location.cpp b/src/storage/jani/Location.cpp index 32d17531e..18e91f720 100644 --- a/src/storage/jani/Location.cpp +++ b/src/storage/jani/Location.cpp @@ -1,7 +1,8 @@ #include "src/storage/jani/Location.h" -#include "src/storage/jani/Assignment.h" -#include "src/exceptions/InvalidJaniException.h" + #include "src/utility/macros.h" +#include "src/exceptions/InvalidJaniException.h" +#include "src/exceptions/InvalidArgumentException.h" namespace storm { namespace jani { @@ -14,18 +15,17 @@ namespace storm { return name; } - std::vector<Assignment> const& Location::getTransientAssignments() const { + OrderedAssignments const& Location::getTransientAssignments() const { return transientAssignments; } void Location::addTransientAssignment(storm::jani::Assignment const& assignment) { - transientAssignments.push_back(assignment); + STORM_LOG_THROW(assignment.isTransient(), storm::exceptions::InvalidArgumentException, "Must not add non-transient assignment to location."); + transientAssignments.add(assignment); } void Location::checkValid() const { - for(auto const& assignment : transientAssignments) { - STORM_LOG_THROW(assignment.isTransientAssignment(), storm::exceptions::InvalidJaniException, "Only transient assignments are allowed in locations."); - } + // Intentionally left empty. } } diff --git a/src/storage/jani/Location.h b/src/storage/jani/Location.h index e80faedf9..050129972 100644 --- a/src/storage/jani/Location.h +++ b/src/storage/jani/Location.h @@ -1,8 +1,8 @@ #pragma once #include <string> -#include <vector> -#include "src/storage/jani/Assignment.h" + +#include "src/storage/jani/OrderedAssignments.h" namespace storm { namespace jani { @@ -27,7 +27,7 @@ namespace storm { /*! * Retrieves the transient assignments of this location. */ - std::vector<Assignment> const& getTransientAssignments() const; + OrderedAssignments const& getTransientAssignments() const; /*! * Adds the given transient assignment to this location. @@ -44,7 +44,7 @@ namespace storm { std::string name; /// The transient assignments made in this location. - std::vector<Assignment> transientAssignments; + OrderedAssignments transientAssignments; }; } diff --git a/src/storage/jani/OrderedAssignments.cpp b/src/storage/jani/OrderedAssignments.cpp new file mode 100644 index 000000000..2b7ee613f --- /dev/null +++ b/src/storage/jani/OrderedAssignments.cpp @@ -0,0 +1,116 @@ +#include "src/storage/jani/OrderedAssignments.h" + +#include "src/utility/macros.h" +#include "src/exceptions/InvalidArgumentException.h" + +namespace storm { + namespace jani { + + OrderedAssignments::OrderedAssignments(std::vector<Assignment> const& assignments) { + for (auto const& assignment : assignments) { + add(assignment); + } + } + + bool OrderedAssignments::add(Assignment const& assignment) { + // If the element is contained in this set of assignment, nothing needs to be added. + if (this->contains(assignment)) { + return false; + } + + // Otherwise, we find the spot to insert it. + auto it = lowerBound(assignment, allAssignments); + + if (it != allAssignments.end()) { + STORM_LOG_THROW(assignment.getExpressionVariable() != (*it)->getExpressionVariable(), storm::exceptions::InvalidArgumentException, "Cannot add assignment as an assignment to this variable already exists."); + } + + // Finally, insert the new element in the correct vectors. + auto elementToInsert = std::make_shared<Assignment>(assignment); + allAssignments.emplace(it, elementToInsert); + if (assignment.isTransient()) { + auto transientIt = lowerBound(assignment, transientAssignments); + transientAssignments.emplace(transientIt, elementToInsert); + } else { + auto nonTransientIt = lowerBound(assignment, nonTransientAssignments); + nonTransientAssignments.emplace(nonTransientIt, elementToInsert); + } + + return true; + } + + bool OrderedAssignments::remove(Assignment const& assignment) { + // If the element is contained in this set of assignment, nothing needs to be removed. + if (!this->contains(assignment)) { + return false; + } + + // Otherwise, we find the element to delete. + auto it = lowerBound(assignment, allAssignments); + STORM_LOG_ASSERT(it != allAssignments.end(), "Invalid iterator, expected existing element."); + STORM_LOG_ASSERT(assignment == **it, "Wrong iterator position."); + allAssignments.erase(it); + + if (assignment.isTransient()) { + auto transientIt = lowerBound(assignment, transientAssignments); + STORM_LOG_ASSERT(transientIt != transientAssignments.end(), "Invalid iterator, expected existing element."); + STORM_LOG_ASSERT(assignment == **transientIt, "Wrong iterator position."); + transientAssignments.erase(transientIt); + } else { + auto nonTransientIt = lowerBound(assignment, nonTransientAssignments); + STORM_LOG_ASSERT(nonTransientIt != nonTransientAssignments.end(), "Invalid iterator, expected existing element."); + STORM_LOG_ASSERT(assignment == **nonTransientIt, "Wrong iterator position."); + nonTransientAssignments.erase(nonTransientIt); + } + return true; + } + + bool OrderedAssignments::contains(Assignment const& assignment) const { + auto it = lowerBound(assignment, allAssignments); + if (it != allAssignments.end() && assignment == **it) { + return true; + } else { + return false; + } + } + + detail::ConstAssignments OrderedAssignments::getAllAssignments() const { + return detail::ConstAssignments(allAssignments.begin(), allAssignments.end()); + } + + detail::ConstAssignments OrderedAssignments::getTransientAssignments() const { + return detail::ConstAssignments(transientAssignments.begin(), transientAssignments.end()); + } + + detail::ConstAssignments OrderedAssignments::getNonTransientAssignments() const { + return detail::ConstAssignments(nonTransientAssignments.begin(), nonTransientAssignments.end()); + } + + detail::Assignments::iterator OrderedAssignments::begin() { + return detail::Assignments::make_iterator(allAssignments.begin()); + } + + detail::ConstAssignments::iterator OrderedAssignments::begin() const { + return detail::ConstAssignments::make_iterator(allAssignments.begin()); + } + + detail::Assignments::iterator OrderedAssignments::end() { + return detail::Assignments::make_iterator(allAssignments.end()); + } + + detail::ConstAssignments::iterator OrderedAssignments::end() const { + return detail::ConstAssignments::make_iterator(allAssignments.end()); + } + + void OrderedAssignments::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) { + for (auto& assignment : allAssignments) { + assignment->substitute(substitution); + } + } + + std::vector<std::shared_ptr<Assignment>>::const_iterator OrderedAssignments::lowerBound(Assignment const& assignment, std::vector<std::shared_ptr<Assignment>> const& assignments) { + return std::lower_bound(assignments.begin(), assignments.end(), assignment, storm::jani::AssignmentPartialOrderByVariable()); + } + + } +} \ No newline at end of file diff --git a/src/storage/jani/OrderedAssignments.h b/src/storage/jani/OrderedAssignments.h new file mode 100644 index 000000000..c9e07a34d --- /dev/null +++ b/src/storage/jani/OrderedAssignments.h @@ -0,0 +1,91 @@ +#pragma once + +#include "src/adapters/DereferenceIteratorAdapter.h" + +#include "src/storage/jani/Assignment.h" + +namespace storm { + namespace jani { + + namespace detail { + using Assignments = storm::adapters::DereferenceIteratorAdapter<std::vector<std::shared_ptr<Assignment>>>; + using ConstAssignments = storm::adapters::DereferenceIteratorAdapter<std::vector<std::shared_ptr<Assignment>> const>; + } + + class OrderedAssignments { + public: + /*! + * Creates an ordered set of assignments. + */ + OrderedAssignments(std::vector<Assignment> const& assignments = std::vector<Assignment>()); + + /*! + * Adds the given assignment to the set of assignments. + * + * @return True iff the assignment was added. + */ + bool add(Assignment const& assignment); + + /*! + * Removes the given assignment from this set of assignments. + * + * @return True if the assignment was found and removed. + */ + bool remove(Assignment const& assignment); + + /*! + * Retrieves whether the given assignment is contained in this set of assignments. + */ + bool contains(Assignment const& assignment) const; + + /*! + * Returns all assignments in this set of assignments. + */ + detail::ConstAssignments getAllAssignments() const; + + /*! + * Returns all transient assignments in this set of assignments. + */ + detail::ConstAssignments getTransientAssignments() const; + + /*! + * Returns all non-transient assignments in this set of assignments. + */ + detail::ConstAssignments getNonTransientAssignments() const; + + /*! + * Returns an iterator to the assignments. + */ + detail::Assignments::iterator begin(); + + /*! + * Returns an iterator to the assignments. + */ + detail::ConstAssignments::iterator begin() const; + + /*! + * Returns an iterator past the end of the assignments. + */ + detail::Assignments::iterator end(); + + /*! + * Returns an iterator past the end of the assignments. + */ + detail::ConstAssignments::iterator end() const; + + /*! + * Substitutes all variables in all expressions according to the given substitution. + */ + void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution); + + private: + static std::vector<std::shared_ptr<Assignment>>::const_iterator lowerBound(Assignment const& assignment, std::vector<std::shared_ptr<Assignment>> const& assignments); + + // The vectors to store the assignments. These need to be ordered at all times. + std::vector<std::shared_ptr<Assignment>> allAssignments; + std::vector<std::shared_ptr<Assignment>> transientAssignments; + std::vector<std::shared_ptr<Assignment>> nonTransientAssignments; + }; + + } +} \ No newline at end of file diff --git a/src/storage/jani/VariableSet.cpp b/src/storage/jani/VariableSet.cpp index c138686e8..4caae4269 100644 --- a/src/storage/jani/VariableSet.cpp +++ b/src/storage/jani/VariableSet.cpp @@ -6,46 +6,7 @@ namespace storm { namespace jani { - - namespace detail { - - template<typename VariableType> - VariableType& Dereferencer<VariableType>::operator()(std::shared_ptr<VariableType> const& d) const { - return *d; - } - - template<typename VariableType> - Variables<VariableType>::Variables(input_iterator it, input_iterator ite) : it(it), ite(ite) { - // Intentionally left empty. - } - template<typename VariableType> - typename Variables<VariableType>::iterator Variables<VariableType>::begin() { - return boost::make_transform_iterator(it, Dereferencer<VariableType>()); - } - - template<typename VariableType> - typename Variables<VariableType>::iterator Variables<VariableType>::end() { - return boost::make_transform_iterator(ite, Dereferencer<VariableType>()); - } - - template<typename VariableType> - ConstVariables<VariableType>::ConstVariables(const_input_iterator it, const_input_iterator ite) : it(it), ite(ite) { - // Intentionally left empty. - } - - template<typename VariableType> - typename ConstVariables<VariableType>::const_iterator ConstVariables<VariableType>::begin() { - return boost::make_transform_iterator(it, Dereferencer<VariableType const>()); - } - - template<typename VariableType> - typename ConstVariables<VariableType>::const_iterator ConstVariables<VariableType>::end() { - return boost::make_transform_iterator(ite, Dereferencer<VariableType const>()); - } - - } - VariableSet::VariableSet() { // Intentionally left empty. } @@ -132,20 +93,20 @@ namespace storm { return getVariable(it->second); } - VariableSet::iterator VariableSet::begin() { - return boost::make_transform_iterator(variables.begin(), detail::Dereferencer<Variable>()); + typename detail::Variables<Variable>::iterator VariableSet::begin() { + return detail::Variables<Variable>::make_iterator(variables.begin()); } - VariableSet::const_iterator VariableSet::begin() const { - return boost::make_transform_iterator(variables.begin(), detail::Dereferencer<Variable const>()); + typename detail::ConstVariables<Variable>::iterator VariableSet::begin() const { + return detail::ConstVariables<Variable>::make_iterator(variables.begin()); } - VariableSet::iterator VariableSet::end() { - return boost::make_transform_iterator(variables.end(), detail::Dereferencer<Variable>()); + typename detail::Variables<Variable>::iterator VariableSet::end() { + return detail::Variables<Variable>::make_iterator(variables.end()); } - VariableSet::const_iterator VariableSet::end() const { - return boost::make_transform_iterator(variables.end(), detail::Dereferencer<Variable const>()); + detail::ConstVariables<Variable>::iterator VariableSet::end() const { + return detail::ConstVariables<Variable>::make_iterator(variables.end()); } Variable const& VariableSet::getVariable(storm::expressions::Variable const& variable) const { @@ -197,20 +158,25 @@ namespace storm { return !(containsBooleanVariable() || containsBoundedIntegerVariable() || containsUnboundedIntegerVariables()); } - template class detail::Dereferencer<Variable>; - template class detail::Dereferencer<BooleanVariable>; - template class detail::Dereferencer<BoundedIntegerVariable>; - template class detail::Dereferencer<UnboundedIntegerVariable>; - template class detail::Dereferencer<Variable const>; - template class detail::Dereferencer<BooleanVariable const>; - template class detail::Dereferencer<BoundedIntegerVariable const>; - template class detail::Dereferencer<UnboundedIntegerVariable const>; - template class detail::Variables<BooleanVariable>; - template class detail::Variables<BoundedIntegerVariable>; - template class detail::Variables<UnboundedIntegerVariable>; - template class detail::ConstVariables<BooleanVariable>; - template class detail::ConstVariables<BoundedIntegerVariable>; - template class detail::ConstVariables<UnboundedIntegerVariable>; - + uint_fast64_t VariableSet::getNumberOfTransientVariables() const { + uint_fast64_t result = 0; + for (auto const& variable : variables) { + if (variable->isTransient()) { + ++result; + } + } + return result; + } + + std::vector<std::shared_ptr<Variable const>> VariableSet::getTransientVariables() const { + std::vector<std::shared_ptr<Variable const>> result; + for (auto const& variable : variables) { + if (variable->isTransient()) { + result.push_back(variable); + } + } + return result; + } + } } diff --git a/src/storage/jani/VariableSet.h b/src/storage/jani/VariableSet.h index 777292ba9..78275de0b 100644 --- a/src/storage/jani/VariableSet.h +++ b/src/storage/jani/VariableSet.h @@ -3,7 +3,7 @@ #include <vector> #include <set> -#include <boost/iterator/transform_iterator.hpp> +#include "src/adapters/DereferenceIteratorAdapter.h" #include "src/storage/jani/BooleanVariable.h" #include "src/storage/jani/UnboundedIntegerVariable.h" @@ -12,57 +12,17 @@ namespace storm { namespace jani { - - class VariableSet; - - namespace detail { - - template<typename VariableType> - class Dereferencer { - public: - VariableType& operator()(std::shared_ptr<VariableType> const& d) const; - }; - - template<typename VariableType> - class Variables { - public: - typedef typename std::vector<std::shared_ptr<VariableType>>::iterator input_iterator; - typedef boost::transform_iterator<Dereferencer<VariableType>, input_iterator> iterator; - - Variables(input_iterator it, input_iterator ite); - - iterator begin(); - iterator end(); - - private: - input_iterator it; - input_iterator ite; - }; - - template<typename VariableType> - class ConstVariables { - public: - typedef typename std::vector<std::shared_ptr<VariableType>>::const_iterator const_input_iterator; - typedef boost::transform_iterator<Dereferencer<VariableType const>, const_input_iterator> const_iterator; - - ConstVariables(const_input_iterator it, const_input_iterator ite); - - const_iterator begin(); - const_iterator end(); - private: - const_input_iterator it; - const_input_iterator ite; - }; + namespace detail { + template <typename VariableType> + using Variables = storm::adapters::DereferenceIteratorAdapter<std::vector<std::shared_ptr<VariableType>>>; + + template <typename VariableType> + using ConstVariables = storm::adapters::DereferenceIteratorAdapter<std::vector<std::shared_ptr<VariableType>> const>; } class VariableSet { public: - typedef typename std::vector<std::shared_ptr<Variable>>::iterator input_iterator; - typedef typename std::vector<std::shared_ptr<Variable>>::const_iterator const_input_iterator; - typedef boost::transform_iterator<detail::Dereferencer<Variable>, input_iterator> iterator; - typedef boost::transform_iterator<detail::Dereferencer<Variable const>, const_input_iterator> const_iterator; - /*! * Creates an empty variable set. */ @@ -156,22 +116,22 @@ namespace storm { /*! * Retrieves an iterator to the variables in this set. */ - iterator begin(); + typename detail::Variables<Variable>::iterator begin(); /*! * Retrieves an iterator to the variables in this set. */ - const_iterator begin() const; + typename detail::ConstVariables<Variable>::iterator begin() const; /*! * Retrieves the end iterator to the variables in this set. */ - iterator end(); + typename detail::Variables<Variable>::iterator end(); /*! * Retrieves the end iterator to the variables in this set. */ - const_iterator end() const; + typename detail::ConstVariables<Variable>::iterator end() const; /*! * Retrieves whether the set of variables contains a boolean variable. @@ -203,6 +163,16 @@ namespace storm { */ bool empty() const; + /*! + * Retrieves the number of transient variables in this variable set. + */ + uint_fast64_t getNumberOfTransientVariables() const; + + /*! + * Retrieves a vector of transient variables in this variable set. + */ + std::vector<std::shared_ptr<Variable const>> getTransientVariables() const; + private: /// The vector of all variables. std::vector<std::shared_ptr<Variable>> variables; From 23809f54f1ec8707faaa98158070ce91fb427033 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 9 Sep 2016 14:39:49 +0200 Subject: [PATCH 27/34] first version of rewards for JANI models (explicit next-state generator only) Former-commit-id: b2b063842714695d96197d1d29ece78621ff6528 [formerly c763581e068072e8ea5ab9a6686ce04c74332a74] Former-commit-id: a032da1cff90c7bef6e172dbf350f40d49d4e777 --- src/adapters/DereferenceIteratorAdapter.h | 4 +- src/generator/JaniNextStateGenerator.cpp | 47 ++++++++++++++++++----- src/generator/JaniNextStateGenerator.h | 6 +++ src/generator/StateBehavior.cpp | 5 +++ src/generator/StateBehavior.h | 7 +++- src/storage/SymbolicModelDescription.cpp | 9 +++++ src/storage/SymbolicModelDescription.h | 14 +++++++ src/storage/jani/Edge.cpp | 10 ++--- src/storage/jani/Edge.h | 8 ++-- src/storage/jani/Location.cpp | 8 ++-- src/storage/jani/Location.h | 6 +-- 11 files changed, 96 insertions(+), 28 deletions(-) create mode 100644 src/storage/SymbolicModelDescription.cpp create mode 100644 src/storage/SymbolicModelDescription.h diff --git a/src/adapters/DereferenceIteratorAdapter.h b/src/adapters/DereferenceIteratorAdapter.h index ef1ab683d..16ac0834e 100644 --- a/src/adapters/DereferenceIteratorAdapter.h +++ b/src/adapters/DereferenceIteratorAdapter.h @@ -25,11 +25,11 @@ namespace storm { // Intentionally left empty. } - iterator begin() { + iterator begin() const { return boost::make_transform_iterator(it, Dereferencer<value_type>()); } - iterator end() { + iterator end() const { return boost::make_transform_iterator(ite, Dereferencer<value_type>()); } diff --git a/src/generator/JaniNextStateGenerator.cpp b/src/generator/JaniNextStateGenerator.cpp index 510abbf5a..859257931 100644 --- a/src/generator/JaniNextStateGenerator.cpp +++ b/src/generator/JaniNextStateGenerator.cpp @@ -52,7 +52,6 @@ namespace storm { rewardVariables.push_back(globalVariables.getTransientVariables().front()->getExpressionVariable()); } } - // If there are terminal states we need to handle, we now need to translate all labels to expressions. if (this->options.hasTerminalStates()) { @@ -202,11 +201,6 @@ namespace storm { CompressedState JaniNextStateGenerator<ValueType, StateType>::applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& destination) { CompressedState newState(state); - // NOTE: the following process assumes that the assignments of the destination are ordered in such a way - // that the assignments to boolean variables precede the assignments to all integer variables and that - // within the types, the assignments to variables are ordered (in ascending order) by the expression variables. - // This is guaranteed for JANI models, by sorting the assignments as soon as an edge destination is created. - auto assignmentIt = destination.getNonTransientAssignments().begin(); auto assignmentIte = destination.getNonTransientAssignments().end(); @@ -242,6 +236,22 @@ namespace storm { // Prepare the result, in case we return early. StateBehavior<ValueType, StateType> result; + // Retrieve the locations from the state. + std::vector<uint64_t> locations = getLocations(*this->state); + + // First, construct the state rewards, as we may return early if there are no choices later and we already + // need the state rewards then. + std::vector<ValueType> stateRewards(this->rewardVariables.size(), storm::utility::zero<ValueType>()); + uint64_t automatonIndex = 0; + for (auto const& automaton : model.getAutomata()) { + uint64_t currentLocationIndex = locations[automatonIndex]; + storm::jani::Location const& location = automaton.getLocation(currentLocationIndex); + auto valueIt = stateRewards.begin(); + performTransientAssignments(location.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); + ++automatonIndex; + } + result.addStateRewards(std::move(stateRewards)); + // If a terminal expression was set and we must not expand this state, return now. if (!this->terminalStates.empty()) { for (auto const& expressionBool : this->terminalStates) { @@ -251,9 +261,6 @@ namespace storm { } } - // Retrieve the locations from the state. - std::vector<uint64_t> locations = getLocations(*this->state); - // Get all choices for the state. std::vector<Choice<ValueType>> allChoices = getSilentActionChoices(locations, *this->state, stateToIdCallback); std::vector<Choice<ValueType>> allLabeledChoices = getNonsilentActionChoices(locations, *this->state, stateToIdCallback); @@ -302,6 +309,25 @@ namespace storm { return result; } + template<typename ValueType, typename StateType> + void JaniNextStateGenerator<ValueType, StateType>::performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function<void (ValueType const&)> const& callback) { + auto rewardVariableIt = rewardVariables.begin(); + auto rewardVariableIte = rewardVariables.end(); + for (auto const& assignment : transientAssignments) { + while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) { + callback(storm::utility::zero<ValueType>()); + ++rewardVariableIt; + } + if (rewardVariableIt == rewardVariableIte) { + break; + } + if (*rewardVariableIt == assignment.getExpressionVariable()) { + callback(ValueType(this->evaluator.asRational(assignment.getAssignedExpression()))); + ++rewardVariableIt; + } + } + } + template<typename ValueType, typename StateType> std::vector<Choice<ValueType>> JaniNextStateGenerator<ValueType, StateType>::getSilentActionChoices(std::vector<uint64_t> const& locations, CompressedState const& state, StateToIdCallback stateToIdCallback) { std::vector<Choice<ValueType>> result; @@ -339,6 +365,9 @@ namespace storm { probabilitySum += probability; } + // Create the state-action reward for the newly created choice. + performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&choice] (ValueType const& value) { choice.addChoiceReward(value); } ); + // Check that the resulting distribution is in fact a distribution. STORM_LOG_THROW(!this->isDiscreteTimeModel() || this->comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Probabilities do not sum to one for edge (actually sum to " << probabilitySum << ")."); } diff --git a/src/generator/JaniNextStateGenerator.h b/src/generator/JaniNextStateGenerator.h index be6033ebc..f3202a569 100644 --- a/src/generator/JaniNextStateGenerator.h +++ b/src/generator/JaniNextStateGenerator.h @@ -89,6 +89,12 @@ namespace storm { */ void checkGlobalVariableWritesValid(std::vector<std::vector<storm::jani::Edge const*>> const& enabledEdges) const; + /*! + * Treats the given transient assignments by calling the callback function whenever a transient assignment + * to one of the reward variables of this generator is performed. + */ + void performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function<void (ValueType const&)> const& callback); + /// The model used for the generation of next states. storm::jani::Model model; diff --git a/src/generator/StateBehavior.cpp b/src/generator/StateBehavior.cpp index 4e71c537f..8ad2c1e91 100644 --- a/src/generator/StateBehavior.cpp +++ b/src/generator/StateBehavior.cpp @@ -20,6 +20,11 @@ namespace storm { stateRewards.push_back(stateReward); } + template<typename ValueType, typename StateType> + void StateBehavior<ValueType, StateType>::addStateRewards(std::vector<ValueType>&& stateRewards) { + this->stateRewards = std::move(stateRewards); + } + template<typename ValueType, typename StateType> void StateBehavior<ValueType, StateType>::setExpanded(bool newValue) { this->expanded = newValue; diff --git a/src/generator/StateBehavior.h b/src/generator/StateBehavior.h index 8f81c8b30..1082e9045 100644 --- a/src/generator/StateBehavior.h +++ b/src/generator/StateBehavior.h @@ -25,7 +25,12 @@ namespace storm { * Adds the given state reward to the behavior of the state. */ void addStateReward(ValueType const& stateReward); - + + /*! + * Adds the given state rewards to the behavior of the state. + */ + void addStateRewards(std::vector<ValueType>&& stateRewards); + /*! * Sets whether the state was expanded. */ diff --git a/src/storage/SymbolicModelDescription.cpp b/src/storage/SymbolicModelDescription.cpp new file mode 100644 index 000000000..9451c6a08 --- /dev/null +++ b/src/storage/SymbolicModelDescription.cpp @@ -0,0 +1,9 @@ +// +// SymbolicModelDescription.cpp +// storm +// +// Created by Christian Dehnert on 09/09/16. +// +// + +#include "SymbolicModelDescription.hpp" diff --git a/src/storage/SymbolicModelDescription.h b/src/storage/SymbolicModelDescription.h new file mode 100644 index 000000000..f73dce810 --- /dev/null +++ b/src/storage/SymbolicModelDescription.h @@ -0,0 +1,14 @@ +// +// SymbolicModelDescription.hpp +// storm +// +// Created by Christian Dehnert on 09/09/16. +// +// + +#ifndef SymbolicModelDescription_hpp +#define SymbolicModelDescription_hpp + +#include <stdio.h> + +#endif /* SymbolicModelDescription_hpp */ diff --git a/src/storage/jani/Edge.cpp b/src/storage/jani/Edge.cpp index 90b03fa16..0a06f50a8 100644 --- a/src/storage/jani/Edge.cpp +++ b/src/storage/jani/Edge.cpp @@ -8,7 +8,7 @@ namespace storm { namespace jani { - Edge::Edge(uint64_t sourceLocationIndex, uint64_t actionIndex, boost::optional<storm::expressions::Expression> const& rate, storm::expressions::Expression const& guard, std::vector<EdgeDestination> destinations) : sourceLocationIndex(sourceLocationIndex), actionIndex(actionIndex), rate(rate), guard(guard), destinations(destinations) { + Edge::Edge(uint64_t sourceLocationIndex, uint64_t actionIndex, boost::optional<storm::expressions::Expression> const& rate, storm::expressions::Expression const& guard, std::vector<EdgeDestination> destinations) : sourceLocationIndex(sourceLocationIndex), actionIndex(actionIndex), rate(rate), guard(guard), destinations(destinations), assignments(), writtenGlobalVariables() { // Intentionally left empty. } @@ -52,8 +52,8 @@ namespace storm { destinations.push_back(destination); } - OrderedAssignments const& Edge::getTransientAssignments() const { - return transientAssignments; + OrderedAssignments const& Edge::getAssignments() const { + return assignments; } void Edge::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) { @@ -61,7 +61,7 @@ namespace storm { if (this->hasRate()) { this->setRate(this->getRate().substitute(substitution)); } - for (auto& assignment : this->getTransientAssignments()) { + for (auto& assignment : this->getAssignments()) { assignment.substitute(substitution); } for (auto& destination : this->getDestinations()) { @@ -81,7 +81,7 @@ namespace storm { bool Edge::addTransientAssignment(Assignment const& assignment) { STORM_LOG_THROW(assignment.isTransient(), storm::exceptions::InvalidArgumentException, "Must not add non-transient assignment to location."); - return transientAssignments.add(assignment); + return assignments.add(assignment); } void Edge::liftTransientDestinationAssignments() { diff --git a/src/storage/jani/Edge.h b/src/storage/jani/Edge.h index 4e64b1b7f..6ce6ef127 100644 --- a/src/storage/jani/Edge.h +++ b/src/storage/jani/Edge.h @@ -91,9 +91,9 @@ namespace storm { bool addTransientAssignment(Assignment const& assignment); /*! - * Retrieves the transient assignments of this edge. + * Retrieves the assignments of this edge. */ - OrderedAssignments const& getTransientAssignments() const; + OrderedAssignments const& getAssignments() const; /*! * Finds the transient assignments common to all destinations and lifts them to the edge. Afterwards, these @@ -118,8 +118,8 @@ namespace storm { /// The destinations of this edge. std::vector<EdgeDestination> destinations; - /// The transient assignments made when taking this edge. - OrderedAssignments transientAssignments; + /// The assignments made when taking this edge. + OrderedAssignments assignments; /// A set of global variables that is written by at least one of the edge's destinations. This set is /// initialized by the call to <code>finalize</code>. diff --git a/src/storage/jani/Location.cpp b/src/storage/jani/Location.cpp index 18e91f720..4f09e4959 100644 --- a/src/storage/jani/Location.cpp +++ b/src/storage/jani/Location.cpp @@ -7,7 +7,7 @@ namespace storm { namespace jani { - Location::Location(std::string const& name, std::vector<Assignment> const& transientAssignments) : name(name), transientAssignments(transientAssignments) { + Location::Location(std::string const& name, std::vector<Assignment> const& transientAssignments) : name(name), assignments(transientAssignments) { // Intentionally left empty. } @@ -15,13 +15,13 @@ namespace storm { return name; } - OrderedAssignments const& Location::getTransientAssignments() const { - return transientAssignments; + OrderedAssignments const& Location::getAssignments() const { + return assignments; } void Location::addTransientAssignment(storm::jani::Assignment const& assignment) { STORM_LOG_THROW(assignment.isTransient(), storm::exceptions::InvalidArgumentException, "Must not add non-transient assignment to location."); - transientAssignments.add(assignment); + assignments.add(assignment); } void Location::checkValid() const { diff --git a/src/storage/jani/Location.h b/src/storage/jani/Location.h index 050129972..9de4b683f 100644 --- a/src/storage/jani/Location.h +++ b/src/storage/jani/Location.h @@ -25,9 +25,9 @@ namespace storm { std::string const& getName() const; /*! - * Retrieves the transient assignments of this location. + * Retrieves the assignments of this location. */ - OrderedAssignments const& getTransientAssignments() const; + OrderedAssignments const& getAssignments() const; /*! * Adds the given transient assignment to this location. @@ -44,7 +44,7 @@ namespace storm { std::string name; /// The transient assignments made in this location. - OrderedAssignments transientAssignments; + OrderedAssignments assignments; }; } From 7c9c55b09c90944efa6115199ad327ae217db629 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 9 Sep 2016 14:42:56 +0200 Subject: [PATCH 28/34] added 'superclass' for PRISM program and JANI model so they can be handled as symbolic model descriptions Former-commit-id: 748069c151a8157867c5a8358476c0266c2d52b9 [formerly 2c3e462958903cf0ec2f00e3d19802694af7c73e] Former-commit-id: e8d3ceb693377f5f39cc57bae2a2f23b85ec4312 --- src/storage/SymbolicModelDescription.cpp | 43 +++++++++++++++++++----- src/storage/SymbolicModelDescription.h | 35 +++++++++++++------ 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/storage/SymbolicModelDescription.cpp b/src/storage/SymbolicModelDescription.cpp index 9451c6a08..3bf4bf121 100644 --- a/src/storage/SymbolicModelDescription.cpp +++ b/src/storage/SymbolicModelDescription.cpp @@ -1,9 +1,36 @@ -// -// SymbolicModelDescription.cpp -// storm -// -// Created by Christian Dehnert on 09/09/16. -// -// +#include "src/storage/SymbolicModelDescription.h" -#include "SymbolicModelDescription.hpp" +#include "src/utility/macros.h" +#include "src/exceptions/InvalidOperationException.h" + +namespace storm { + namespace storage { + + SymbolicModelDescription::SymbolicModelDescription(storm::jani::Model const& model) { + // Intentionally left empty. + } + + SymbolicModelDescription::SymbolicModelDescription(storm::prism::Program const& program) { + // Intentionally left empty. + } + + bool SymbolicModelDescription::isJaniModel() const { + return modelDescription.which() == 0; + } + + bool SymbolicModelDescription::isPrismProgram() const { + return modelDescription.which() == 1; + } + + storm::jani::Model const& SymbolicModelDescription::asJaniModel() const { + STORM_LOG_THROW(isJaniModel(), storm::exceptions::InvalidOperationException, "Cannot retrieve JANI model, because the symbolic description has a different type."); + return boost::get<storm::jani::Model>(modelDescription); + } + + storm::prism::Program const& SymbolicModelDescription::asPrismProgram() const { + STORM_LOG_THROW(isPrismProgram(), storm::exceptions::InvalidOperationException, "Cannot retrieve JANI model, because the symbolic description has a different type."); + return boost::get<storm::prism::Program>(modelDescription); + } + + } +} \ No newline at end of file diff --git a/src/storage/SymbolicModelDescription.h b/src/storage/SymbolicModelDescription.h index f73dce810..1679ef1df 100644 --- a/src/storage/SymbolicModelDescription.h +++ b/src/storage/SymbolicModelDescription.h @@ -1,14 +1,27 @@ -// -// SymbolicModelDescription.hpp -// storm -// -// Created by Christian Dehnert on 09/09/16. -// -// +#pragma once -#ifndef SymbolicModelDescription_hpp -#define SymbolicModelDescription_hpp +#include <boost/variant.hpp> -#include <stdio.h> +#include "src/storage/jani/Model.h" +#include "src/storage/prism/Program.h" -#endif /* SymbolicModelDescription_hpp */ +namespace storm { + namespace storage { + + class SymbolicModelDescription { + public: + SymbolicModelDescription(storm::jani::Model const& model); + SymbolicModelDescription(storm::prism::Program const& program); + + bool isJaniModel() const; + bool isPrismProgram() const; + + storm::jani::Model const& asJaniModel() const; + storm::prism::Program const& asPrismProgram() const; + + private: + boost::variant<storm::jani::Model, storm::prism::Program> modelDescription; + }; + + } +} \ No newline at end of file From d5ba9e00e86ab62361eb0bd68dc2816e7314c2dd Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 9 Sep 2016 17:59:17 +0200 Subject: [PATCH 29/34] started on making jani available from cli, commit to switch workplace Former-commit-id: 4c04d77409fd58433bb53694e1250259431ae2a0 [formerly 279141117d04c1aeeed2eb435ec839180369981c] Former-commit-id: e05805177e7d777330f068473b1ec76a0cc4c745 --- src/cli/cli.cpp | 24 +++++++---- src/parser/FormulaParser.cpp | 5 ++- src/parser/FormulaParser.h | 6 ++- .../CounterexampleGeneratorSettings.cpp | 2 +- src/settings/modules/IOSettings.cpp | 37 ++++++++++++----- src/settings/modules/IOSettings.h | 40 ++++++++++++++---- src/storage/SymbolicModelDescription.cpp | 41 +++++++++++++++---- src/storage/SymbolicModelDescription.h | 9 +++- src/utility/storm.cpp | 6 ++- src/utility/storm.h | 1 - 10 files changed, 131 insertions(+), 40 deletions(-) diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 148c8d357..0629e0707 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -3,6 +3,8 @@ #include "../utility/storm.h" +#include "src/storage/SymbolicModelDescription.h" + #include "src/settings/modules/DebugSettings.h" #include "src/settings/modules/IOSettings.h" #include "src/settings/modules/CoreSettings.h" @@ -206,19 +208,27 @@ namespace storm { storm::utility::initializeFileLogging(); } - if (storm::settings::getModule<storm::settings::modules::IOSettings>().isSymbolicSet()) { - // If we have to build the model from a symbolic representation, we need to parse the representation first. - storm::prism::Program program = storm::parseProgram(storm::settings::getModule<storm::settings::modules::IOSettings>().getSymbolicModelFilename()); + auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>(); + if (ioSettings.isPrismOrJaniInputSet()) { + storm::storage::SymbolicModelDescription model; + if (ioSettings.isPrismInputSet()) { + model = storm::parseProgram(ioSettings.getPrismInputFilename()); + } else if (ioSettings.isJaniInputSet()) { + model = storm::parseJaniModel(ioSettings.getJaniInputFilename()).first; + } // Get the string that assigns values to the unknown currently undefined constants in the model. - std::string constantDefinitionString = storm::settings::getModule<storm::settings::modules::IOSettings>().getConstantDefinitionString(); - storm::prism::Program preprocessedProgram = storm::utility::prism::preprocess(program, constantDefinitionString); - std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = preprocessedProgram.getConstantsSubstitution(); + std::string constantDefinitionString = ioSettings.getConstantDefinitionString(); + model.preprocess(constantDefinitionString); // Then proceed to parsing the properties (if given), since the model we are building may depend on the property. std::vector<std::shared_ptr<storm::logic::Formula const>> formulas; if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isPropertySet()) { - formulas = storm::parseFormulasForProgram(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), preprocessedProgram); + if (model.isJaniModel()) { + formulas = storm::parseFormulasForJaniModel(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), model.asJaniModel()); + } else { + formulas = storm::parseFormulasForPrismProgram(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), model.asPrismProgram()); + } } // There may be constants of the model appearing in the formulas, so we replace all their occurrences diff --git a/src/parser/FormulaParser.cpp b/src/parser/FormulaParser.cpp index 74dbf31cf..f6aaf82a4 100644 --- a/src/parser/FormulaParser.cpp +++ b/src/parser/FormulaParser.cpp @@ -4,6 +4,9 @@ #include "src/parser/SpiritErrorHandler.h" +#include "src/storage/prism/Program.h" +#include "src/storage/jani/Model.h" + // If the parser fails due to ill-formed data, this exception is thrown. #include "src/exceptions/WrongFormatException.h" @@ -176,7 +179,7 @@ namespace storm { phoenix::function<SpiritErrorHandler> handler; }; - FormulaParser::FormulaParser(std::shared_ptr<storm::expressions::ExpressionManager const> const& manager) : manager(manager->getSharedPointer()), grammar(new FormulaParserGrammar(manager)) { + FormulaParser::FormulaParser(std::shared_ptr<storm::expressions::ExpressionManager const> const& manager) : manager(manager), grammar(new FormulaParserGrammar(manager)) { // Intentionally left empty. } diff --git a/src/parser/FormulaParser.h b/src/parser/FormulaParser.h index 86570c4f6..f69fa6eb2 100644 --- a/src/parser/FormulaParser.h +++ b/src/parser/FormulaParser.h @@ -9,9 +9,11 @@ #include "src/storage/expressions/Expression.h" #include "src/utility/macros.h" -#include "src/storage/prism/Program.h" - namespace storm { + namespace prism { + class Program; + } + namespace parser { // Forward-declare grammar. diff --git a/src/settings/modules/CounterexampleGeneratorSettings.cpp b/src/settings/modules/CounterexampleGeneratorSettings.cpp index b2dbb0ddc..540892a44 100644 --- a/src/settings/modules/CounterexampleGeneratorSettings.cpp +++ b/src/settings/modules/CounterexampleGeneratorSettings.cpp @@ -48,7 +48,7 @@ namespace storm { bool CounterexampleGeneratorSettings::check() const { // Ensure that the model was given either symbolically or explicitly. - STORM_LOG_THROW(!isMinimalCommandSetGenerationSet() || storm::settings::getModule<storm::settings::modules::IOSettings>().isSymbolicSet(), storm::exceptions::InvalidSettingsException, "For the generation of a minimal command set, the model has to be specified symbolically."); + STORM_LOG_THROW(!isMinimalCommandSetGenerationSet() || storm::settings::getModule<storm::settings::modules::IOSettings>().isPrismInputSet(), storm::exceptions::InvalidSettingsException, "For the generation of a minimal command set, the model has to be specified in the PRISM format."); if (isMinimalCommandSetGenerationSet()) { STORM_LOG_WARN_COND(isUseMaxSatBasedMinimalCommandSetGenerationSet() || !isEncodeReachabilitySet(), "Encoding reachability is only available for the MaxSat-based minimal command set generation, so selecting it has no effect."); diff --git a/src/settings/modules/IOSettings.cpp b/src/settings/modules/IOSettings.cpp index 80f9b3439..ef6877089 100644 --- a/src/settings/modules/IOSettings.cpp +++ b/src/settings/modules/IOSettings.cpp @@ -17,8 +17,8 @@ namespace storm { const std::string IOSettings::exportMatOptionName = "exportmat"; const std::string IOSettings::explicitOptionName = "explicit"; const std::string IOSettings::explicitOptionShortName = "exp"; - const std::string IOSettings::symbolicOptionName = "symbolic"; - const std::string IOSettings::symbolicOptionShortName = "s"; + const std::string IOSettings::prismInputOptionName = "prism"; + const std::string IOSettings::janiInputOptionName = "jani"; const std::string IOSettings::explorationOrderOptionName = "explorder"; const std::string IOSettings::explorationOrderOptionShortName = "eo"; const std::string IOSettings::transitionRewardsOptionName = "transrew"; @@ -38,8 +38,10 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, explicitOptionName, false, "Parses the model given in an explicit (sparse) representation.").setShortName(explicitOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("transition filename", "The name of the file from which to read the transitions.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("labeling filename", "The name of the file from which to read the state labeling.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, symbolicOptionName, false, "Parses the model given in a symbolic representation.").setShortName(symbolicOptionShortName) - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the symbolic model.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, prismInputOptionName, false, "Parses the model given in the PRISM format.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the PRISM input.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, janiInputOptionName, false, "Parses the model given in the JANI format.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the JANI input.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build()); std::vector<std::string> explorationOrders = {"dfs", "bfs"}; this->addOption(storm::settings::OptionBuilder(moduleName, explorationOrderOptionName, false, "Sets which exploration order to use.").setShortName(explorationOrderOptionShortName) @@ -51,7 +53,7 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The file from which to read the state rewards.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, choiceLabelingOptionName, false, "If given, the choice labels are read from this file and added to the explicit model. Note that this requires the model to be given as an explicit model (i.e., via --" + explicitOptionName + ").") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The file from which to read the choice labels.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, constantsOptionName, false, "Specifies the constant replacements to use in symbolic models. Note that Note that this requires the model to be given as an symbolic model (i.e., via --" + symbolicOptionName + ").").setShortName(constantsOptionShortName) + this->addOption(storm::settings::OptionBuilder(moduleName, constantsOptionName, false, "Specifies the constant replacements to use in symbolic models. Note that this requires the model to be given as an symbolic model (i.e., via --" + prismInputOptionName + " or --" + janiInputOptionName + ").").setShortName(constantsOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of constants and their value, e.g. a=1,b=2,c=3.").setDefaultValueString("").build()).build()); } @@ -75,14 +77,26 @@ namespace storm { return this->getOption(explicitOptionName).getArgumentByName("labeling filename").getValueAsString(); } - bool IOSettings::isSymbolicSet() const { - return this->getOption(symbolicOptionName).getHasOptionBeenSet(); + bool IOSettings::isPrismInputSet() const { + return this->getOption(prismInputOptionName).getHasOptionBeenSet(); } - std::string IOSettings::getSymbolicModelFilename() const { - return this->getOption(symbolicOptionName).getArgumentByName("filename").getValueAsString(); + bool IOSettings::isPrismOrJaniInputSet() const { + return isJaniInputSet() || isPrismInputSet(); } + std::string IOSettings::getPrismInputFilename() const { + return this->getOption(prismInputOptionName).getArgumentByName("filename").getValueAsString(); + } + + bool IOSettings::isJaniInputSet() const { + return this->getOption(janiInputOptionName).getHasOptionBeenSet(); + } + + std::string IOSettings::getJaniInputFilename() const { + return this->getOption(janiInputOptionName).getArgumentByName("filename").getValueAsString(); + } + bool IOSettings::isExplorationOrderSet() const { return this->getOption(explorationOrderOptionName).getHasOptionBeenSet(); } @@ -141,8 +155,11 @@ namespace storm { } bool IOSettings::check() const { + // Ensure that not two symbolic input models were given. + STORM_LOG_THROW(!isJaniInputSet() || !isPrismInputSet(), storm::exceptions::InvalidSettingsException, "Symbolic model "); + // Ensure that the model was given either symbolically or explicitly. - STORM_LOG_THROW(!isSymbolicSet() || !isExplicitSet(), storm::exceptions::InvalidSettingsException, "The model may be either given in an explicit or a symbolic format, but not both."); + STORM_LOG_THROW(!isJaniInputSet() || !isPrismInputSet() || !isExplicitSet(), storm::exceptions::InvalidSettingsException, "The model may be either given in an explicit or a symbolic format (PRISM or JANI), but not both."); return true; } diff --git a/src/settings/modules/IOSettings.h b/src/settings/modules/IOSettings.h index eb1ced407..8585ea573 100644 --- a/src/settings/modules/IOSettings.h +++ b/src/settings/modules/IOSettings.h @@ -59,20 +59,42 @@ namespace storm { std::string getLabelingFilename() const; /*! - * Retrieves whether the symbolic option was set. + * Retrieves whether the PRISM language option was set. * - * @return True if the symbolic option was set. + * @return True if the PRISM input option was set. */ - bool isSymbolicSet() const; + bool isPrismInputSet() const; + + /*! + * Retrieves whether the JANI input option was set. + * + * @return True if the JANI input option was set. + */ + bool isJaniInputSet() const; /*! - * Retrieves the name of the file that contains the symbolic model specification if the model was given - * using the symbolic option. + * Retrieves whether the JANI or PRISM input option was set. * - * @return The name of the file that contains the symbolic model specification. + * @return True if either of the two options was set. */ - std::string getSymbolicModelFilename() const; + bool isPrismOrJaniInputSet() const; + /*! + * Retrieves the name of the file that contains the PRISM model specification if the model was given + * using the PRISM input option. + * + * @return The name of the file that contains the PRISM model specification. + */ + std::string getPrismInputFilename() const; + + /*! + * Retrieves the name of the file that contains the JANI model specification if the model was given + * using the JANI input option. + * + * @return The name of the file that contains the JANI model specification. + */ + std::string getJaniInputFilename() const; + /*! * Retrieves whether the model exploration order was set. * @@ -174,8 +196,8 @@ namespace storm { static const std::string exportMatOptionName; static const std::string explicitOptionName; static const std::string explicitOptionShortName; - static const std::string symbolicOptionName; - static const std::string symbolicOptionShortName; + static const std::string prismInputOptionName; + static const std::string janiInputOptionName; static const std::string explorationOrderOptionName; static const std::string explorationOrderOptionShortName; static const std::string transitionRewardsOptionName; diff --git a/src/storage/SymbolicModelDescription.cpp b/src/storage/SymbolicModelDescription.cpp index 3bf4bf121..8d30575b7 100644 --- a/src/storage/SymbolicModelDescription.cpp +++ b/src/storage/SymbolicModelDescription.cpp @@ -1,35 +1,62 @@ #include "src/storage/SymbolicModelDescription.h" +#include "src/utility/prism.h" +#include "src/utility/jani.h" + #include "src/utility/macros.h" #include "src/exceptions/InvalidOperationException.h" namespace storm { namespace storage { - SymbolicModelDescription::SymbolicModelDescription(storm::jani::Model const& model) { + SymbolicModelDescription::SymbolicModelDescription(storm::jani::Model const& model) : modelDescription(model) { // Intentionally left empty. } - SymbolicModelDescription::SymbolicModelDescription(storm::prism::Program const& program) { + SymbolicModelDescription::SymbolicModelDescription(storm::prism::Program const& program) : modelDescription(program) { // Intentionally left empty. } - + + bool SymbolicModelDescription::hasModel() const { + return static_cast<bool>(modelDescription); + } + bool SymbolicModelDescription::isJaniModel() const { - return modelDescription.which() == 0; + return modelDescription.get().which() == 0; } bool SymbolicModelDescription::isPrismProgram() const { - return modelDescription.which() == 1; + return modelDescription.get().which() == 1; + } + + void SymbolicModelDescription::setModel(storm::jani::Model const& model) { + modelDescription = model; + } + + void SymbolicModelDescription::setModel(storm::prism::Program const& program) { + modelDescription = program; } storm::jani::Model const& SymbolicModelDescription::asJaniModel() const { STORM_LOG_THROW(isJaniModel(), storm::exceptions::InvalidOperationException, "Cannot retrieve JANI model, because the symbolic description has a different type."); - return boost::get<storm::jani::Model>(modelDescription); + return boost::get<storm::jani::Model>(modelDescription.get()); } storm::prism::Program const& SymbolicModelDescription::asPrismProgram() const { STORM_LOG_THROW(isPrismProgram(), storm::exceptions::InvalidOperationException, "Cannot retrieve JANI model, because the symbolic description has a different type."); - return boost::get<storm::prism::Program>(modelDescription); + return boost::get<storm::prism::Program>(modelDescription.get()); + } + + void SymbolicModelDescription::preprocess(std::string const& constantDefinitionString) { + if (this->isJaniModel()) { + std::map<storm::expressions::Variable, storm::expressions::Expression> substitution = storm::utility::jani::parseConstantDefinitionString(this->asJaniModel(), constantDefinitionString); + this->modelDescription = this->asJaniModel().defineUndefinedConstants(substitution); + this->modelDescription = this->asJaniModel().substituteConstants(); + } else if (this->isPrismProgram()) { + std::map<storm::expressions::Variable, storm::expressions::Expression> substitution = storm::utility::prism::parseConstantDefinitionString(this->asPrismProgram(), constantDefinitionString); + this->modelDescription = this->asPrismProgram().defineUndefinedConstants(substitution); + this->modelDescription = this->asPrismProgram().substituteConstants(); + } } } diff --git a/src/storage/SymbolicModelDescription.h b/src/storage/SymbolicModelDescription.h index 1679ef1df..ec9acf91f 100644 --- a/src/storage/SymbolicModelDescription.h +++ b/src/storage/SymbolicModelDescription.h @@ -10,17 +10,24 @@ namespace storm { class SymbolicModelDescription { public: + SymbolicModelDescription(); SymbolicModelDescription(storm::jani::Model const& model); SymbolicModelDescription(storm::prism::Program const& program); + bool hasModel() const; bool isJaniModel() const; bool isPrismProgram() const; + + void setModel(storm::jani::Model const& model); + void setModel(storm::prism::Program const& program); storm::jani::Model const& asJaniModel() const; storm::prism::Program const& asPrismProgram() const; + void preprocess(std::string const& constantDefinitionString = ""); + private: - boost::variant<storm::jani::Model, storm::prism::Program> modelDescription; + boost::optional<boost::variant<storm::jani::Model, storm::prism::Program>> modelDescription; }; } diff --git a/src/utility/storm.cpp b/src/utility/storm.cpp index 5bc0fdfee..6ce361d5c 100644 --- a/src/utility/storm.cpp +++ b/src/utility/storm.cpp @@ -43,7 +43,11 @@ namespace storm { return parseFormulas(formulaParser, inputString); } - std::vector<std::shared_ptr<storm::logic::Formula const>> parseFormulasForProgram(std::string const& inputString, storm::prism::Program const& program) { + std::vector<std::shared_ptr<storm::logic::Formula const>> parseFormulasForJaniModel(std::string const& inputString, storm::jani::Model const& model) { + storm::parser::FormulaParser formulaParser(model.getManager().getSharedPointer()); + return parseFormulas(formulaParser, inputString); + } + std::vector<std::shared_ptr<storm::logic::Formula const>> parseFormulasForPrismProgram(std::string const& inputString, storm::prism::Program const& program) { storm::parser::FormulaParser formulaParser(program); return parseFormulas(formulaParser, inputString); } diff --git a/src/utility/storm.h b/src/utility/storm.h index faaef184f..d1c767615 100644 --- a/src/utility/storm.h +++ b/src/utility/storm.h @@ -208,7 +208,6 @@ namespace storm { void generateCounterexample(storm::prism::Program const& program, std::shared_ptr<storm::models::sparse::Model<ValueType>> model, std::shared_ptr<storm::logic::Formula const> const& formula) { if (storm::settings::getModule<storm::settings::modules::CounterexampleGeneratorSettings>().isMinimalCommandSetGenerationSet()) { STORM_LOG_THROW(model->getType() == storm::models::ModelType::Mdp, storm::exceptions::InvalidTypeException, "Minimal command set generation is only available for MDPs."); - STORM_LOG_THROW(storm::settings::getModule<storm::settings::modules::IOSettings>().isSymbolicSet(), storm::exceptions::InvalidSettingsException, "Minimal command set generation is only available for symbolic models."); std::shared_ptr<storm::models::sparse::Mdp<ValueType>> mdp = model->template as<storm::models::sparse::Mdp<ValueType>>(); From e274cd33eb33fa3d0913b1273201d7a0ec186f37 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Sat, 10 Sep 2016 10:35:25 +0200 Subject: [PATCH 30/34] adapted cli to use symbolic model description rather than PRISM program Former-commit-id: d06884a848f57a221ab1fa5819ada7660ac55447 [formerly 9a128e04f1eafc4e8961ad91f7723c118f511b80] Former-commit-id: 25a820d0009fa1ab9262d26b3f010b74c63e9b3b --- src/builder/DdJaniModelBuilder.cpp | 47 +++++++++---------- src/builder/DdJaniModelBuilder.h | 22 +-------- src/builder/DdPrismModelBuilder.cpp | 33 +++++--------- src/builder/DdPrismModelBuilder.h | 11 ----- src/cli/cli.cpp | 13 ++---- src/cli/entrypoints.h | 56 ++++++++++++----------- src/storage/SymbolicModelDescription.h | 2 +- src/storage/jani/Model.cpp | 6 ++- src/storage/jani/Model.h | 7 ++- src/storage/prism/Program.cpp | 1 - src/utility/storm.cpp | 15 +++++- src/utility/storm.h | 63 +++++++++++++++++--------- 12 files changed, 134 insertions(+), 142 deletions(-) diff --git a/src/builder/DdJaniModelBuilder.cpp b/src/builder/DdJaniModelBuilder.cpp index f62afa00f..a2b837080 100644 --- a/src/builder/DdJaniModelBuilder.cpp +++ b/src/builder/DdJaniModelBuilder.cpp @@ -102,22 +102,6 @@ namespace storm { } } - template <storm::dd::DdType Type, typename ValueType> - DdJaniModelBuilder<Type, ValueType>::DdJaniModelBuilder(storm::jani::Model const& model, Options const& options) : model(model), options(options) { - if (this->model->hasUndefinedConstants()) { - std::vector<std::reference_wrapper<storm::jani::Constant const>> undefinedConstants = this->model->getUndefinedConstants(); - std::vector<std::string> strings; - for (auto const& constant : undefinedConstants) { - std::stringstream stream; - stream << constant.get().getName() << " (" << constant.get().getType() << ")"; - strings.push_back(stream.str()); - } - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " << boost::join(strings, ", ") << "."); - } - - this->model = this->model->substituteConstants(); - } - template <storm::dd::DdType Type, typename ValueType> struct CompositionVariables { CompositionVariables() : manager(std::make_shared<storm::dd::DdManager<Type>>()), @@ -1732,31 +1716,42 @@ namespace storm { } template <storm::dd::DdType Type, typename ValueType> - std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdJaniModelBuilder<Type, ValueType>::build() { + std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdJaniModelBuilder<Type, ValueType>::build(storm::jani::Model const& model, Options const& options) { + if (model.hasUndefinedConstants()) { + std::vector<std::reference_wrapper<storm::jani::Constant const>> undefinedConstants = model.getUndefinedConstants(); + std::vector<std::string> strings; + for (auto const& constant : undefinedConstants) { + std::stringstream stream; + stream << constant.get().getName() << " (" << constant.get().getType() << ")"; + strings.push_back(stream.str()); + } + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Model still contains these undefined constants: " << boost::join(strings, ", ") << "."); + } + // Create all necessary variables. - CompositionVariableCreator<Type, ValueType> variableCreator(*this->model); + CompositionVariableCreator<Type, ValueType> variableCreator(model); CompositionVariables<Type, ValueType> variables = variableCreator.create(); // Create a builder to compose and build the model. -// SeparateEdgesSystemComposer<Type, ValueType> composer(*this->model, variables); - CombinedEdgesSystemComposer<Type, ValueType> composer(*this->model, variables); +// SeparateEdgesSystemComposer<Type, ValueType> composer(model, variables); + CombinedEdgesSystemComposer<Type, ValueType> composer(model, variables); ComposerResult<Type, ValueType> system = composer.compose(); // Postprocess the variables in place. - postprocessVariables(this->model->getModelType(), system, variables); + postprocessVariables(model.getModelType(), system, variables); // Postprocess the system in place and get the states that were terminal (i.e. whose transitions were cut off). - storm::dd::Bdd<Type> terminalStates = postprocessSystem(*this->model, system, variables, options); + storm::dd::Bdd<Type> terminalStates = postprocessSystem(model, system, variables, options); // Start creating the model components. ModelComponents<Type, ValueType> modelComponents; // Build initial states. - modelComponents.initialStates = computeInitialStates(*this->model, variables); + modelComponents.initialStates = computeInitialStates(model, variables); // Perform reachability analysis to obtain reachable states. storm::dd::Bdd<Type> transitionMatrixBdd = system.transitions.notZero(); - if (this->model->getModelType() == storm::jani::ModelType::MDP) { + if (model.getModelType() == storm::jani::ModelType::MDP) { transitionMatrixBdd = transitionMatrixBdd.existsAbstract(variables.allNondeterminismVariables); } modelComponents.reachableStates = storm::utility::dd::computeReachableStates(modelComponents.initialStates, transitionMatrixBdd, variables.rowMetaVariables, variables.columnMetaVariables); @@ -1770,13 +1765,13 @@ namespace storm { modelComponents.transitionMatrix = system.transitions * reachableStatesAdd; // Fix deadlocks if existing. - modelComponents.deadlockStates = fixDeadlocks(this->model->getModelType(), modelComponents.transitionMatrix, transitionMatrixBdd, modelComponents.reachableStates, variables); + modelComponents.deadlockStates = fixDeadlocks(model.getModelType(), modelComponents.transitionMatrix, transitionMatrixBdd, modelComponents.reachableStates, variables); // Cut the deadlock states by removing all states that we 'converted' to deadlock states by making them terminal. modelComponents.deadlockStates = modelComponents.deadlockStates && !terminalStates; // Finally, create the model. - return createModel(this->model->getModelType(), variables, modelComponents); + return createModel(model.getModelType(), variables, modelComponents); } template class DdJaniModelBuilder<storm::dd::DdType::CUDD, double>; diff --git a/src/builder/DdJaniModelBuilder.h b/src/builder/DdJaniModelBuilder.h index 348d017ad..f1b16af1a 100644 --- a/src/builder/DdJaniModelBuilder.h +++ b/src/builder/DdJaniModelBuilder.h @@ -77,11 +77,6 @@ namespace storm { boost::optional<storm::expressions::Expression> negatedTerminalStates; }; - /*! - * Creates a builder for the given model that uses the given options. - */ - DdJaniModelBuilder(storm::jani::Model const& model, Options const& options = Options()); - /*! * Translates the given program into a symbolic model (i.e. one that stores the transition relation as a * decision diagram). @@ -89,22 +84,7 @@ namespace storm { * @param model The model to translate. * @return A pointer to the resulting model. */ - std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> build(); - - /*! - * Retrieves the model that was actually translated (i.e. including constant substitutions etc.). Note - * that this function may only be called after a succesful translation. - * - * @return The translated model. - */ - storm::jani::Model const& getTranslatedModel() const; - - private: - /// The model to translate. - boost::optional<storm::jani::Model> model; - - /// The options to use for building the model. - Options options; + std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> build(storm::jani::Model const& model, Options const& options = Options()); }; } diff --git a/src/builder/DdPrismModelBuilder.cpp b/src/builder/DdPrismModelBuilder.cpp index 6c495e15c..859a2424e 100644 --- a/src/builder/DdPrismModelBuilder.cpp +++ b/src/builder/DdPrismModelBuilder.cpp @@ -1222,17 +1222,10 @@ namespace storm { return storm::models::symbolic::StandardRewardModel<Type, ValueType>(stateRewards, stateActionRewards, transitionRewards); } - template <storm::dd::DdType Type, typename ValueType> - storm::prism::Program const& DdPrismModelBuilder<Type, ValueType>::getTranslatedProgram() const { - return preparedProgram.get(); - } - template <storm::dd::DdType Type, typename ValueType> std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdPrismModelBuilder<Type, ValueType>::build(storm::prism::Program const& program, Options const& options) { - preparedProgram = program; - - if (preparedProgram->hasUndefinedConstants()) { - std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = preparedProgram->getUndefinedConstants(); + if (program.hasUndefinedConstants()) { + std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = program.getUndefinedConstants(); std::stringstream stream; bool printComma = false; for (auto const& constant : undefinedConstants) { @@ -1247,13 +1240,11 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " + stream.str()); } - preparedProgram = preparedProgram->substituteConstants(); - - STORM_LOG_DEBUG("Building representation of program:" << std::endl << *preparedProgram << std::endl); + STORM_LOG_DEBUG("Building representation of program:" << std::endl << program << std::endl); // Start by initializing the structure used for storing all information needed during the model generation. // In particular, this creates the meta variables used to encode the model. - GenerationInformation generationInfo(*preparedProgram); + GenerationInformation generationInfo(program); SystemResult system = createSystemDecisionDiagram(generationInfo); storm::dd::Add<Type, ValueType> transitionMatrix = system.allTransitionsDd; @@ -1264,7 +1255,7 @@ namespace storm { // If we were asked to treat some states as terminal states, we cut away their transitions now. storm::dd::Bdd<Type> terminalStatesBdd = generationInfo.manager->getBddZero(); if (options.terminalStates || options.negatedTerminalStates) { - std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = preparedProgram->getConstantsSubstitution(); + std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = program.getConstantsSubstitution(); if (options.terminalStates) { storm::expressions::Expression terminalExpression; @@ -1273,7 +1264,7 @@ namespace storm { } else { std::string const& labelName = boost::get<std::string>(options.terminalStates.get()); if (program.hasLabel(labelName)) { - terminalExpression = preparedProgram->getLabelExpression(labelName); + terminalExpression = program.getLabelExpression(labelName); } else { STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'."); } @@ -1294,7 +1285,7 @@ namespace storm { } else { std::string const& labelName = boost::get<std::string>(options.negatedTerminalStates.get()); if (program.hasLabel(labelName)) { - negatedTerminalExpression = preparedProgram->getLabelExpression(labelName); + negatedTerminalExpression = program.getLabelExpression(labelName); } else { STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'."); } @@ -1377,18 +1368,18 @@ namespace storm { // First, we make sure that all selected reward models actually exist. for (auto const& rewardModelName : options.rewardModelsToBuild) { - STORM_LOG_THROW(rewardModelName.empty() || preparedProgram->hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException, "Model does not possess a reward model with the name '" << rewardModelName << "'."); + STORM_LOG_THROW(rewardModelName.empty() || program.hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException, "Model does not possess a reward model with the name '" << rewardModelName << "'."); } - for (auto const& rewardModel : preparedProgram->getRewardModels()) { + for (auto const& rewardModel : program.getRewardModels()) { if (options.buildAllRewardModels || options.rewardModelsToBuild.find(rewardModel.getName()) != options.rewardModelsToBuild.end()) { selectedRewardModels.push_back(rewardModel); } } // If no reward model was selected until now and a referenced reward model appears to be unique, we build // the only existing reward model (given that no explicit name was given for the referenced reward model). - if (selectedRewardModels.empty() && preparedProgram->getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") { - selectedRewardModels.push_back(preparedProgram->getRewardModel(0)); + if (selectedRewardModels.empty() && program.getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") { + selectedRewardModels.push_back(program.getRewardModel(0)); } std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<Type, ValueType>> rewardModels; @@ -1398,7 +1389,7 @@ namespace storm { // Build the labels that can be accessed as a shortcut. std::map<std::string, storm::expressions::Expression> labelToExpressionMapping; - for (auto const& label : preparedProgram->getLabels()) { + for (auto const& label : program.getLabels()) { labelToExpressionMapping.emplace(label.getName(), label.getStatePredicateExpression()); } diff --git a/src/builder/DdPrismModelBuilder.h b/src/builder/DdPrismModelBuilder.h index 6db0c4639..464a0a071 100644 --- a/src/builder/DdPrismModelBuilder.h +++ b/src/builder/DdPrismModelBuilder.h @@ -98,14 +98,6 @@ namespace storm { */ std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> build(storm::prism::Program const& program, Options const& options = Options()); - /*! - * Retrieves the program that was actually translated (i.e. including constant substitutions etc.). Note - * that this function may only be called after a succesful translation. - * - * @return The translated program. - */ - storm::prism::Program const& getTranslatedProgram() const; - private: // This structure can store the decision diagrams representing a particular action. struct UpdateDecisionDiagram { @@ -243,9 +235,6 @@ namespace storm { static SystemResult createSystemDecisionDiagram(GenerationInformation& generationInfo); static storm::dd::Bdd<Type> createInitialStatesDecisionDiagram(GenerationInformation& generationInfo); - - // This member holds the program that was most recently translated (if any). - boost::optional<storm::prism::Program> preparedProgram; }; } // namespace adapters diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 0629e0707..31a0a8afb 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -231,27 +231,20 @@ namespace storm { } } - // There may be constants of the model appearing in the formulas, so we replace all their occurrences - // by their definitions in the translated program. - std::vector<std::shared_ptr<storm::logic::Formula const>> preprocessedFormulas; - for (auto const& formula : formulas) { - preprocessedFormulas.emplace_back(formula->substitute(constantsSubstitution)); - } - if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isParametricSet()) { #ifdef STORM_HAVE_CARL - buildAndCheckSymbolicModel<storm::RationalFunction>(preprocessedProgram, preprocessedFormulas, true); + buildAndCheckSymbolicModel<storm::RationalFunction>(model, formulas, true); #else STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No parameters are supported in this build."); #endif } else if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isExactSet()) { #ifdef STORM_HAVE_CARL - buildAndCheckSymbolicModel<storm::RationalNumber>(preprocessedProgram, preprocessedFormulas, true); + buildAndCheckSymbolicModel<storm::RationalNumber>(model, formulas, true); #else STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No exact numbers are supported in this build."); #endif } else { - buildAndCheckSymbolicModel<double>(preprocessedProgram, preprocessedFormulas, true); + buildAndCheckSymbolicModel<double>(model, formulas, true); } } else if (storm::settings::getModule<storm::settings::modules::IOSettings>().isExplicitSet()) { STORM_LOG_THROW(storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Only the sparse engine supports explicit model input."); diff --git a/src/cli/entrypoints.h b/src/cli/entrypoints.h index b41a0f07f..f4b009b7e 100644 --- a/src/cli/entrypoints.h +++ b/src/cli/entrypoints.h @@ -3,7 +3,10 @@ #include "src/utility/storm.h" +#include "src/storage/SymbolicModelDescription.h" + #include "src/exceptions/NotImplementedException.h" +#include "src/exceptions/InvalidSettingsException.h" namespace storm { namespace cli { @@ -49,12 +52,14 @@ namespace storm { #endif template<storm::dd::DdType DdType> - void verifySymbolicModelWithAbstractionRefinementEngine(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { + void verifySymbolicModelWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Abstraction Refinement is not yet implemented."); } template<typename ValueType> - void verifySymbolicModelWithExplorationEngine(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { + void verifySymbolicModelWithExplorationEngine(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { + STORM_LOG_THROW(model.isPrismProgram(), storm::exceptions::InvalidSettingsException, "Exploration engine is currently only applicable to PRISM models."); + storm::prism::Program const& program = model.asPrismProgram(); STORM_LOG_THROW(program.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::MDP, storm::exceptions::InvalidSettingsException, "Currently exploration-based verification is only available for DTMCs and MDPs."); for (auto const& formula : formulas) { @@ -98,7 +103,7 @@ namespace storm { #ifdef STORM_HAVE_CARL template<> - void verifySymbolicModelWithExplorationEngine<storm::RationalFunction>(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) { + void verifySymbolicModelWithExplorationEngine<storm::RationalFunction>(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Exploration-based verification does currently not support parametric models."); } #endif @@ -177,81 +182,80 @@ namespace storm { } template<storm::dd::DdType LibraryType> - void buildAndCheckSymbolicModelWithSymbolicEngine(bool hybrid, storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { + void buildAndCheckSymbolicModelWithSymbolicEngine(bool hybrid, storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { // Start by building the model. - auto model = buildSymbolicModel<double, LibraryType>(program, formulas); + auto markovModel = buildSymbolicModel<double, LibraryType>(model, formulas); // Print some information about the model. - model->printModelInformationToStream(std::cout); + markovModel->printModelInformationToStream(std::cout); // Then select the correct engine. if (hybrid) { - verifySymbolicModelWithHybridEngine(model, formulas, onlyInitialStatesRelevant); + verifySymbolicModelWithHybridEngine(markovModel, formulas, onlyInitialStatesRelevant); } else { - verifySymbolicModelWithDdEngine(model, formulas, onlyInitialStatesRelevant); + verifySymbolicModelWithDdEngine(markovModel, formulas, onlyInitialStatesRelevant); } } template<typename ValueType> - void buildAndCheckSymbolicModelWithSparseEngine(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { + void buildAndCheckSymbolicModelWithSparseEngine(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { // Start by building the model. - std::shared_ptr<storm::models::ModelBase> model = buildSparseModel<ValueType>(program, formulas); + std::shared_ptr<storm::models::ModelBase> markovModel = buildSparseModel<ValueType>(model, formulas); // Print some information about the model. - model->printModelInformationToStream(std::cout); + markovModel->printModelInformationToStream(std::cout); // Preprocess the model. - BRANCH_ON_SPARSE_MODELTYPE(model, model, ValueType, preprocessModel, formulas); + BRANCH_ON_SPARSE_MODELTYPE(markovModel, markovModel, ValueType, preprocessModel, formulas); - std::shared_ptr<storm::models::sparse::Model<ValueType>> sparseModel = model->template as<storm::models::sparse::Model<ValueType>>(); + std::shared_ptr<storm::models::sparse::Model<ValueType>> sparseModel = markovModel->template as<storm::models::sparse::Model<ValueType>>(); // Finally, treat the formulas. if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isCounterexampleSet()) { - generateCounterexamples<ValueType>(program, sparseModel, formulas); + generateCounterexamples<ValueType>(model, sparseModel, formulas); } else { verifySparseModel<ValueType>(sparseModel, formulas, onlyInitialStatesRelevant); } } template<typename ValueType> - void buildAndCheckSymbolicModel(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { + void buildAndCheckSymbolicModel(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { if (storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::AbstractionRefinement) { auto ddlib = storm::settings::getModule<storm::settings::modules::CoreSettings>().getDdLibraryType(); if (ddlib == storm::dd::DdType::CUDD) { - verifySymbolicModelWithAbstractionRefinementEngine<storm::dd::DdType::CUDD>(program, formulas, onlyInitialStatesRelevant); + verifySymbolicModelWithAbstractionRefinementEngine<storm::dd::DdType::CUDD>(model, formulas, onlyInitialStatesRelevant); } else { - verifySymbolicModelWithAbstractionRefinementEngine<storm::dd::DdType::Sylvan>(program, formulas, onlyInitialStatesRelevant); + verifySymbolicModelWithAbstractionRefinementEngine<storm::dd::DdType::Sylvan>(model, formulas, onlyInitialStatesRelevant); } } else if (storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::Exploration) { - verifySymbolicModelWithExplorationEngine<ValueType>(program, formulas, onlyInitialStatesRelevant); + verifySymbolicModelWithExplorationEngine<ValueType>(model, formulas, onlyInitialStatesRelevant); } else { auto engine = storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine(); if (engine == storm::settings::modules::CoreSettings::Engine::Dd || engine == storm::settings::modules::CoreSettings::Engine::Hybrid) { auto ddlib = storm::settings::getModule<storm::settings::modules::CoreSettings>().getDdLibraryType(); if (ddlib == storm::dd::DdType::CUDD) { - buildAndCheckSymbolicModelWithSymbolicEngine<storm::dd::DdType::CUDD>(engine == storm::settings::modules::CoreSettings::Engine::Hybrid, program, formulas, onlyInitialStatesRelevant); + buildAndCheckSymbolicModelWithSymbolicEngine<storm::dd::DdType::CUDD>(engine == storm::settings::modules::CoreSettings::Engine::Hybrid, model, formulas, onlyInitialStatesRelevant); } else { - buildAndCheckSymbolicModelWithSymbolicEngine<storm::dd::DdType::Sylvan>(engine == storm::settings::modules::CoreSettings::Engine::Hybrid, program, formulas, onlyInitialStatesRelevant); + buildAndCheckSymbolicModelWithSymbolicEngine<storm::dd::DdType::Sylvan>(engine == storm::settings::modules::CoreSettings::Engine::Hybrid, model, formulas, onlyInitialStatesRelevant); } } else { STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Illegal engine."); - - buildAndCheckSymbolicModelWithSparseEngine<ValueType>(program, formulas, onlyInitialStatesRelevant); + buildAndCheckSymbolicModelWithSparseEngine<ValueType>(model, formulas, onlyInitialStatesRelevant); } } } #ifdef STORM_HAVE_CARL template<> - void buildAndCheckSymbolicModel<storm::RationalNumber>(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) { + void buildAndCheckSymbolicModel<storm::RationalNumber>(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) { STORM_LOG_THROW(storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Cannot use this data type with an engine different than the sparse one."); - buildAndCheckSymbolicModelWithSparseEngine<storm::RationalNumber>(program, formulas, onlyInitialStatesRelevant); + buildAndCheckSymbolicModelWithSparseEngine<storm::RationalNumber>(model, formulas, onlyInitialStatesRelevant); } template<> - void buildAndCheckSymbolicModel<storm::RationalFunction>(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) { + void buildAndCheckSymbolicModel<storm::RationalFunction>(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) { STORM_LOG_THROW(storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Cannot use this data type with an engine different than the sparse one."); - buildAndCheckSymbolicModelWithSparseEngine<storm::RationalFunction>(program, formulas, onlyInitialStatesRelevant); + buildAndCheckSymbolicModelWithSparseEngine<storm::RationalFunction>(model, formulas, onlyInitialStatesRelevant); } #endif diff --git a/src/storage/SymbolicModelDescription.h b/src/storage/SymbolicModelDescription.h index ec9acf91f..77da92d82 100644 --- a/src/storage/SymbolicModelDescription.h +++ b/src/storage/SymbolicModelDescription.h @@ -10,7 +10,7 @@ namespace storm { class SymbolicModelDescription { public: - SymbolicModelDescription(); + SymbolicModelDescription() = default; SymbolicModelDescription(storm::jani::Model const& model); SymbolicModelDescription(storm::prism::Program const& program); diff --git a/src/storage/jani/Model.cpp b/src/storage/jani/Model.cpp index 0bec35317..9a9a95d8f 100644 --- a/src/storage/jani/Model.cpp +++ b/src/storage/jani/Model.cpp @@ -34,6 +34,10 @@ namespace storm { silentActionIndex = addAction(storm::jani::Action(SILENT_ACTION_NAME)); } + storm::expressions::ExpressionManager& Model::getManager() const { + return *expressionManager; + } + uint64_t Model::getJaniVersion() const { return version; } @@ -104,7 +108,7 @@ namespace storm { std::vector<Constant>& Model::getConstants() { return constants; } - + Variable const& Model::addVariable(Variable const& variable) { if (variable.isBooleanVariable()) { return addVariable(variable.asBooleanVariable()); diff --git a/src/storage/jani/Model.h b/src/storage/jani/Model.h index 946871cc5..375c4d792 100644 --- a/src/storage/jani/Model.h +++ b/src/storage/jani/Model.h @@ -30,6 +30,11 @@ namespace storm { * Creates an empty model with the given type. */ Model(std::string const& name, ModelType const& modelType, uint64_t version = 1, boost::optional<std::shared_ptr<storm::expressions::ExpressionManager>> const& expressionManager = boost::none); + + /*! + * Retrieves the expression manager responsible for the expressions in the model. + */ + storm::expressions::ExpressionManager& getManager() const; /*! * Retrieves the JANI-version of the model. @@ -106,7 +111,7 @@ namespace storm { * Retrieves the constant with the given name (if any). */ Constant const& getConstant(std::string const& name) const; - + /*! * Adds the given variable to this model. */ diff --git a/src/storage/prism/Program.cpp b/src/storage/prism/Program.cpp index 99f4d3e4f..126f53c4e 100644 --- a/src/storage/prism/Program.cpp +++ b/src/storage/prism/Program.cpp @@ -332,7 +332,6 @@ namespace storm { return constantsSubstitution; } - std::size_t Program::getNumberOfConstants() const { return this->getConstants().size(); } diff --git a/src/utility/storm.cpp b/src/utility/storm.cpp index 6ce361d5c..c567c05cb 100644 --- a/src/utility/storm.cpp +++ b/src/utility/storm.cpp @@ -43,12 +43,23 @@ namespace storm { return parseFormulas(formulaParser, inputString); } + std::vector<std::shared_ptr<storm::logic::Formula const>> substituteConstantsInFormulas(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) { + std::vector<std::shared_ptr<storm::logic::Formula const>> preprocessedFormulas; + for (auto const& formula : formulas) { + preprocessedFormulas.emplace_back(formula->substitute(substitution)); + } + return preprocessedFormulas; + } + std::vector<std::shared_ptr<storm::logic::Formula const>> parseFormulasForJaniModel(std::string const& inputString, storm::jani::Model const& model) { storm::parser::FormulaParser formulaParser(model.getManager().getSharedPointer()); - return parseFormulas(formulaParser, inputString); + auto formulas = parseFormulas(formulaParser, inputString); + return substituteConstantsInFormulas(formulas, model.getConstantsSubstitution()); } + std::vector<std::shared_ptr<storm::logic::Formula const>> parseFormulasForPrismProgram(std::string const& inputString, storm::prism::Program const& program) { storm::parser::FormulaParser formulaParser(program); - return parseFormulas(formulaParser, inputString); + auto formulas = parseFormulas(formulaParser, inputString); + return substituteConstantsInFormulas(formulas, program.getConstantsSubstitution()); } } diff --git a/src/utility/storm.h b/src/utility/storm.h index d1c767615..c5df89d64 100644 --- a/src/utility/storm.h +++ b/src/utility/storm.h @@ -48,11 +48,13 @@ // Headers of builders. #include "src/builder/ExplicitModelBuilder.h" #include "src/builder/DdPrismModelBuilder.h" +#include "src/builder/DdJaniModelBuilder.h" // Headers for model processing. #include "src/storage/bisimulation/DeterministicModelBisimulationDecomposition.h" #include "src/storage/bisimulation/NondeterministicModelBisimulationDecomposition.h" #include "src/storage/ModelFormulasPair.h" +#include "src/storage/SymbolicModelDescription.h" // Headers for model checking. #include "src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" @@ -79,9 +81,9 @@ #include "src/counterexamples/MILPMinimalLabelSetGenerator.h" #include "src/counterexamples/SMTMinimalCommandSetGenerator.h" -// Headers related to PRISM model building. +// Headers related to model building. #include "src/generator/PrismNextStateGenerator.h" -#include "src/utility/prism.h" +#include "src/generator/JaniNextStateGenerator.h" // Headers related to exception handling. #include "src/exceptions/InvalidStateException.h" @@ -101,10 +103,11 @@ namespace storm { std::pair<storm::jani::Model, std::vector<storm::jani::Property>> parseJaniModel(std::string const& path); storm::prism::Program parseProgram(std::string const& path); std::vector<std::shared_ptr<storm::logic::Formula const>> parseFormulasForExplicit(std::string const& inputString); - std::vector<std::shared_ptr<storm::logic::Formula const>> parseFormulasForProgram(std::string const& inputString, storm::prism::Program const& program); + std::vector<std::shared_ptr<storm::logic::Formula const>> parseFormulasForPrismProgram(std::string const& inputString, storm::prism::Program const& program); + std::vector<std::shared_ptr<storm::logic::Formula const>> parseFormulasForJaniModel(std::string const& inputString, storm::jani::Model const& model); template<typename ValueType> - std::shared_ptr<storm::models::sparse::Model<ValueType>> buildSparseModel(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { + std::shared_ptr<storm::models::sparse::Model<ValueType>> buildSparseModel(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { storm::generator::NextStateGeneratorOptions options(formulas); // Generate command labels if we are going to build a counterexample later. @@ -112,18 +115,34 @@ namespace storm { options.setBuildChoiceLabels(true); } - std::shared_ptr<storm::generator::NextStateGenerator<ValueType, uint32_t>> generator = std::make_shared<storm::generator::PrismNextStateGenerator<ValueType, uint32_t>>(program, options); + std::shared_ptr<storm::generator::NextStateGenerator<ValueType, uint32_t>> generator; + if (model.isPrismProgram()) { + generator = std::make_shared<storm::generator::PrismNextStateGenerator<ValueType, uint32_t>>(model.asPrismProgram(), options); + } else if (model.isJaniModel()) { + generator = std::make_shared<storm::generator::JaniNextStateGenerator<ValueType, uint32_t>>(model.asJaniModel(), options); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Cannot build sparse model from this symbolic model description."); + } storm::builder::ExplicitModelBuilder<ValueType> builder(generator); return builder.build(); } template<typename ValueType, storm::dd::DdType LibraryType = storm::dd::DdType::CUDD> - std::shared_ptr<storm::models::symbolic::Model<LibraryType, ValueType>> buildSymbolicModel(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) { - typename storm::builder::DdPrismModelBuilder<LibraryType, ValueType>::Options options; - options = typename storm::builder::DdPrismModelBuilder<LibraryType, ValueType>::Options(formulas); - - storm::builder::DdPrismModelBuilder<LibraryType, ValueType> builder; - return builder.build(program, options); + std::shared_ptr<storm::models::symbolic::Model<LibraryType, ValueType>> buildSymbolicModel(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) { + if (model.isPrismProgram()) { + typename storm::builder::DdPrismModelBuilder<LibraryType, ValueType>::Options options; + options = typename storm::builder::DdPrismModelBuilder<LibraryType, ValueType>::Options(formulas); + + storm::builder::DdPrismModelBuilder<LibraryType, ValueType> builder; + return builder.build(model.asPrismProgram(), options); + } else { + STORM_LOG_THROW(model.isJaniModel(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model for the given symbolic model description."); + typename storm::builder::DdJaniModelBuilder<LibraryType, ValueType>::Options options; + options = typename storm::builder::DdJaniModelBuilder<LibraryType, ValueType>::Options(formulas); + + storm::builder::DdJaniModelBuilder<LibraryType, ValueType> builder; + return builder.build(model.asJaniModel(), options); + } } template<typename ModelType> @@ -205,11 +224,13 @@ namespace storm { } template<typename ValueType> - void generateCounterexample(storm::prism::Program const& program, std::shared_ptr<storm::models::sparse::Model<ValueType>> model, std::shared_ptr<storm::logic::Formula const> const& formula) { + void generateCounterexample(storm::storage::SymbolicModelDescription const& model, std::shared_ptr<storm::models::sparse::Model<ValueType>> markovModel, std::shared_ptr<storm::logic::Formula const> const& formula) { if (storm::settings::getModule<storm::settings::modules::CounterexampleGeneratorSettings>().isMinimalCommandSetGenerationSet()) { - STORM_LOG_THROW(model->getType() == storm::models::ModelType::Mdp, storm::exceptions::InvalidTypeException, "Minimal command set generation is only available for MDPs."); - - std::shared_ptr<storm::models::sparse::Mdp<ValueType>> mdp = model->template as<storm::models::sparse::Mdp<ValueType>>(); + STORM_LOG_THROW(model.isPrismProgram(), storm::exceptions::InvalidTypeException, "Minimal command set generation is only available for PRISM models."); + STORM_LOG_THROW(markovModel->getType() == storm::models::ModelType::Mdp, storm::exceptions::InvalidTypeException, "Minimal command set generation is only available for MDPs."); + storm::prism::Program const& program = model.asPrismProgram(); + + std::shared_ptr<storm::models::sparse::Mdp<ValueType>> mdp = markovModel->template as<storm::models::sparse::Mdp<ValueType>>(); // Determine whether we are required to use the MILP-version or the SAT-version. bool useMILP = storm::settings::getModule<storm::settings::modules::CounterexampleGeneratorSettings>().isUseMilpBasedMinimalCommandSetGenerationSet(); @@ -227,20 +248,20 @@ namespace storm { #ifdef STORM_HAVE_CARL template<> - inline void generateCounterexample(storm::prism::Program const& program, std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> model, std::shared_ptr<storm::logic::Formula const> const& formula) { - STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unable to generate counterexample for parametric model."); + inline void generateCounterexample(storm::storage::SymbolicModelDescription const& model, std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> markovModel, std::shared_ptr<storm::logic::Formula const> const& formula) { + STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unable to generate counterexample for exact arithmetic model."); } template<> - inline void generateCounterexample(storm::prism::Program const& program, std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> model, std::shared_ptr<storm::logic::Formula const> const& formula) { + inline void generateCounterexample(storm::storage::SymbolicModelDescription const& model, std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> markovModel, std::shared_ptr<storm::logic::Formula const> const& formula) { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unable to generate counterexample for parametric model."); } #endif template<typename ValueType> - void generateCounterexamples(storm::prism::Program const& program, std::shared_ptr<storm::models::sparse::Model<ValueType>> model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) { + void generateCounterexamples(storm::storage::SymbolicModelDescription const& model, std::shared_ptr<storm::models::sparse::Model<ValueType>> markovModel, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) { for (auto const& formula : formulas) { - generateCounterexample(program, model, formula); + generateCounterexample(model, markovModel, formula); } } @@ -408,7 +429,7 @@ namespace storm { // Program and formula storm::prism::Program program = parseProgram(programFilePath); program.checkValidity(); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = parseFormulasForProgram(formulaString, program);; + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = parseFormulasForPrismProgram(formulaString, program); if(formulas.size()!=1) { STORM_LOG_ERROR("The given formulaString does not specify exactly one formula"); return false; From 8a8aca006234d557640c0bf8ccf5855fb614455c Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Sat, 10 Sep 2016 11:46:22 +0200 Subject: [PATCH 31/34] explicit reward model building for JANI working from cli Former-commit-id: 22b4dbcdbf8f330a87f0e09ccf89d2fc49b4855e [formerly 4edbdf42075482783112564a9b03936ef5d692ea] Former-commit-id: e93b8bf1a0d4658afadd11b2b1248cbfe760ccfa --- src/generator/JaniNextStateGenerator.cpp | 93 ++++++++++++++++++------ src/generator/JaniNextStateGenerator.h | 11 ++- src/generator/NextStateGenerator.cpp | 12 +++ src/generator/NextStateGenerator.h | 3 + src/storage/SymbolicModelDescription.cpp | 11 +++ src/storage/SymbolicModelDescription.h | 2 + 6 files changed, 108 insertions(+), 24 deletions(-) diff --git a/src/generator/JaniNextStateGenerator.cpp b/src/generator/JaniNextStateGenerator.cpp index 859257931..c0ae75160 100644 --- a/src/generator/JaniNextStateGenerator.cpp +++ b/src/generator/JaniNextStateGenerator.cpp @@ -53,6 +53,9 @@ namespace storm { } } + // Build the information structs for the reward models. + buildRewardModelInformation(); + // If there are terminal states we need to handle, we now need to translate all labels to expressions. if (this->options.hasTerminalStates()) { for (auto const& expressionOrLabelAndBool : this->options.getTerminalStates()) { @@ -309,25 +312,6 @@ namespace storm { return result; } - template<typename ValueType, typename StateType> - void JaniNextStateGenerator<ValueType, StateType>::performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function<void (ValueType const&)> const& callback) { - auto rewardVariableIt = rewardVariables.begin(); - auto rewardVariableIte = rewardVariables.end(); - for (auto const& assignment : transientAssignments) { - while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) { - callback(storm::utility::zero<ValueType>()); - ++rewardVariableIt; - } - if (rewardVariableIt == rewardVariableIte) { - break; - } - if (*rewardVariableIt == assignment.getExpressionVariable()) { - callback(ValueType(this->evaluator.asRational(assignment.getAssignedExpression()))); - ++rewardVariableIt; - } - } - } - template<typename ValueType, typename StateType> std::vector<Choice<ValueType>> JaniNextStateGenerator<ValueType, StateType>::getSilentActionChoices(std::vector<uint64_t> const& locations, CompressedState const& state, StateToIdCallback stateToIdCallback) { std::vector<Choice<ValueType>> result; @@ -537,13 +521,12 @@ namespace storm { template<typename ValueType, typename StateType> std::size_t JaniNextStateGenerator<ValueType, StateType>::getNumberOfRewardModels() const { - return 0; + return rewardVariables.size(); } template<typename ValueType, typename StateType> RewardModelInformation JaniNextStateGenerator<ValueType, StateType>::getRewardModelInformation(uint64_t const& index) const { - STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Cannot retrieve reward model information."); - return RewardModelInformation("", false, false, false); + return rewardModelInformation[index]; } template<typename ValueType, typename StateType> @@ -551,6 +534,72 @@ namespace storm { return NextStateGenerator<ValueType, StateType>::label(states, initialStateIndices, deadlockStateIndices, {}); } + template<typename ValueType, typename StateType> + void JaniNextStateGenerator<ValueType, StateType>::performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function<void (ValueType const&)> const& callback) { + auto rewardVariableIt = rewardVariables.begin(); + auto rewardVariableIte = rewardVariables.end(); + for (auto const& assignment : transientAssignments) { + while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) { + callback(storm::utility::zero<ValueType>()); + ++rewardVariableIt; + } + if (rewardVariableIt == rewardVariableIte) { + break; + } + if (*rewardVariableIt == assignment.getExpressionVariable()) { + callback(ValueType(this->evaluator.asRational(assignment.getAssignedExpression()))); + ++rewardVariableIt; + } + } + } + + template<typename ValueType, typename StateType> + void JaniNextStateGenerator<ValueType, StateType>::buildRewardModelInformation() { + // Prepare all reward model information structs. + for (auto const& variable : rewardVariables) { + rewardModelInformation.emplace_back(variable.getName(), false, false, false); + } + + // Then fill them. + for (auto const& automaton : model.getAutomata()) { + for (auto const& location : automaton.getLocations()) { + auto rewardVariableIt = rewardVariables.begin(); + auto rewardVariableIte = rewardVariables.end(); + + for (auto const& assignment : location.getAssignments().getTransientAssignments()) { + while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) { + ++rewardVariableIt; + } + if (rewardVariableIt == rewardVariableIte) { + break; + } + if (*rewardVariableIt == assignment.getExpressionVariable()) { + rewardModelInformation[std::distance(rewardVariables.begin(), rewardVariableIt)].setHasStateRewards(); + ++rewardVariableIt; + } + } + } + + for (auto const& edge : automaton.getEdges()) { + auto rewardVariableIt = rewardVariables.begin(); + auto rewardVariableIte = rewardVariables.end(); + + for (auto const& assignment : edge.getAssignments().getTransientAssignments()) { + while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) { + ++rewardVariableIt; + } + if (rewardVariableIt == rewardVariableIte) { + break; + } + if (*rewardVariableIt == assignment.getExpressionVariable()) { + rewardModelInformation[std::distance(rewardVariables.begin(), rewardVariableIt)].setHasStateActionRewards(); + ++rewardVariableIt; + } + } + } + } + } + template class JaniNextStateGenerator<double>; #ifdef STORM_HAVE_CARL diff --git a/src/generator/JaniNextStateGenerator.h b/src/generator/JaniNextStateGenerator.h index f3202a569..d9932f60a 100644 --- a/src/generator/JaniNextStateGenerator.h +++ b/src/generator/JaniNextStateGenerator.h @@ -95,12 +95,19 @@ namespace storm { */ void performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function<void (ValueType const&)> const& callback); + /*! + * Builds the information structs for the reward models. + */ + void buildRewardModelInformation(); + /// The model used for the generation of next states. storm::jani::Model model; - // The transient variables of reward models that need to be considered. + /// The transient variables of reward models that need to be considered. std::vector<storm::expressions::Variable> rewardVariables; - + + /// A vector storing information about the corresponding reward models (variables). + std::vector<RewardModelInformation> rewardModelInformation; }; } diff --git a/src/generator/NextStateGenerator.cpp b/src/generator/NextStateGenerator.cpp index 9c1eefbd5..fccf7b783 100644 --- a/src/generator/NextStateGenerator.cpp +++ b/src/generator/NextStateGenerator.cpp @@ -211,6 +211,18 @@ namespace storm { return transitionRewards; } + void RewardModelInformation::setHasStateRewards() { + stateRewards = true; + } + + void RewardModelInformation::setHasStateActionRewards() { + stateActionRewards = true; + } + + void RewardModelInformation::setHasTransitionRewards() { + transitionRewards = true; + } + template<typename ValueType, typename StateType> NextStateGenerator<ValueType, StateType>::NextStateGenerator(storm::expressions::ExpressionManager const& expressionManager, VariableInformation const& variableInformation, NextStateGeneratorOptions const& options) : options(options), expressionManager(expressionManager.getSharedPointer()), variableInformation(variableInformation), evaluator(expressionManager), state(nullptr) { // Intentionally left empty. diff --git a/src/generator/NextStateGenerator.h b/src/generator/NextStateGenerator.h index 30a4157cd..553e7871d 100644 --- a/src/generator/NextStateGenerator.h +++ b/src/generator/NextStateGenerator.h @@ -148,6 +148,9 @@ namespace storm { bool hasStateActionRewards() const; bool hasTransitionRewards() const; + void setHasStateRewards(); + void setHasStateActionRewards(); + void setHasTransitionRewards(); private: std::string name; bool stateRewards; diff --git a/src/storage/SymbolicModelDescription.cpp b/src/storage/SymbolicModelDescription.cpp index 8d30575b7..adb1e2afc 100644 --- a/src/storage/SymbolicModelDescription.cpp +++ b/src/storage/SymbolicModelDescription.cpp @@ -47,6 +47,17 @@ namespace storm { return boost::get<storm::prism::Program>(modelDescription.get()); } + void SymbolicModelDescription::toJani(bool makeVariablesGlobal) { + if (this->isJaniModel()) { + return; + } + if (this->isPrismProgram()) { + modelDescription = this->asPrismProgram().toJani(makeVariablesGlobal); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot transform model description to the JANI format."); + } + } + void SymbolicModelDescription::preprocess(std::string const& constantDefinitionString) { if (this->isJaniModel()) { std::map<storm::expressions::Variable, storm::expressions::Expression> substitution = storm::utility::jani::parseConstantDefinitionString(this->asJaniModel(), constantDefinitionString); diff --git a/src/storage/SymbolicModelDescription.h b/src/storage/SymbolicModelDescription.h index 77da92d82..cd08f9ba0 100644 --- a/src/storage/SymbolicModelDescription.h +++ b/src/storage/SymbolicModelDescription.h @@ -24,6 +24,8 @@ namespace storm { storm::jani::Model const& asJaniModel() const; storm::prism::Program const& asPrismProgram() const; + void toJani(bool makeVariablesGlobal = true); + void preprocess(std::string const& constantDefinitionString = ""); private: From c2cab571f5655148a592184af3ce3fc8d0b0cf4d Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 12 Sep 2016 11:57:36 +0200 Subject: [PATCH 32/34] made tests work again Former-commit-id: bd3e831b0d5c031fae8e7a356e42d67302fb526a [formerly cef4348674ff65b4b4be0c43dba4d94ec3dc623f] Former-commit-id: 8fd0b70c1e7f2f2277c8ef95c0d95c635c03a783 --- src/cli/cli.cpp | 2 +- src/storage/SymbolicModelDescription.cpp | 23 +- src/storage/SymbolicModelDescription.h | 7 +- src/storage/prism/ToJaniConverter.cpp | 17 ++ .../builder/DdJaniModelBuilderTest.cpp | 239 ++++++++---------- .../SparseDtmcRegionModelCheckerTest.cpp | 14 +- .../SparseMdpRegionModelCheckerTest.cpp | 4 +- .../utility/ModelInstantiatorTest.cpp | 6 +- 8 files changed, 157 insertions(+), 155 deletions(-) diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 31a0a8afb..78cbcc042 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -219,7 +219,7 @@ namespace storm { // Get the string that assigns values to the unknown currently undefined constants in the model. std::string constantDefinitionString = ioSettings.getConstantDefinitionString(); - model.preprocess(constantDefinitionString); + model = model.preprocess(constantDefinitionString); // Then proceed to parsing the properties (if given), since the model we are building may depend on the property. std::vector<std::shared_ptr<storm::logic::Formula const>> formulas; diff --git a/src/storage/SymbolicModelDescription.cpp b/src/storage/SymbolicModelDescription.cpp index adb1e2afc..3bccf3b73 100644 --- a/src/storage/SymbolicModelDescription.cpp +++ b/src/storage/SymbolicModelDescription.cpp @@ -17,6 +17,14 @@ namespace storm { // Intentionally left empty. } + SymbolicModelDescription& SymbolicModelDescription::operator=(storm::jani::Model const& model) { + this->modelDescription = model; + } + + SymbolicModelDescription& SymbolicModelDescription::operator=(storm::prism::Program const& program) { + this->modelDescription = program; + } + bool SymbolicModelDescription::hasModel() const { return static_cast<bool>(modelDescription); } @@ -47,27 +55,26 @@ namespace storm { return boost::get<storm::prism::Program>(modelDescription.get()); } - void SymbolicModelDescription::toJani(bool makeVariablesGlobal) { + SymbolicModelDescription SymbolicModelDescription::toJani(bool makeVariablesGlobal) const { if (this->isJaniModel()) { - return; + return *this; } if (this->isPrismProgram()) { - modelDescription = this->asPrismProgram().toJani(makeVariablesGlobal); + return SymbolicModelDescription(this->asPrismProgram().toJani(makeVariablesGlobal)); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot transform model description to the JANI format."); } } - void SymbolicModelDescription::preprocess(std::string const& constantDefinitionString) { + SymbolicModelDescription SymbolicModelDescription::preprocess(std::string const& constantDefinitionString) const { if (this->isJaniModel()) { std::map<storm::expressions::Variable, storm::expressions::Expression> substitution = storm::utility::jani::parseConstantDefinitionString(this->asJaniModel(), constantDefinitionString); - this->modelDescription = this->asJaniModel().defineUndefinedConstants(substitution); - this->modelDescription = this->asJaniModel().substituteConstants(); + return SymbolicModelDescription(this->asJaniModel().defineUndefinedConstants(substitution).substituteConstants()); } else if (this->isPrismProgram()) { std::map<storm::expressions::Variable, storm::expressions::Expression> substitution = storm::utility::prism::parseConstantDefinitionString(this->asPrismProgram(), constantDefinitionString); - this->modelDescription = this->asPrismProgram().defineUndefinedConstants(substitution); - this->modelDescription = this->asPrismProgram().substituteConstants(); + return SymbolicModelDescription(this->asPrismProgram().defineUndefinedConstants(substitution).substituteConstants()); } + return *this; } } diff --git a/src/storage/SymbolicModelDescription.h b/src/storage/SymbolicModelDescription.h index cd08f9ba0..8b5b85d88 100644 --- a/src/storage/SymbolicModelDescription.h +++ b/src/storage/SymbolicModelDescription.h @@ -14,6 +14,9 @@ namespace storm { SymbolicModelDescription(storm::jani::Model const& model); SymbolicModelDescription(storm::prism::Program const& program); + SymbolicModelDescription& operator=(storm::jani::Model const& model); + SymbolicModelDescription& operator=(storm::prism::Program const& program); + bool hasModel() const; bool isJaniModel() const; bool isPrismProgram() const; @@ -24,9 +27,9 @@ namespace storm { storm::jani::Model const& asJaniModel() const; storm::prism::Program const& asPrismProgram() const; - void toJani(bool makeVariablesGlobal = true); + SymbolicModelDescription toJani(bool makeVariablesGlobal = true) const; - void preprocess(std::string const& constantDefinitionString = ""); + SymbolicModelDescription preprocess(std::string const& constantDefinitionString = "") const; private: boost::optional<boost::variant<storm::jani::Model, storm::prism::Program>> modelDescription; diff --git a/src/storage/prism/ToJaniConverter.cpp b/src/storage/prism/ToJaniConverter.cpp index 7c3d859b2..33ad88fef 100644 --- a/src/storage/prism/ToJaniConverter.cpp +++ b/src/storage/prism/ToJaniConverter.cpp @@ -137,11 +137,15 @@ namespace storm { } STORM_LOG_THROW(!rewardModel.hasTransitionRewards(), storm::exceptions::NotImplementedException, "Transition reward translation currently not implemented."); } + STORM_LOG_THROW(transientEdgeAssignments.empty() || transientLocationAssignments.empty() || !program.specifiesSystemComposition(), storm::exceptions::NotImplementedException, "Cannot translate reward models from PRISM to JANI that specify a custom system composition."); // Now create the separate JANI automata from the modules of the PRISM program. While doing so, we use the // previously built mapping to make variables global that are read by more than one module. bool firstModule = true; for (auto const& module : program.getModules()) { + // Keep track of the action indices contained in this module. + std::set<uint_fast64_t> actionIndicesOfModule; + storm::jani::Automaton automaton(module.getName()); for (auto const& variable : module.getIntegerVariables()) { 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()); @@ -184,6 +188,8 @@ namespace storm { } for (auto const& command : module.getCommands()) { + actionIndicesOfModule.insert(command.getActionIndex()); + boost::optional<storm::expressions::Expression> rateExpression; std::vector<storm::jani::EdgeDestination> destinations; if (program.getModelType() == Program::ModelType::CTMC || program.getModelType() == Program::ModelType::CTMDP) { @@ -224,6 +230,17 @@ namespace storm { automaton.addEdge(newEdge); } + // Now remove for all actions of this module the corresponding transient assignments, because we must + // not deal out this reward multiple times. + // NOTE: This only works for the standard composition and not for any custom compositions. This case + // must be checked for earlier. + for (auto actionIndex : actionIndicesOfModule) { + auto it = transientEdgeAssignments.find(actionIndex); + if (it != transientEdgeAssignments.end()) { + transientEdgeAssignments.erase(it); + } + } + janiModel.addAutomaton(automaton); firstModule = false; } diff --git a/test/functional/builder/DdJaniModelBuilderTest.cpp b/test/functional/builder/DdJaniModelBuilderTest.cpp index 1470e196d..3fc00e217 100644 --- a/test/functional/builder/DdJaniModelBuilderTest.cpp +++ b/test/functional/builder/DdJaniModelBuilderTest.cpp @@ -6,6 +6,7 @@ #include "src/storage/dd/Add.h" #include "src/storage/dd/Bdd.h" +#include "src/storage/SymbolicModelDescription.h" #include "src/models/symbolic/StandardRewardModel.h" #include "src/parser/PrismParser.h" @@ -16,78 +17,70 @@ #include "src/settings/modules/IOSettings.h" TEST(DdJaniModelBuilderTest_Sylvan, Dtmc) { - storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/die.pm"); - storm::jani::Model janiModel = program.toJani(true); + storm::storage::SymbolicModelDescription modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/die.pm"); + storm::jani::Model janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); - storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double> builder(janiModel); - std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::Sylvan>> model = builder.build(); + storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double> builder; + std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::Sylvan>> model = builder.build(janiModel); EXPECT_EQ(13ul, model->getNumberOfStates()); EXPECT_EQ(20ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/brp-16-2.pm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/brp-16-2.pm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(677ul, model->getNumberOfStates()); EXPECT_EQ(867ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/crowds-5-5.pm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/crowds-5-5.pm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(8607ul, model->getNumberOfStates()); EXPECT_EQ(15113ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader-3-5.pm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader-3-5.pm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(273ul, model->getNumberOfStates()); EXPECT_EQ(397ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/nand-5-2.pm"); - janiModel = program.toJani(true); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/nand-5-2.pm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double>(janiModel); - model = builder.build(); + model = builder.build(janiModel); EXPECT_EQ(1728ul, model->getNumberOfStates()); EXPECT_EQ(2505ul, model->getNumberOfTransitions()); } TEST(DdJaniModelBuilderTest_Cudd, Dtmc) { - storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/die.pm"); - storm::jani::Model janiModel = program.toJani(true); + storm::storage::SymbolicModelDescription modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/die.pm"); + storm::jani::Model janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); - storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double> builder(janiModel); - std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::CUDD>> model = builder.build(); + storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double> builder; + std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::CUDD>> model = builder.build(janiModel); EXPECT_EQ(13ul, model->getNumberOfStates()); EXPECT_EQ(20ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/brp-16-2.pm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/brp-16-2.pm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(677ul, model->getNumberOfStates()); EXPECT_EQ(867ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/crowds-5-5.pm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/crowds-5-5.pm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(8607ul, model->getNumberOfStates()); EXPECT_EQ(15113ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader-3-5.pm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader-3-5.pm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(273ul, model->getNumberOfStates()); EXPECT_EQ(397ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/nand-5-2.pm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/nand-5-2.pm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(1728ul, model->getNumberOfStates()); EXPECT_EQ(2505ul, model->getNumberOfTransitions()); } @@ -96,38 +89,34 @@ TEST(DdJaniModelBuilderTest_Sylvan, Ctmc) { // Set the PRISM compatibility mode temporarily. It is set to its old value once the returned object is destructed. std::unique_ptr<storm::settings::SettingMemento> enablePrismCompatibility = storm::settings::mutableIOSettings().overridePrismCompatibilityMode(true); - storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/cluster2.sm"); - storm::jani::Model janiModel = program.toJani(true); - storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double> builder(janiModel); - std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::Sylvan>> model = builder.build(); + storm::storage::SymbolicModelDescription modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/cluster2.sm"); + storm::jani::Model janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double> builder; + std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::Sylvan>> model = builder.build(janiModel); EXPECT_EQ(276ul, model->getNumberOfStates()); EXPECT_EQ(1120ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/embedded2.sm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/embedded2.sm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(3478ul, model->getNumberOfStates()); EXPECT_EQ(14639ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/polling2.sm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/polling2.sm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(12ul, model->getNumberOfStates()); EXPECT_EQ(22ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/fms2.sm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/fms2.sm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(810ul, model->getNumberOfStates()); EXPECT_EQ(3699ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/tandem5.sm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/tandem5.sm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(66ul, model->getNumberOfStates()); EXPECT_EQ(189ul, model->getNumberOfTransitions()); } @@ -136,47 +125,43 @@ TEST(DdJaniModelBuilderTest_Cudd, Ctmc) { // Set the PRISM compatibility mode temporarily. It is set to its old value once the returned object is destructed. std::unique_ptr<storm::settings::SettingMemento> enablePrismCompatibility = storm::settings::mutableIOSettings().overridePrismCompatibilityMode(true); - storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/cluster2.sm"); - storm::jani::Model janiModel = program.toJani(true); - storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double> builder(janiModel); - std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::CUDD>> model = builder.build(); + storm::storage::SymbolicModelDescription modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/cluster2.sm"); + storm::jani::Model janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double> builder; + std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::CUDD>> model = builder.build(janiModel); EXPECT_EQ(276ul, model->getNumberOfStates()); EXPECT_EQ(1120ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/embedded2.sm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/embedded2.sm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(3478ul, model->getNumberOfStates()); EXPECT_EQ(14639ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/polling2.sm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/polling2.sm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(12ul, model->getNumberOfStates()); EXPECT_EQ(22ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/fms2.sm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/fms2.sm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(810ul, model->getNumberOfStates()); EXPECT_EQ(3699ul, model->getNumberOfTransitions()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/tandem5.sm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/tandem5.sm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_EQ(66ul, model->getNumberOfStates()); EXPECT_EQ(189ul, model->getNumberOfTransitions()); } TEST(DdJaniModelBuilderTest_Sylvan, Mdp) { - storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/two_dice.nm"); - storm::jani::Model janiModel = program.toJani(true); - storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double> builder(janiModel); - std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::Sylvan>> model = builder.build(); + storm::storage::SymbolicModelDescription modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/two_dice.nm"); + storm::jani::Model janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double> builder; + std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::Sylvan>> model = builder.build(janiModel); EXPECT_TRUE(model->getType() == storm::models::ModelType::Mdp); std::shared_ptr<storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan>> mdp = model->as<storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan>>(); @@ -185,10 +170,9 @@ TEST(DdJaniModelBuilderTest_Sylvan, Mdp) { EXPECT_EQ(436ul, mdp->getNumberOfTransitions()); EXPECT_EQ(254ul, mdp->getNumberOfChoices()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader3.nm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader3.nm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_TRUE(model->getType() == storm::models::ModelType::Mdp); mdp = model->as<storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan>>(); @@ -197,10 +181,9 @@ TEST(DdJaniModelBuilderTest_Sylvan, Mdp) { EXPECT_EQ(654ul, mdp->getNumberOfTransitions()); EXPECT_EQ(573ul, mdp->getNumberOfChoices()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/coin2-2.nm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/coin2-2.nm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_TRUE(model->getType() == storm::models::ModelType::Mdp); mdp = model->as<storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan>>(); @@ -209,10 +192,9 @@ TEST(DdJaniModelBuilderTest_Sylvan, Mdp) { EXPECT_EQ(492ul, mdp->getNumberOfTransitions()); EXPECT_EQ(400ul, mdp->getNumberOfChoices()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/csma2-2.nm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/csma2-2.nm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_TRUE(model->getType() == storm::models::ModelType::Mdp); mdp = model->as<storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan>>(); @@ -221,10 +203,9 @@ TEST(DdJaniModelBuilderTest_Sylvan, Mdp) { EXPECT_EQ(1282ul, mdp->getNumberOfTransitions()); EXPECT_EQ(1054ul, mdp->getNumberOfChoices()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/firewire3-0.5.nm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/firewire3-0.5.nm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_TRUE(model->getType() == storm::models::ModelType::Mdp); mdp = model->as<storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan>>(); @@ -233,10 +214,9 @@ TEST(DdJaniModelBuilderTest_Sylvan, Mdp) { EXPECT_EQ(5585ul, mdp->getNumberOfTransitions()); EXPECT_EQ(5519ul, mdp->getNumberOfChoices()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/wlan0-2-2.nm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::Sylvan, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/wlan0-2-2.nm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_TRUE(model->getType() == storm::models::ModelType::Mdp); mdp = model->as<storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan>>(); @@ -247,10 +227,10 @@ TEST(DdJaniModelBuilderTest_Sylvan, Mdp) { } TEST(DdJaniModelBuilderTest_Cudd, Mdp) { - storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/two_dice.nm"); - storm::jani::Model janiModel = program.toJani(true); - storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double> builder(janiModel); - std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::CUDD>> model = builder.build(); + storm::storage::SymbolicModelDescription modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/two_dice.nm"); + storm::jani::Model janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double> builder; + std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::CUDD>> model = builder.build(janiModel); EXPECT_TRUE(model->getType() == storm::models::ModelType::Mdp); std::shared_ptr<storm::models::symbolic::Mdp<storm::dd::DdType::CUDD>> mdp = model->as<storm::models::symbolic::Mdp<storm::dd::DdType::CUDD>>(); @@ -259,10 +239,9 @@ TEST(DdJaniModelBuilderTest_Cudd, Mdp) { EXPECT_EQ(436ul, mdp->getNumberOfTransitions()); EXPECT_EQ(254ul, mdp->getNumberOfChoices()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader3.nm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader3.nm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_TRUE(model->getType() == storm::models::ModelType::Mdp); mdp = model->as<storm::models::symbolic::Mdp<storm::dd::DdType::CUDD>>(); @@ -271,10 +250,9 @@ TEST(DdJaniModelBuilderTest_Cudd, Mdp) { EXPECT_EQ(654ul, mdp->getNumberOfTransitions()); EXPECT_EQ(573ul, mdp->getNumberOfChoices()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/coin2-2.nm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/coin2-2.nm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_TRUE(model->getType() == storm::models::ModelType::Mdp); mdp = model->as<storm::models::symbolic::Mdp<storm::dd::DdType::CUDD>>(); @@ -283,10 +261,9 @@ TEST(DdJaniModelBuilderTest_Cudd, Mdp) { EXPECT_EQ(492ul, mdp->getNumberOfTransitions()); EXPECT_EQ(400ul, mdp->getNumberOfChoices()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/csma2-2.nm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/csma2-2.nm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_TRUE(model->getType() == storm::models::ModelType::Mdp); mdp = model->as<storm::models::symbolic::Mdp<storm::dd::DdType::CUDD>>(); @@ -295,10 +272,9 @@ TEST(DdJaniModelBuilderTest_Cudd, Mdp) { EXPECT_EQ(1282ul, mdp->getNumberOfTransitions()); EXPECT_EQ(1054ul, mdp->getNumberOfChoices()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/firewire3-0.5.nm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/firewire3-0.5.nm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_TRUE(model->getType() == storm::models::ModelType::Mdp); mdp = model->as<storm::models::symbolic::Mdp<storm::dd::DdType::CUDD>>(); @@ -307,10 +283,9 @@ TEST(DdJaniModelBuilderTest_Cudd, Mdp) { EXPECT_EQ(5585ul, mdp->getNumberOfTransitions()); EXPECT_EQ(5519ul, mdp->getNumberOfChoices()); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/wlan0-2-2.nm"); - janiModel = program.toJani(true); - builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double>(janiModel); - model = builder.build(); + modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/wlan0-2-2.nm"); + janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + model = builder.build(janiModel); EXPECT_TRUE(model->getType() == storm::models::ModelType::Mdp); mdp = model->as<storm::models::symbolic::Mdp<storm::dd::DdType::CUDD>>(); @@ -321,8 +296,8 @@ TEST(DdJaniModelBuilderTest_Cudd, Mdp) { } TEST(DdJaniModelBuilderTest_Cudd, IllegalSynchronizingWrites) { - storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/coin2-2-illegalSynchronizingWrite.nm"); - storm::jani::Model janiModel = program.toJani(true); - storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double> builder(janiModel); - EXPECT_THROW(std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::CUDD>> model = builder.build(), storm::exceptions::WrongFormatException); + storm::storage::SymbolicModelDescription modelDescription = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/coin2-2-illegalSynchronizingWrite.nm"); + storm::jani::Model janiModel = modelDescription.toJani(true).preprocess().asJaniModel(); + storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double> builder; + EXPECT_THROW(std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::CUDD>> model = builder.build(janiModel), storm::exceptions::WrongFormatException); } \ No newline at end of file diff --git a/test/functional/modelchecker/SparseDtmcRegionModelCheckerTest.cpp b/test/functional/modelchecker/SparseDtmcRegionModelCheckerTest.cpp index f14808886..aed634c75 100644 --- a/test/functional/modelchecker/SparseDtmcRegionModelCheckerTest.cpp +++ b/test/functional/modelchecker/SparseDtmcRegionModelCheckerTest.cpp @@ -24,7 +24,7 @@ TEST(SparseDtmcRegionModelCheckerTest, Brp_Prob) { // Program and formula storm::prism::Program program = storm::parseProgram(programFile); program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForProgram(formulaAsString, program);; + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForPrismProgram(formulaAsString, program);; std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); auto const& regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>(); storm::modelchecker::region::SparseRegionModelCheckerSettings settings(regionSettings.getSampleMode(), regionSettings.getApproxMode(), regionSettings.getSmtMode()); @@ -95,7 +95,7 @@ TEST(SparseDtmcRegionModelCheckerTest, Brp_Rew) { storm::prism::Program program = storm::parseProgram(programFile); program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForProgram(formulaAsString, program);; + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForPrismProgram(formulaAsString, program);; std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); auto const& regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>(); storm::modelchecker::region::SparseRegionModelCheckerSettings settings(regionSettings.getSampleMode(), regionSettings.getApproxMode(), regionSettings.getSmtMode()); @@ -189,7 +189,7 @@ TEST(SparseDtmcRegionModelCheckerTest, Brp_Rew_Infty) { carl::VariablePool::getInstance().clear(); storm::prism::Program program = storm::parseProgram(programFile); program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForProgram(formulaAsString, program);; + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForPrismProgram(formulaAsString, program);; std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); auto const& regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>(); storm::modelchecker::region::SparseRegionModelCheckerSettings settings(regionSettings.getSampleMode(), regionSettings.getApproxMode(), regionSettings.getSmtMode()); @@ -233,7 +233,7 @@ TEST(SparseDtmcRegionModelCheckerTest, Brp_Rew_4Par) { carl::VariablePool::getInstance().clear(); storm::prism::Program program = storm::parseProgram(programFile); program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForProgram(formulaAsString, program);; + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForPrismProgram(formulaAsString, program);; std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); auto const& regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>(); storm::modelchecker::region::SparseRegionModelCheckerSettings settings(regionSettings.getSampleMode(), regionSettings.getApproxMode(), regionSettings.getSmtMode()); @@ -297,7 +297,7 @@ TEST(SparseDtmcRegionModelCheckerTest, Crowds_Prob) { storm::prism::Program program = storm::parseProgram(programFile); program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForProgram(formulaAsString, program);; + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForPrismProgram(formulaAsString, program);; std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); auto const& regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>(); storm::modelchecker::region::SparseRegionModelCheckerSettings settings(regionSettings.getSampleMode(), regionSettings.getApproxMode(), regionSettings.getSmtMode()); @@ -389,7 +389,7 @@ TEST(SparseDtmcRegionModelCheckerTest, Crowds_Prob_1Par) { storm::prism::Program program = storm::parseProgram(programFile); program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForProgram(formulaAsString, program);; + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForPrismProgram(formulaAsString, program);; std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); auto const& regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>(); storm::modelchecker::region::SparseRegionModelCheckerSettings settings(regionSettings.getSampleMode(), regionSettings.getApproxMode(), regionSettings.getSmtMode()); @@ -455,7 +455,7 @@ TEST(SparseDtmcRegionModelCheckerTest, Crowds_Prob_Const) { storm::prism::Program program = storm::parseProgram(programFile); program = storm::utility::prism::preprocess(program, constantsAsString); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForProgram(formulaAsString, program);; + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForPrismProgram(formulaAsString, program);; std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>(); auto const& regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>(); storm::modelchecker::region::SparseRegionModelCheckerSettings settings(regionSettings.getSampleMode(), regionSettings.getApproxMode(), regionSettings.getSmtMode()); diff --git a/test/functional/modelchecker/SparseMdpRegionModelCheckerTest.cpp b/test/functional/modelchecker/SparseMdpRegionModelCheckerTest.cpp index 1ceb6c4e6..2b2aa9d2c 100644 --- a/test/functional/modelchecker/SparseMdpRegionModelCheckerTest.cpp +++ b/test/functional/modelchecker/SparseMdpRegionModelCheckerTest.cpp @@ -23,7 +23,7 @@ TEST(SparseMdpRegionModelCheckerTest, two_dice_Prob) { carl::VariablePool::getInstance().clear(); storm::prism::Program program = storm::parseProgram(programFile); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForProgram(formulaFile, program); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForPrismProgram(formulaFile, program); std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); auto const& regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>(); storm::modelchecker::region::SparseRegionModelCheckerSettings settings(regionSettings.getSampleMode(), regionSettings.getApproxMode(), regionSettings.getSmtMode()); @@ -91,7 +91,7 @@ TEST(SparseMdpRegionModelCheckerTest, coin_Prob) { carl::VariablePool::getInstance().clear(); storm::prism::Program program = storm::parseProgram(programFile); - std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForProgram(formulaAsString, program); + std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::parseFormulasForPrismProgram(formulaAsString, program); std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>(); auto const& regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>(); storm::modelchecker::region::SparseRegionModelCheckerSettings settings(regionSettings.getSampleMode(), regionSettings.getApproxMode(), regionSettings.getSmtMode()); diff --git a/test/functional/utility/ModelInstantiatorTest.cpp b/test/functional/utility/ModelInstantiatorTest.cpp index 2dd74c66a..d1319613c 100644 --- a/test/functional/utility/ModelInstantiatorTest.cpp +++ b/test/functional/utility/ModelInstantiatorTest.cpp @@ -26,7 +26,7 @@ TEST(ModelInstantiatorTest, BrpProb) { // Program and formula storm::prism::Program program = storm::parseProgram(programFile); program.checkValidity(); - std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::parseFormulasForProgram(formulaAsString, program); + std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::parseFormulasForPrismProgram(formulaAsString, program); ASSERT_TRUE(formulas.size()==1); // Parametric model storm::generator::NextStateGeneratorOptions options(*formulas.front()); @@ -144,7 +144,7 @@ TEST(ModelInstantiatorTest, Brp_Rew) { // Program and formula storm::prism::Program program = storm::parseProgram(programFile); program.checkValidity(); - std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::parseFormulasForProgram(formulaAsString, program); + std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::parseFormulasForPrismProgram(formulaAsString, program); ASSERT_TRUE(formulas.size()==1); // Parametric model storm::generator::NextStateGeneratorOptions options(*formulas.front()); @@ -214,7 +214,7 @@ TEST(ModelInstantiatorTest, Consensus) { // Program and formula storm::prism::Program program = storm::parseProgram(programFile); program.checkValidity(); - std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::parseFormulasForProgram(formulaAsString, program); + std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::parseFormulasForPrismProgram(formulaAsString, program); ASSERT_TRUE(formulas.size()==1); // Parametric model storm::generator::NextStateGeneratorOptions options(*formulas.front()); From 2a7e4a3c55705661f6329996535ec2d6ce9b14cd Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Mon, 12 Sep 2016 13:41:49 +0200 Subject: [PATCH 33/34] towards DD-based JANI rewards Former-commit-id: 36d6cfbca394e6973275ce26607276b3ccf8091b [formerly c9d50742926cad18333a8fdbf8f358f1acc85734] Former-commit-id: b8fe7376b328e1a485f38f7d70a46ca5ac5d6a48 --- src/builder/DdJaniModelBuilder.cpp | 78 ++++++++++++++++++++++-- src/builder/DdJaniModelBuilder.h | 10 +++ src/generator/JaniNextStateGenerator.cpp | 9 ++- 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/src/builder/DdJaniModelBuilder.cpp b/src/builder/DdJaniModelBuilder.cpp index a2b837080..1a61b51c0 100644 --- a/src/builder/DdJaniModelBuilder.cpp +++ b/src/builder/DdJaniModelBuilder.cpp @@ -102,6 +102,16 @@ namespace storm { } } + template <storm::dd::DdType Type, typename ValueType> + std::set<std::string> const& DdJaniModelBuilder<Type, ValueType>::Options::getRewardModelNames() const { + return rewardModelsToBuild; + } + + template <storm::dd::DdType Type, typename ValueType> + bool DdJaniModelBuilder<Type, ValueType>::Options::isBuildAllRewardModelsSet() const { + return buildAllRewardModels; + } + template <storm::dd::DdType Type, typename ValueType> struct CompositionVariables { CompositionVariables() : manager(std::make_shared<storm::dd::DdManager<Type>>()), @@ -356,7 +366,7 @@ namespace storm { template <storm::dd::DdType Type, typename ValueType> class SystemComposer : public storm::jani::CompositionVisitor { public: - SystemComposer(storm::jani::Model const& model, CompositionVariables<Type, ValueType> const& variables) : model(model), variables(variables) { + SystemComposer(storm::jani::Model const& model, CompositionVariables<Type, ValueType> const& variables, std::vector<storm::expressions::Variable> const& transientVariables) : model(model), variables(variables), transientVariables(transientVariables) { // Intentionally left empty. } @@ -368,6 +378,9 @@ namespace storm { // The variable to use when building an automaton. CompositionVariables<Type, ValueType> const& variables; + + // The transient variables to consider during system composition. + std::vector<storm::expressions::Variable> transientVariables; }; // This structure represents an edge destination. @@ -906,7 +919,7 @@ namespace storm { public: // This structure represents an edge. struct EdgeDd { - EdgeDd(storm::dd::Add<Type> const& guard = storm::dd::Add<Type>(), storm::dd::Add<Type, ValueType> const& transitions = storm::dd::Add<Type, ValueType>(), std::set<storm::expressions::Variable> const& writtenGlobalVariables = {}) : guard(guard), transitions(transitions), writtenGlobalVariables(writtenGlobalVariables) { + EdgeDd(storm::dd::Add<Type> const& guard = storm::dd::Add<Type>(), storm::dd::Add<Type, ValueType> const& transitions = storm::dd::Add<Type, ValueType>(), std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientVariableAssignments = {}, std::set<storm::expressions::Variable> const& writtenGlobalVariables = {}) : guard(guard), transitions(transitions), transientVariableAssignments(transientVariableAssignments), writtenGlobalVariables(writtenGlobalVariables) { // Intentionally left empty. } @@ -916,6 +929,9 @@ namespace storm { // A DD that represents the transitions of this edge. storm::dd::Add<Type, ValueType> transitions; + // A mapping from transient variables to the DDs representing their value assignments. + std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientVariableAssignments; + // The set of global variables written by this edge. std::set<storm::expressions::Variable> writtenGlobalVariables; }; @@ -994,7 +1010,7 @@ namespace storm { }; - CombinedEdgesSystemComposer(storm::jani::Model const& model, CompositionVariables<Type, ValueType> const& variables) : SystemComposer<Type, ValueType>(model, variables) { + CombinedEdgesSystemComposer(storm::jani::Model const& model, CompositionVariables<Type, ValueType> const& variables, std::vector<storm::expressions::Variable> const& transientVariables) : SystemComposer<Type, ValueType>(model, variables, transientVariables) { // Intentionally left empty. } @@ -1307,6 +1323,27 @@ namespace storm { transitions *= this->variables.rowExpressionAdapter->translateExpression(edge.getRate()); } + // Finally treat the transient assignments. + if (!this->transientVariables.empty()) { + auto transientAssignments = edge.getAssignments().getTransientAssignments(); + + auto transientVariableIt = this->transientVariables.begin(); + auto transientVariableIte = this->transientVariables.end(); + for (auto const& assignment : transientAssignments) { + while (transientVariableIt != transientVariableIte && *transientVariableIt < assignment.getExpressionVariable()) { +// callback(storm::utility::zero<ValueType>()); + ++transientVariableIt; + } + if (transientVariableIt == transientVariableIte) { + break; + } + if (*transientVariableIt == assignment.getExpressionVariable()) { +// callback(ValueType(this->evaluator.asRational(assignment.getAssignedExpression()))); + ++transientVariableIt; + } + } + } + return EdgeDd(guard, guard * transitions, globalVariablesInSomeDestination); } else { return EdgeDd(this->variables.manager->template getAddZero<ValueType>(), this->variables.manager->template getAddZero<ValueType>()); @@ -1715,6 +1752,36 @@ namespace storm { return deadlockStates; } + template <storm::dd::DdType Type, typename ValueType> + std::vector<storm::expressions::Variable> selectRewardVariables(storm::jani::Model const& model, typename DdJaniModelBuilder<Type, ValueType>::Options const& options) { + std::vector<storm::expressions::Variable> result; + if (options.isBuildAllRewardModelsSet()) { + for (auto const& variable : model.getGlobalVariables()) { + if (variable.isTransient()) { + result.push_back(variable.getExpressionVariable()); + } + } + } else { + auto const& globalVariables = model.getGlobalVariables(); + for (auto const& rewardModelName : options.getRewardModelNames()) { + if (globalVariables.hasVariable(rewardModelName)) { + result.push_back(globalVariables.getVariable(rewardModelName).getExpressionVariable()); + } else { + STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException, "Cannot build unknown reward model '" << rewardModelName << "'."); + STORM_LOG_THROW(globalVariables.getNumberOfTransientVariables() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous."); + } + } + + // If no reward model was yet added, but there was one that was given in the options, we try to build the + // standard reward model. + if (result.empty() && !options.getRewardModelNames().empty()) { + result.push_back(globalVariables.getTransientVariables().front()->getExpressionVariable()); + } + } + + return result; + } + template <storm::dd::DdType Type, typename ValueType> std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdJaniModelBuilder<Type, ValueType>::build(storm::jani::Model const& model, Options const& options) { if (model.hasUndefinedConstants()) { @@ -1732,9 +1799,12 @@ namespace storm { CompositionVariableCreator<Type, ValueType> variableCreator(model); CompositionVariables<Type, ValueType> variables = variableCreator.create(); + // Determine which transient assignments need to be considered in the building process. + std::vector<storm::expressions::Variable> rewardVariables = selectRewardVariables<Type, ValueType>(model, options); + // Create a builder to compose and build the model. // SeparateEdgesSystemComposer<Type, ValueType> composer(model, variables); - CombinedEdgesSystemComposer<Type, ValueType> composer(model, variables); + CombinedEdgesSystemComposer<Type, ValueType> composer(model, variables, rewardVariables); ComposerResult<Type, ValueType> system = composer.compose(); // Postprocess the variables in place. diff --git a/src/builder/DdJaniModelBuilder.h b/src/builder/DdJaniModelBuilder.h index f1b16af1a..dd99f5fcb 100644 --- a/src/builder/DdJaniModelBuilder.h +++ b/src/builder/DdJaniModelBuilder.h @@ -59,6 +59,16 @@ namespace storm { */ void setTerminalStatesFromFormula(storm::logic::Formula const& formula); + /*! + * Retrieves the names of the reward models to build. + */ + std::set<std::string> const& getRewardModelNames() const; + + /*! + * Retrieves whether the flag to build all reward models is set. + */ + bool isBuildAllRewardModelsSet() const; + // A flag that indicates whether or not all reward models are to be build. bool buildAllRewardModels; diff --git a/src/generator/JaniNextStateGenerator.cpp b/src/generator/JaniNextStateGenerator.cpp index c0ae75160..23a3a7068 100644 --- a/src/generator/JaniNextStateGenerator.cpp +++ b/src/generator/JaniNextStateGenerator.cpp @@ -34,9 +34,8 @@ namespace storm { } } } else { - auto const& globalVariables = model.getGlobalVariables(); - // Extract the reward models from the program based on the names we were given. + auto const& globalVariables = model.getGlobalVariables(); for (auto const& rewardModelName : this->options.getRewardModelNames()) { if (globalVariables.hasVariable(rewardModelName)) { rewardVariables.push_back(globalVariables.getVariable(rewardModelName).getExpressionVariable()); @@ -536,6 +535,12 @@ namespace storm { template<typename ValueType, typename StateType> void JaniNextStateGenerator<ValueType, StateType>::performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function<void (ValueType const&)> const& callback) { + // If there are no reward variables, there is no need to iterate at all. + if (rewardVariables.empty()) { + return; + } + + // Otherwise, perform the callback for all selected reward variables. auto rewardVariableIt = rewardVariables.begin(); auto rewardVariableIte = rewardVariables.end(); for (auto const& assignment : transientAssignments) { From 99badd02c54f438e00d9437ccce96661a9dc4c41 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Tue, 13 Sep 2016 11:06:34 +0200 Subject: [PATCH 34/34] more work towards JANI reward models Former-commit-id: 4be9f840c4742c7f9d6d42e29b50aa3e424e3d34 [formerly be673543113b2335f7bb59bc6a57c7c595d60b16] Former-commit-id: b8ea6172e77b792c739a9f80badcdc261eeabfaa --- examples/dtmc/die/die.pm | 1 + src/builder/DdJaniModelBuilder.cpp | 189 ++++++++++++++---- src/builder/DdPrismModelBuilder.cpp | 2 + src/cli/cli.cpp | 3 + src/generator/JaniNextStateGenerator.cpp | 7 +- .../prctl/helper/SymbolicDtmcPrctlHelper.cpp | 2 +- src/settings/modules/IOSettings.cpp | 10 + src/settings/modules/IOSettings.h | 8 + src/storage/SymbolicModelDescription.cpp | 2 + src/storage/jani/Automaton.cpp | 10 +- src/storage/jani/Automaton.h | 7 +- src/storage/jani/Location.cpp | 6 + src/storage/jani/Location.h | 5 + src/storage/jani/Model.cpp | 6 + src/storage/jani/Model.h | 5 + 15 files changed, 222 insertions(+), 41 deletions(-) diff --git a/examples/dtmc/die/die.pm b/examples/dtmc/die/die.pm index dacde8a79..c5634bf4f 100644 --- a/examples/dtmc/die/die.pm +++ b/examples/dtmc/die/die.pm @@ -29,3 +29,4 @@ label "three" = s=7&d=3; label "four" = s=7&d=4; label "five" = s=7&d=5; label "six" = s=7&d=6; +label "end" = s=7; diff --git a/src/builder/DdJaniModelBuilder.cpp b/src/builder/DdJaniModelBuilder.cpp index 1a61b51c0..5ab18683b 100644 --- a/src/builder/DdJaniModelBuilder.cpp +++ b/src/builder/DdJaniModelBuilder.cpp @@ -241,6 +241,7 @@ namespace storm { // Start by creating a meta variable for the location of the automaton. std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = result.manager->addMetaVariable("l_" + automaton.getName(), 0, automaton.getNumberOfLocations() - 1); result.automatonToLocationVariableMap[automaton.getName()] = variablePair; + result.rowColumnMetaVariablePairs.push_back(variablePair); // Add the location variable to the row/column variables. result.rowMetaVariables.insert(variablePair.first); @@ -353,11 +354,13 @@ namespace storm { template <storm::dd::DdType Type, typename ValueType> struct ComposerResult { - ComposerResult(storm::dd::Add<Type, ValueType> const& transitions, storm::dd::Bdd<Type> const& illegalFragment, uint64_t numberOfNondeterminismVariables = 0) : transitions(transitions), illegalFragment(illegalFragment), numberOfNondeterminismVariables(numberOfNondeterminismVariables) { + ComposerResult(storm::dd::Add<Type, ValueType> const& transitions, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientLocationAssignments, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientEdgeAssignments, storm::dd::Bdd<Type> const& illegalFragment, uint64_t numberOfNondeterminismVariables = 0) : transitions(transitions), transientLocationAssignments(transientLocationAssignments), transientEdgeAssignments(transientEdgeAssignments), illegalFragment(illegalFragment), numberOfNondeterminismVariables(numberOfNondeterminismVariables) { // Intentionally left empty. } storm::dd::Add<Type, ValueType> transitions; + std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientLocationAssignments; + std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments; storm::dd::Bdd<Type> illegalFragment; uint64_t numberOfNondeterminismVariables; }; @@ -919,7 +922,7 @@ namespace storm { public: // This structure represents an edge. struct EdgeDd { - EdgeDd(storm::dd::Add<Type> const& guard = storm::dd::Add<Type>(), storm::dd::Add<Type, ValueType> const& transitions = storm::dd::Add<Type, ValueType>(), std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientVariableAssignments = {}, std::set<storm::expressions::Variable> const& writtenGlobalVariables = {}) : guard(guard), transitions(transitions), transientVariableAssignments(transientVariableAssignments), writtenGlobalVariables(writtenGlobalVariables) { + EdgeDd(storm::dd::Add<Type> const& guard = storm::dd::Add<Type>(), storm::dd::Add<Type, ValueType> const& transitions = storm::dd::Add<Type, ValueType>(), std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientEdgeAssignments = {}, std::set<storm::expressions::Variable> const& writtenGlobalVariables = {}) : guard(guard), transitions(transitions), transientEdgeAssignments(transientEdgeAssignments), writtenGlobalVariables(writtenGlobalVariables) { // Intentionally left empty. } @@ -930,7 +933,7 @@ namespace storm { storm::dd::Add<Type, ValueType> transitions; // A mapping from transient variables to the DDs representing their value assignments. - std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientVariableAssignments; + std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments; // The set of global variables written by this edge. std::set<storm::expressions::Variable> writtenGlobalVariables; @@ -938,7 +941,7 @@ namespace storm { // This structure represents an edge. struct ActionDd { - ActionDd(storm::dd::Add<Type> const& guard = storm::dd::Add<Type>(), storm::dd::Add<Type, ValueType> const& transitions = storm::dd::Add<Type, ValueType>(), std::pair<uint64_t, uint64_t> localNondeterminismVariables = std::pair<uint64_t, uint64_t>(0, 0), std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> const& variableToWritingFragment = {}, storm::dd::Bdd<Type> const& illegalFragment = storm::dd::Bdd<Type>()) : guard(guard), transitions(transitions), localNondeterminismVariables(localNondeterminismVariables), variableToWritingFragment(variableToWritingFragment), illegalFragment(illegalFragment) { + ActionDd(storm::dd::Add<Type> const& guard = storm::dd::Add<Type>(), storm::dd::Add<Type, ValueType> const& transitions = storm::dd::Add<Type, ValueType>(), std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientEdgeAssignments = {}, std::pair<uint64_t, uint64_t> localNondeterminismVariables = std::pair<uint64_t, uint64_t>(0, 0), std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> const& variableToWritingFragment = {}, storm::dd::Bdd<Type> const& illegalFragment = storm::dd::Bdd<Type>()) : guard(guard), transitions(transitions), transientEdgeAssignments(transientEdgeAssignments), localNondeterminismVariables(localNondeterminismVariables), variableToWritingFragment(variableToWritingFragment), illegalFragment(illegalFragment) { // Intentionally left empty. } @@ -960,6 +963,9 @@ namespace storm { // A DD that represents the transitions of this edge. storm::dd::Add<Type, ValueType> transitions; + // A mapping from transient variables to their assignments. + std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments; + // The local nondeterminism variables used by this action DD, given as the lowest std::pair<uint64_t, uint64_t> localNondeterminismVariables; @@ -974,7 +980,7 @@ namespace storm { // This structure represents a subcomponent of a composition. struct AutomatonDd { - AutomatonDd(storm::dd::Add<Type, ValueType> const& identity) : actionIndexToAction(), identity(identity), localNondeterminismVariables(std::make_pair<uint64_t, uint64_t>(0, 0)) { + AutomatonDd(storm::dd::Add<Type, ValueType> const& identity, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientLocationAssignments = {}) : actionIndexToAction(), transientLocationAssignments(transientLocationAssignments), identity(identity), localNondeterminismVariables(std::make_pair<uint64_t, uint64_t>(0, 0)) { // Intentionally left empty. } @@ -1002,6 +1008,9 @@ namespace storm { // A mapping from action indices to the action DDs. std::map<uint64_t, ActionDd> actionIndexToAction; + // A mapping from transient variables to their location-based transient assignment values. + std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientLocationAssignments; + // The identity of the automaton's variables. storm::dd::Add<Type, ValueType> identity; @@ -1094,6 +1103,7 @@ namespace storm { private: AutomatonDd composeInParallel(AutomatonDd const& automaton1, AutomatonDd const& automaton2, std::set<uint64_t> const& synchronizingActionIndices) { AutomatonDd result(automaton1); + result.transientLocationAssignments = joinTransientAssignmentMaps(automaton1.transientLocationAssignments, automaton2.transientLocationAssignments); // Treat all actions of the first automaton. for (auto const& action1 : automaton1.actionIndexToAction) { @@ -1117,7 +1127,7 @@ namespace storm { } else { // If only the first automaton has this action, we only need to apply the identity of the // second automaton. - result.actionIndexToAction[action1.first] = ActionDd(action1.second.guard, action1.second.transitions * automaton2.identity, action1.second.localNondeterminismVariables, action1.second.variableToWritingFragment, action1.second.illegalFragment); + result.actionIndexToAction[action1.first] = ActionDd(action1.second.guard, action1.second.transitions * automaton2.identity, action1.second.transientEdgeAssignments, action1.second.localNondeterminismVariables, action1.second.variableToWritingFragment, action1.second.illegalFragment); } } } @@ -1130,7 +1140,7 @@ namespace storm { if (synchronizingActionIndices.find(action2.first) == synchronizingActionIndices.end()) { // If only the second automaton has this action, we only need to apply the identity of the // first automaton. - result.actionIndexToAction[action2.first] = ActionDd(action2.second.guard, action2.second.transitions * automaton1.identity, action2.second.localNondeterminismVariables, action2.second.variableToWritingFragment, action2.second.illegalFragment); + result.actionIndexToAction[action2.first] = ActionDd(action2.second.guard, action2.second.transitions * automaton1.identity, action2.second.transientEdgeAssignments, action2.second.localNondeterminismVariables, action2.second.variableToWritingFragment, action2.second.illegalFragment); } } } @@ -1166,7 +1176,7 @@ namespace storm { } } - return ActionDd(action1.guard * action2.guard, action1.transitions * action2.transitions, std::make_pair(std::min(action1.getLowestLocalNondeterminismVariable(), action2.getLowestLocalNondeterminismVariable()), std::max(action1.getHighestLocalNondeterminismVariable(), action2.getHighestLocalNondeterminismVariable())), globalVariableToWritingFragment, illegalFragment); + return ActionDd(combinedGuard.template toAdd<ValueType>(), action1.transitions * action2.transitions, joinTransientAssignmentMaps(action1.transientEdgeAssignments, action2.transientEdgeAssignments), std::make_pair(std::min(action1.getLowestLocalNondeterminismVariable(), action2.getLowestLocalNondeterminismVariable()), std::max(action1.getHighestLocalNondeterminismVariable(), action2.getHighestLocalNondeterminismVariable())), globalVariableToWritingFragment, illegalFragment); } ActionDd combineUnsynchronizedActions(ActionDd action1, ActionDd action2, storm::dd::Add<Type, ValueType> const& identity1, storm::dd::Add<Type, ValueType> const& identity2) { @@ -1183,7 +1193,7 @@ namespace storm { STORM_LOG_TRACE("Combining unsynchronized actions."); if (this->model.getModelType() == storm::jani::ModelType::DTMC || this->model.getModelType() == storm::jani::ModelType::CTMC) { - return ActionDd(action1.guard + action2.guard, action1.transitions + action2.transitions, std::make_pair<uint64_t, uint64_t>(0, 0), joinVariableWritingFragmentMaps(action1.variableToWritingFragment, action2.variableToWritingFragment), this->variables.manager->getBddZero()); + return ActionDd(action1.guard + action2.guard, action1.transitions + action2.transitions, joinTransientAssignmentMaps(action1.transientEdgeAssignments, action2.transientEdgeAssignments), std::make_pair<uint64_t, uint64_t>(0, 0), joinVariableWritingFragmentMaps(action1.variableToWritingFragment, action2.variableToWritingFragment), this->variables.manager->getBddZero()); } else if (this->model.getModelType() == storm::jani::ModelType::MDP) { if (action1.transitions.isZero()) { return action2; @@ -1192,7 +1202,7 @@ namespace storm { } // Bring both choices to the same number of variables that encode the nondeterminism. - assert(action1.getLowestLocalNondeterminismVariable() == action2.getLowestLocalNondeterminismVariable()); + STORM_LOG_ASSERT(action1.getLowestLocalNondeterminismVariable() == action2.getLowestLocalNondeterminismVariable(), "Mismatching lowest nondeterminism variable indices."); uint_fast64_t highestLocalNondeterminismVariable = std::max(action1.getHighestLocalNondeterminismVariable(), action2.getHighestLocalNondeterminismVariable()); if (action1.getHighestLocalNondeterminismVariable() > action2.getHighestLocalNondeterminismVariable()) { storm::dd::Add<Type, ValueType> nondeterminismEncoding = this->variables.manager->template getAddOne<ValueType>(); @@ -1201,6 +1211,10 @@ namespace storm { nondeterminismEncoding *= this->variables.manager->getEncoding(this->variables.localNondeterminismVariables[i], 0).template toAdd<ValueType>(); } action2.transitions *= nondeterminismEncoding; + + for (auto& transientAssignment : action2.transientEdgeAssignments) { + transientAssignment.second *= nondeterminismEncoding; + } } else if (action2.getHighestLocalNondeterminismVariable() > action1.getHighestLocalNondeterminismVariable()) { storm::dd::Add<Type, ValueType> nondeterminismEncoding = this->variables.manager->template getAddOne<ValueType>(); @@ -1208,6 +1222,10 @@ namespace storm { nondeterminismEncoding *= this->variables.manager->getEncoding(this->variables.localNondeterminismVariables[i], 0).template toAdd<ValueType>(); } action1.transitions *= nondeterminismEncoding; + + for (auto& transientAssignment : action1.transientEdgeAssignments) { + transientAssignment.second *= nondeterminismEncoding; + } } // Add a new variable that resolves the nondeterminism between the two choices. @@ -1221,14 +1239,14 @@ namespace storm { entry.second = this->variables.manager->getEncoding(this->variables.localNondeterminismVariables[highestLocalNondeterminismVariable], 1) && entry.second; } - return ActionDd((action1.guard.toBdd() || action2.guard.toBdd()).template toAdd<ValueType>(), combinedTransitions, std::make_pair(action1.getLowestLocalNondeterminismVariable(), highestLocalNondeterminismVariable + 1), joinVariableWritingFragmentMaps(action1.variableToWritingFragment, action2.variableToWritingFragment), action1.illegalFragment || action2.illegalFragment); + return ActionDd((action1.guard.toBdd() || action2.guard.toBdd()).template toAdd<ValueType>(), combinedTransitions, joinTransientAssignmentMaps(action1.transientEdgeAssignments, action2.transientEdgeAssignments), std::make_pair(action1.getLowestLocalNondeterminismVariable(), highestLocalNondeterminismVariable + 1), joinVariableWritingFragmentMaps(action1.variableToWritingFragment, action2.variableToWritingFragment), action1.illegalFragment || action2.illegalFragment); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Illegal model type."); } } AutomatonDd rename(AutomatonDd const& automaton, std::map<uint64_t, uint64_t> const& indexToIndex) { - AutomatonDd result(automaton.identity); + AutomatonDd result(automaton.identity, automaton.transientLocationAssignments); for (auto const& action : automaton.actionIndexToAction) { auto renamingIt = indexToIndex.find(action.first); @@ -1258,6 +1276,23 @@ namespace storm { return result; } + void performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function<void (storm::jani::Assignment const&)> const& callback) { + auto transientVariableIt = this->transientVariables.begin(); + auto transientVariableIte = this->transientVariables.end(); + for (auto const& assignment : transientAssignments) { + while (transientVariableIt != transientVariableIte && *transientVariableIt < assignment.getExpressionVariable()) { + ++transientVariableIt; + } + if (transientVariableIt == transientVariableIte) { + break; + } + if (*transientVariableIt == assignment.getExpressionVariable()) { + callback(assignment); + ++transientVariableIt; + } + } + } + EdgeDd buildEdgeDd(storm::jani::Automaton const& automaton, storm::jani::Edge const& edge) { STORM_LOG_TRACE("Translating guard " << edge.getGuard()); @@ -1324,27 +1359,12 @@ namespace storm { } // Finally treat the transient assignments. + std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments; if (!this->transientVariables.empty()) { - auto transientAssignments = edge.getAssignments().getTransientAssignments(); - - auto transientVariableIt = this->transientVariables.begin(); - auto transientVariableIte = this->transientVariables.end(); - for (auto const& assignment : transientAssignments) { - while (transientVariableIt != transientVariableIte && *transientVariableIt < assignment.getExpressionVariable()) { -// callback(storm::utility::zero<ValueType>()); - ++transientVariableIt; - } - if (transientVariableIt == transientVariableIte) { - break; - } - if (*transientVariableIt == assignment.getExpressionVariable()) { -// callback(ValueType(this->evaluator.asRational(assignment.getAssignedExpression()))); - ++transientVariableIt; - } - } + performTransientAssignments(edge.getAssignments().getTransientAssignments(), [this, &transientEdgeAssignments, &guard] (storm::jani::Assignment const& assignment) { transientEdgeAssignments[assignment.getExpressionVariable()] = guard * this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression()); } ); } - return EdgeDd(guard, guard * transitions, globalVariablesInSomeDestination); + return EdgeDd(guard, guard * transitions, transientEdgeAssignments, globalVariablesInSomeDestination); } else { return EdgeDd(this->variables.manager->template getAddZero<ValueType>(), this->variables.manager->template getAddZero<ValueType>()); } @@ -1373,16 +1393,52 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot translate model of this type."); } } else { - return ActionDd(this->variables.manager->template getAddZero<ValueType>(), this->variables.manager->template getAddZero<ValueType>(), std::make_pair<uint64_t, uint64_t>(0, 0), {}, this->variables.manager->getBddZero()); + return ActionDd(this->variables.manager->template getAddZero<ValueType>(), this->variables.manager->template getAddZero<ValueType>(), {}, std::make_pair<uint64_t, uint64_t>(0, 0), {}, this->variables.manager->getBddZero()); } } + void addToTransientAssignmentMap(std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>>& transientAssignments, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& assignmentsToAdd) { + for (auto const& entry : assignmentsToAdd) { + auto it = transientAssignments.find(entry.first); + if (it != transientAssignments.end()) { + it->second += entry.second; + } else { + transientAssignments[entry.first] = entry.second; + } + } + } + + void addToTransientAssignmentMap(std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>>& transientAssignments, storm::expressions::Variable const& variable, storm::dd::Add<Type, ValueType> const& assignmentToAdd) { + auto it = transientAssignments.find(variable); + if (it != transientAssignments.end()) { + it->second += assignmentToAdd; + } else { + transientAssignments[variable] = assignmentToAdd; + } + } + + std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> joinTransientAssignmentMaps(std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientAssignments1, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientAssignments2) { + std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> result = transientAssignments1; + + for (auto const& entry : transientAssignments2) { + auto resultIt = result.find(entry.first); + if (resultIt != result.end()) { + resultIt->second += entry.second; + } else { + result[entry.first] = entry.second; + } + } + + return result; + } + ActionDd combineEdgesToActionMarkovChain(std::vector<EdgeDd> const& edgeDds) { storm::dd::Bdd<Type> allGuards = this->variables.manager->getBddZero(); storm::dd::Add<Type, ValueType> allTransitions = this->variables.manager->template getAddZero<ValueType>(); storm::dd::Bdd<Type> temporary; std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment; + std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments; for (auto const& edgeDd : edgeDds) { // Check for overlapping guards. storm::dd::Bdd<Type> guardBdd = edgeDd.guard.toBdd(); @@ -1395,6 +1451,9 @@ namespace storm { allGuards |= guardBdd; allTransitions += edgeDd.transitions; + // Add the transient variable assignments to the resulting one. + addToTransientAssignmentMap(transientEdgeAssignments, edgeDd.transientEdgeAssignments); + // Keep track of the fragment that is writing global variables. for (auto const& variable : edgeDd.writtenGlobalVariables) { auto it = globalVariableToWritingFragment.find(variable); @@ -1406,7 +1465,7 @@ namespace storm { } } - return ActionDd(allGuards.template toAdd<ValueType>(), allTransitions, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment, this->variables.manager->getBddZero()); + return ActionDd(allGuards.template toAdd<ValueType>(), allTransitions, transientEdgeAssignments, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment, this->variables.manager->getBddZero()); } void addToVariableWritingFragmentMap(std::map<storm::expressions::Variable, storm::dd::Bdd<Type>>& globalVariableToWritingFragment, storm::expressions::Variable const& variable, storm::dd::Bdd<Type> const& partToAdd) const { @@ -1436,13 +1495,15 @@ namespace storm { ActionDd combineEdgesBySummation(storm::dd::Add<Type, ValueType> const& guard, std::vector<EdgeDd> const& edges) { storm::dd::Add<Type, ValueType> transitions = this->variables.manager->template getAddZero<ValueType>(); std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment; + std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments; for (auto const& edge : edges) { transitions += edge.transitions; + addToTransientAssignmentMap(transientEdgeAssignments, edge.transientEdgeAssignments); for (auto const& variable : edge.writtenGlobalVariables) { addToVariableWritingFragmentMap(globalVariableToWritingFragment, variable, edge.guard.toBdd()); } } - return ActionDd(guard, transitions, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment, this->variables.manager->getBddZero()); + return ActionDd(guard, transitions, transientEdgeAssignments, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment, this->variables.manager->getBddZero()); } ActionDd combineEdgesToActionMdp(std::vector<EdgeDd> const& edges, uint64_t localNondeterminismVariableOffset) { @@ -1465,6 +1526,7 @@ namespace storm { storm::dd::Add<Type, ValueType> allEdges = this->variables.manager->template getAddZero<ValueType>(); std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment; + std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientAssignments; storm::dd::Bdd<Type> equalsNumberOfChoicesDd; std::vector<storm::dd::Add<Type, ValueType>> choiceDds(maxChoices, this->variables.manager->template getAddZero<ValueType>()); @@ -1515,6 +1577,11 @@ namespace storm { // Combine the overlapping part of the guard with command updates and add it to the resulting DD. choiceDds[k] += remainingGuardChoicesIntersection.template toAdd<ValueType>() * currentEdge.transitions; + // Keep track of the fragment of transient assignments. + for (auto const& transientAssignment : currentEdge.transientEdgeAssignments) { + addToTransientAssignmentMap(transientAssignments, transientAssignment.first, remainingGuardChoicesIntersection.template toAdd<ValueType>() * transientAssignment.second * indicesEncodedWithLocalNondeterminismVariables[k].first.template toAdd<ValueType>()); + } + // Keep track of the written global variables of the fragment. for (auto const& variable : currentEdge.writtenGlobalVariables) { addToVariableWritingFragmentMap(globalVariableToWritingFragment, variable, remainingGuardChoicesIntersection && indicesEncodedWithLocalNondeterminismVariables[k].first); @@ -1540,7 +1607,7 @@ namespace storm { sumOfGuards = sumOfGuards * (!equalsNumberOfChoicesDd).template toAdd<ValueType>(); } - return ActionDd(allGuards.template toAdd<ValueType>(), allEdges, std::make_pair(localNondeterminismVariableOffset, localNondeterminismVariableOffset + numberOfBinaryVariables), globalVariableToWritingFragment, this->variables.manager->getBddZero()); + return ActionDd(allGuards.template toAdd<ValueType>(), allEdges, transientAssignments, std::make_pair(localNondeterminismVariableOffset, localNondeterminismVariableOffset + numberOfBinaryVariables), globalVariableToWritingFragment, this->variables.manager->getBddZero()); } } @@ -1558,6 +1625,20 @@ namespace storm { result.setLowestLocalNondeterminismVariable(std::max(result.getLowestLocalNondeterminismVariable(), actionDd.getLowestLocalNondeterminismVariable())); result.setHighestLocalNondeterminismVariable(std::max(result.getHighestLocalNondeterminismVariable(), actionDd.getHighestLocalNondeterminismVariable())); } + + for (uint64_t locationIndex = 0; locationIndex < automaton.getNumberOfLocations(); ++locationIndex) { + auto const& location = automaton.getLocation(locationIndex); + performTransientAssignments(location.getAssignments().getTransientAssignments(), [this,&automatonName,locationIndex,&result] (storm::jani::Assignment const& assignment) { + storm::dd::Add<Type, ValueType> assignedValues = this->variables.manager->getEncoding(this->variables.automatonToLocationVariableMap.at(automatonName).first, locationIndex).template toAdd<ValueType>() * this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression()); + auto it = result.transientLocationAssignments.find(assignment.getExpressionVariable()); + if (it != result.transientLocationAssignments.end()) { + it->second += assignedValues; + } else { + result.transientLocationAssignments[assignment.getExpressionVariable()] = assignedValues; + } + }); + } + return result; } @@ -1588,28 +1669,36 @@ namespace storm { uint64_t numberOfUsedNondeterminismVariables = automaton.getHighestLocalNondeterminismVariable(); // Add missing global variable identities, action and nondeterminism encodings. + std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments; for (auto& action : automaton.actionIndexToAction) { illegalFragment |= action.second.illegalFragment; addMissingGlobalVariableIdentities(action.second); storm::dd::Add<Type, ValueType> actionEncoding = encodeAction(action.first != this->model.getSilentActionIndex() ? boost::optional<uint64_t>(action.first) : boost::none, this->variables); storm::dd::Add<Type, ValueType> missingNondeterminismEncoding = encodeIndex(0, action.second.getHighestLocalNondeterminismVariable(), numberOfUsedNondeterminismVariables - action.second.getHighestLocalNondeterminismVariable(), this->variables); storm::dd::Add<Type, ValueType> extendedTransitions = actionEncoding * missingNondeterminismEncoding * action.second.transitions; + + for (auto const& transientAssignment : action.second.transientEdgeAssignments) { + addToTransientAssignmentMap(transientEdgeAssignments, transientAssignment.first, actionEncoding * missingNondeterminismEncoding * transientAssignment.second); + } + result += extendedTransitions; } - return ComposerResult<Type, ValueType>(result, illegalFragment, numberOfUsedNondeterminismVariables); + return ComposerResult<Type, ValueType>(result, automaton.transientLocationAssignments, transientEdgeAssignments, illegalFragment, numberOfUsedNondeterminismVariables); } else if (this->model.getModelType() == storm::jani::ModelType::DTMC || this->model.getModelType() == storm::jani::ModelType::CTMC) { // Simply add all actions, but make sure to include the missing global variable identities. storm::dd::Add<Type, ValueType> result = this->variables.manager->template getAddZero<ValueType>(); storm::dd::Bdd<Type> illegalFragment = this->variables.manager->getBddZero(); + std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments; for (auto& action : automaton.actionIndexToAction) { illegalFragment |= action.second.illegalFragment; addMissingGlobalVariableIdentities(action.second); + addToTransientAssignmentMap(transientEdgeAssignments, action.second.transientEdgeAssignments); result += action.second.transitions; } - return ComposerResult<Type, ValueType>(result, illegalFragment, 0); + return ComposerResult<Type, ValueType>(result, automaton.transientLocationAssignments, transientEdgeAssignments, illegalFragment, 0); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Illegal model type."); } @@ -1782,6 +1871,31 @@ namespace storm { return result; } + template <storm::dd::DdType Type, typename ValueType> + std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<Type, ValueType>> buildRewardModels(ComposerResult<Type, ValueType> const& system, std::vector<storm::expressions::Variable> const& rewardVariables) { + std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<Type, ValueType>> result; + + for (auto const& variable : rewardVariables) { + boost::optional<storm::dd::Add<Type, ValueType>> stateRewards = boost::none; + boost::optional<storm::dd::Add<Type, ValueType>> stateActionRewards = boost::none; + boost::optional<storm::dd::Add<Type, ValueType>> transitionRewards = boost::none; + + auto it = system.transientLocationAssignments.find(variable); + if (it != system.transientLocationAssignments.end()) { + stateRewards = it->second; + } + + it = system.transientEdgeAssignments.find(variable); + if (it != system.transientEdgeAssignments.end()) { + stateActionRewards = it->second; + } + + result.emplace(variable.getName(), storm::models::symbolic::StandardRewardModel<Type, ValueType>(stateRewards, stateActionRewards, transitionRewards)); + } + + return result; + } + template <storm::dd::DdType Type, typename ValueType> std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdJaniModelBuilder<Type, ValueType>::build(storm::jani::Model const& model, Options const& options) { if (model.hasUndefinedConstants()) { @@ -1840,6 +1954,9 @@ namespace storm { // Cut the deadlock states by removing all states that we 'converted' to deadlock states by making them terminal. modelComponents.deadlockStates = modelComponents.deadlockStates && !terminalStates; + // Build the reward models. + modelComponents.rewardModels = buildRewardModels(system, rewardVariables); + // Finally, create the model. return createModel(model.getModelType(), variables, modelComponents); } diff --git a/src/builder/DdPrismModelBuilder.cpp b/src/builder/DdPrismModelBuilder.cpp index 859a2424e..b45269dc4 100644 --- a/src/builder/DdPrismModelBuilder.cpp +++ b/src/builder/DdPrismModelBuilder.cpp @@ -1219,6 +1219,8 @@ namespace storm { } } + stateActionRewards.get().exportToDot("prismrew.dot"); + return storm::models::symbolic::StandardRewardModel<Type, ValueType>(stateRewards, stateActionRewards, transitionRewards); } diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 78cbcc042..755674cd1 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -213,6 +213,9 @@ namespace storm { storm::storage::SymbolicModelDescription model; if (ioSettings.isPrismInputSet()) { model = storm::parseProgram(ioSettings.getPrismInputFilename()); + if (ioSettings.isPrismToJaniSet()) { + model = model.toJani(true); + } } else if (ioSettings.isJaniInputSet()) { model = storm::parseJaniModel(ioSettings.getJaniInputFilename()).first; } diff --git a/src/generator/JaniNextStateGenerator.cpp b/src/generator/JaniNextStateGenerator.cpp index 23a3a7068..5b5f54151 100644 --- a/src/generator/JaniNextStateGenerator.cpp +++ b/src/generator/JaniNextStateGenerator.cpp @@ -550,12 +550,15 @@ namespace storm { } if (rewardVariableIt == rewardVariableIte) { break; - } - if (*rewardVariableIt == assignment.getExpressionVariable()) { + } else if (*rewardVariableIt == assignment.getExpressionVariable()) { callback(ValueType(this->evaluator.asRational(assignment.getAssignedExpression()))); ++rewardVariableIt; } } + // Add a value of zero for all variables that have no assignment. + for (; rewardVariableIt != rewardVariableIte; ++rewardVariableIt) { + callback(storm::utility::zero<ValueType>()); + } } template<typename ValueType, typename StateType> diff --git a/src/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp b/src/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp index b5adb7e15..6266fbb73 100644 --- a/src/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp +++ b/src/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp @@ -172,7 +172,7 @@ namespace storm { // for solving the equation system (i.e. compute (I-A)). submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); submatrix = (model.getRowColumnIdentity() * maybeStatesAdd) - submatrix; - + // Solve the equation system. std::unique_ptr<storm::solver::SymbolicLinearEquationSolver<DdType, ValueType>> solver = linearEquationSolverFactory.create(submatrix, maybeStates, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs()); storm::dd::Add<DdType, ValueType> result = solver->solveEquations(model.getManager().getConstant(0.5) * maybeStatesAdd, subvector); diff --git a/src/settings/modules/IOSettings.cpp b/src/settings/modules/IOSettings.cpp index ef6877089..c174f1f51 100644 --- a/src/settings/modules/IOSettings.cpp +++ b/src/settings/modules/IOSettings.cpp @@ -19,6 +19,7 @@ namespace storm { const std::string IOSettings::explicitOptionShortName = "exp"; const std::string IOSettings::prismInputOptionName = "prism"; const std::string IOSettings::janiInputOptionName = "jani"; + const std::string IOSettings::prismToJaniOptionName = "prism2jani"; const std::string IOSettings::explorationOrderOptionName = "explorder"; const std::string IOSettings::explorationOrderOptionShortName = "eo"; const std::string IOSettings::transitionRewardsOptionName = "transrew"; @@ -42,6 +43,7 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the PRISM input.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, janiInputOptionName, false, "Parses the model given in the JANI format.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the JANI input.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, prismToJaniOptionName, false, "If set, the input PRISM model is transformed to JANI.").build()); std::vector<std::string> explorationOrders = {"dfs", "bfs"}; this->addOption(storm::settings::OptionBuilder(moduleName, explorationOrderOptionName, false, "Sets which exploration order to use.").setShortName(explorationOrderOptionShortName) @@ -85,6 +87,10 @@ namespace storm { return isJaniInputSet() || isPrismInputSet(); } + bool IOSettings::isPrismToJaniSet() const { + return this->getOption(prismToJaniOptionName).getHasOptionBeenSet(); + } + std::string IOSettings::getPrismInputFilename() const { return this->getOption(prismInputOptionName).getArgumentByName("filename").getValueAsString(); } @@ -160,6 +166,10 @@ namespace storm { // Ensure that the model was given either symbolically or explicitly. STORM_LOG_THROW(!isJaniInputSet() || !isPrismInputSet() || !isExplicitSet(), storm::exceptions::InvalidSettingsException, "The model may be either given in an explicit or a symbolic format (PRISM or JANI), but not both."); + + // Make sure PRISM-to-JANI conversion is only set if the actual input is in PRISM format. + STORM_LOG_THROW(!isPrismToJaniSet() || isPrismInputSet(), storm::exceptions::InvalidSettingsException, "For the transformation from PRISM to JANI, the input model must be given in the prism format."); + return true; } diff --git a/src/settings/modules/IOSettings.h b/src/settings/modules/IOSettings.h index 8585ea573..ae6ce6831 100644 --- a/src/settings/modules/IOSettings.h +++ b/src/settings/modules/IOSettings.h @@ -79,6 +79,13 @@ namespace storm { */ bool isPrismOrJaniInputSet() const; + /*! + * Retrieves whether the option to convert PRISM to JANI input was set. + * + * @return True if the option was set. + */ + bool isPrismToJaniSet() const; + /*! * Retrieves the name of the file that contains the PRISM model specification if the model was given * using the PRISM input option. @@ -198,6 +205,7 @@ namespace storm { static const std::string explicitOptionShortName; static const std::string prismInputOptionName; static const std::string janiInputOptionName; + static const std::string prismToJaniOptionName; static const std::string explorationOrderOptionName; static const std::string explorationOrderOptionShortName; static const std::string transitionRewardsOptionName; diff --git a/src/storage/SymbolicModelDescription.cpp b/src/storage/SymbolicModelDescription.cpp index 3bccf3b73..1058e464f 100644 --- a/src/storage/SymbolicModelDescription.cpp +++ b/src/storage/SymbolicModelDescription.cpp @@ -19,10 +19,12 @@ namespace storm { SymbolicModelDescription& SymbolicModelDescription::operator=(storm::jani::Model const& model) { this->modelDescription = model; + return *this; } SymbolicModelDescription& SymbolicModelDescription::operator=(storm::prism::Program const& program) { this->modelDescription = program; + return *this; } bool SymbolicModelDescription::hasModel() const { diff --git a/src/storage/jani/Automaton.cpp b/src/storage/jani/Automaton.cpp index 9e288695f..9c618a838 100644 --- a/src/storage/jani/Automaton.cpp +++ b/src/storage/jani/Automaton.cpp @@ -108,7 +108,11 @@ namespace storm { std::vector<Location> const& Automaton::getLocations() const { return locations; } - + + std::vector<Location>& Automaton::getLocations() { + return locations; + } + Location const& Automaton::getLocation(uint64_t index) const { return locations[index]; } @@ -371,6 +375,10 @@ namespace storm { variable.substitute(substitution); } + for (auto& location : this->getLocations()) { + location.substitute(substitution); + } + this->setInitialStatesRestriction(this->getInitialStatesRestriction().substitute(substitution)); for (auto& edge : this->getEdges()) { diff --git a/src/storage/jani/Automaton.h b/src/storage/jani/Automaton.h index 9ef3c57f2..c6219aa1e 100644 --- a/src/storage/jani/Automaton.h +++ b/src/storage/jani/Automaton.h @@ -157,7 +157,12 @@ namespace storm { * Retrieves the locations of the automaton. */ std::vector<Location> const& getLocations() const; - + + /*! + * Retrieves the locations of the automaton. + */ + std::vector<Location>& getLocations(); + /*! * Retrieves the location with the given index. */ diff --git a/src/storage/jani/Location.cpp b/src/storage/jani/Location.cpp index 4f09e4959..05a22d4e5 100644 --- a/src/storage/jani/Location.cpp +++ b/src/storage/jani/Location.cpp @@ -24,6 +24,12 @@ namespace storm { assignments.add(assignment); } + void Location::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) { + for (auto& assignment : assignments) { + assignment.substitute(substitution); + } + } + void Location::checkValid() const { // Intentionally left empty. } diff --git a/src/storage/jani/Location.h b/src/storage/jani/Location.h index 9de4b683f..a2328cb22 100644 --- a/src/storage/jani/Location.h +++ b/src/storage/jani/Location.h @@ -33,6 +33,11 @@ namespace storm { * Adds the given transient assignment to this location. */ void addTransientAssignment(storm::jani::Assignment const& assignment); + + /*! + * Substitutes all variables in all expressions according to the given substitution. + */ + void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution); /*! * Checks whether the location is valid, that is, whether the assignments are indeed all transient assignments. diff --git a/src/storage/jani/Model.cpp b/src/storage/jani/Model.cpp index 9a9a95d8f..fc170ac58 100644 --- a/src/storage/jani/Model.cpp +++ b/src/storage/jani/Model.cpp @@ -200,6 +200,12 @@ namespace storm { return automata[it->second]; } + uint64_t Model::getAutomatonIndex(std::string const& name) const { + auto it = automatonToIndex.find(name); + STORM_LOG_THROW(it != automatonToIndex.end(), storm::exceptions::InvalidOperationException, "Unable to retrieve unknown automaton '" << name << "'."); + return it->second; + } + std::size_t Model::getNumberOfAutomata() const { return automata.size(); } diff --git a/src/storage/jani/Model.h b/src/storage/jani/Model.h index 375c4d792..2fc06b18f 100644 --- a/src/storage/jani/Model.h +++ b/src/storage/jani/Model.h @@ -196,6 +196,11 @@ namespace storm { * Retrieves the automaton with the given name. */ Automaton const& getAutomaton(std::string const& name) const; + + /*! + * Retrieves the index of the given automaton. + */ + uint64_t getAutomatonIndex(std::string const& name) const; /*! * Retrieves the number of automata in this model.