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.