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/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)
diff --git a/src/adapters/AddExpressionAdapter.cpp b/src/adapters/AddExpressionAdapter.cpp
index e50620db8..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,18 +184,18 @@ namespace storm {
         }
         
         template<storm::dd::DdType Type, typename ValueType>
-        boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BooleanLiteralExpression const& expression) {
+        boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data) {
             return expression.getValue() ? ddManager->getBddOne() : ddManager->getBddZero();
         }
         
         template<storm::dd::DdType Type, typename ValueType>
-        boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::IntegerLiteralExpression const& expression) {
+        boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) {
             return ddManager->getConstant(static_cast<ValueType>(expression.getValue()));
         }
         
         template<storm::dd::DdType Type, typename ValueType>
-        boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::DoubleLiteralExpression const& expression) {
-            return ddManager->getConstant(static_cast<ValueType>(expression.getValue()));
+        boost::any AddExpressionAdapter<Type, ValueType>::visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) {
+            return ddManager->getConstant(static_cast<ValueType>(expression.getValueAsDouble()));
         }
         
         // Explicitly instantiate the symbolic expression adapter
diff --git a/src/adapters/AddExpressionAdapter.h b/src/adapters/AddExpressionAdapter.h
index 89d825d96..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::DoubleLiteralExpression const& expression) override;
+            virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) override;
 
         private:
             // The manager responsible for the DDs built by this adapter.
diff --git a/src/adapters/DereferenceIteratorAdapter.h b/src/adapters/DereferenceIteratorAdapter.h
new file mode 100644
index 000000000..16ac0834e
--- /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() const {
+                return boost::make_transform_iterator(it, Dereferencer<value_type>());
+            }
+            
+            iterator end() const {
+                return boost::make_transform_iterator(ite, Dereferencer<value_type>());
+            }
+            
+            static iterator make_iterator(input_iterator it) {
+                return boost::make_transform_iterator(it, Dereferencer<value_type>());
+            }
+            
+        private:
+            input_iterator it;
+            input_iterator ite;
+        };
+        
+    }
+}
\ No newline at end of file
diff --git a/src/adapters/MathsatExpressionAdapter.h b/src/adapters/MathsatExpressionAdapter.h
index 9fec0cf15..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::DoubleLiteralExpression const& expression) override {
-				return msat_make_number(env, std::to_string(expression.getValue()).c_str());
+			virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) override {
+				return msat_make_number(env, std::to_string(expression.getValueAsDouble()).c_str());
 			}
 
-			virtual boost::any visit(expressions::IntegerLiteralExpression const& expression) override {
+			virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) override {
 				return msat_make_number(env, std::to_string(static_cast<int>(expression.getValue())).c_str());
 			}
 
-			virtual boost::any visit(expressions::UnaryBooleanFunctionExpression const& expression) override {
-                msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this));
+			virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override {
+                msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this, data));
 
 				switch (expression.getOperatorType()) {
 					case storm::expressions::UnaryBooleanFunctionExpression::OperatorType::Not:
@@ -191,8 +191,8 @@ namespace storm {
 				}
 			}
 
-			virtual boost::any visit(expressions::UnaryNumericalFunctionExpression const& expression) override {
-				msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this));
+			virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override {
+				msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this, data));
 
 				switch (expression.getOperatorType()) {
 					case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Minus:
@@ -209,7 +209,7 @@ namespace storm {
 				}
 			}
 
-			virtual boost::any visit(expressions::VariableExpression const& expression) override {
+			virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override {
                 return translateExpression(expression.getVariable());
 			}
 
diff --git a/src/adapters/Z3ExpressionAdapter.cpp b/src/adapters/Z3ExpressionAdapter.cpp
index 60b4e8e1c..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:
@@ -177,14 +177,16 @@ namespace storm {
                         return ite(leftResult <= rightResult, leftResult, rightResult);
 					case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Max:
                         return ite(leftResult >= rightResult, leftResult, rightResult);
+					case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Power:
+                        return pw(leftResult,rightResult);
                     default:
                         STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression: unknown numerical binary operator '" << static_cast<int>(expression.getOperatorType()) << "' in expression " << expression << ".");
                 }
             }
             
-            boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryRelationExpression const& expression)  {
-                z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this));
-                z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this));
+            boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data)  {
+                z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this, data));
+                z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this, data));
     
                 switch(expression.getRelationType()) {
 					case storm::expressions::BinaryRelationExpression::RelationType::Equal:
@@ -204,22 +206,22 @@ namespace storm {
                 }    
             }
             
-            boost::any Z3ExpressionAdapter::visit(storm::expressions::BooleanLiteralExpression const& expression)  {
+            boost::any Z3ExpressionAdapter::visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data)  {
                 return context.bool_val(expression.getValue());
             }
             
-            boost::any Z3ExpressionAdapter::visit(storm::expressions::DoubleLiteralExpression const& expression)  {
+            boost::any Z3ExpressionAdapter::visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data)  {
                 std::stringstream fractionStream;
                 fractionStream << expression.getValue();
                 return context.real_val(fractionStream.str().c_str());
             }
             
-            boost::any Z3ExpressionAdapter::visit(storm::expressions::IntegerLiteralExpression const& expression)  {
+            boost::any Z3ExpressionAdapter::visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data)  {
                 return context.int_val(static_cast<int>(expression.getValue()));
             }
             
-            boost::any Z3ExpressionAdapter::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression)  {
-                z3::expr childResult = boost::any_cast<z3::expr>(expression.getOperand()->accept(*this));
+            boost::any Z3ExpressionAdapter::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data)  {
+                z3::expr childResult = boost::any_cast<z3::expr>(expression.getOperand()->accept(*this, data));
                 
                 switch (expression.getOperatorType()) {
 					case storm::expressions::UnaryBooleanFunctionExpression::OperatorType::Not:
@@ -229,8 +231,8 @@ namespace storm {
                 }    
             }
             
-            boost::any Z3ExpressionAdapter::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression)  {
-                z3::expr childResult = boost::any_cast<z3::expr>(expression.getOperand()->accept(*this));
+            boost::any Z3ExpressionAdapter::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data)  {
+                z3::expr childResult = boost::any_cast<z3::expr>(expression.getOperand()->accept(*this, data));
                 
                 switch(expression.getOperatorType()) {
 					case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Minus:
@@ -251,14 +253,14 @@ namespace storm {
                 }
             }
 
-            boost::any Z3ExpressionAdapter::visit(storm::expressions::IfThenElseExpression const& expression)  {
-                z3::expr conditionResult = boost::any_cast<z3::expr>(expression.getCondition()->accept(*this));
-                z3::expr thenResult = boost::any_cast<z3::expr>(expression.getThenExpression()->accept(*this));
-                z3::expr elseResult = boost::any_cast<z3::expr>(expression.getElseExpression()->accept(*this));
+            boost::any Z3ExpressionAdapter::visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data)  {
+                z3::expr conditionResult = boost::any_cast<z3::expr>(expression.getCondition()->accept(*this, data));
+                z3::expr thenResult = boost::any_cast<z3::expr>(expression.getThenExpression()->accept(*this, data));
+                z3::expr elseResult = boost::any_cast<z3::expr>(expression.getElseExpression()->accept(*this, data));
                 return z3::expr(context, Z3_mk_ite(context, conditionResult, thenResult, elseResult));
             }
             
-            boost::any Z3ExpressionAdapter::visit(storm::expressions::VariableExpression const& expression)  {
+            boost::any Z3ExpressionAdapter::visit(storm::expressions::VariableExpression const& expression, boost::any const& data)  {
                 return this->translateExpression(expression.getVariable());
             }
                         
diff --git a/src/adapters/Z3ExpressionAdapter.h b/src/adapters/Z3ExpressionAdapter.h
index 4fc60c8a5..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::DoubleLiteralExpression const& expression) override;
+            virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) override;
             
-            virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression) override;
+            virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) override;
             
-            virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression) override;
+            virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
             
-            virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression) override;
+            virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
 
-            virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression) override;
+            virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override;
             
-            virtual boost::any visit(storm::expressions::VariableExpression const& expression) override;
+            virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override;
 
         private:
             /*!
diff --git a/src/builder/DdJaniModelBuilder.cpp b/src/builder/DdJaniModelBuilder.cpp
index 9397ed925..5ab18683b 100644
--- a/src/builder/DdJaniModelBuilder.cpp
+++ b/src/builder/DdJaniModelBuilder.cpp
@@ -103,19 +103,13 @@ namespace storm {
         }
         
         template <storm::dd::DdType Type, typename ValueType>
-        DdJaniModelBuilder<Type, ValueType>::DdJaniModelBuilder(storm::jani::Model const& model, Options const& options) : model(model), options(options) {
-            if (this->model->hasUndefinedConstants()) {
-                std::vector<std::reference_wrapper<storm::jani::Constant const>> undefinedConstants = this->model->getUndefinedConstants();
-                std::vector<std::string> strings;
-                for (auto const& constant : undefinedConstants) {
-                    std::stringstream stream;
-                    stream << constant.get().getName() << " (" << constant.get().getType() << ")";
-                    strings.push_back(stream.str());
-                }
-                STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " << boost::join(strings, ", ") << ".");
-            }
-            
-            this->model = this->model->substituteConstants();
+        std::set<std::string> const& DdJaniModelBuilder<Type, ValueType>::Options::getRewardModelNames() const {
+            return rewardModelsToBuild;
+        }
+        
+        template <storm::dd::DdType Type, typename ValueType>
+        bool DdJaniModelBuilder<Type, ValueType>::Options::isBuildAllRewardModelsSet() const {
+            return buildAllRewardModels;
         }
         
         template <storm::dd::DdType Type, typename ValueType>
@@ -188,11 +182,15 @@ namespace storm {
                 this->model.getSystemComposition().accept(*this, boost::none);
                 STORM_LOG_THROW(automata.size() == this->model.getNumberOfAutomata(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model whose system composition refers to a subset of automata.");
                 
-                // Then, check that the model does not contain unbounded integer variables.
+                // Then, check that the model does not contain unbounded integer or non-transient real variables.
                 STORM_LOG_THROW(!this->model.getGlobalVariables().containsUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model that contains global unbounded integer variables.");
                 for (auto const& automaton : this->model.getAutomata()) {
                     STORM_LOG_THROW(!automaton.getVariables().containsUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model that contains unbounded integer variables in automaton '" << automaton.getName() << "'.");
                 }
+                STORM_LOG_THROW(!this->model.getGlobalVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model that contains global non-transient real variables.");
+                for (auto const& automaton : this->model.getAutomata()) {
+                    STORM_LOG_THROW(!automaton.getVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException, "Cannot build symbolic model from JANI model that contains non-transient real variables in automaton '" << automaton.getName() << "'.");
+                }
                 
                 // Based on this assumption, we create the variables.
                 return createVariables();
@@ -243,6 +241,7 @@ namespace storm {
                     // Start by creating a meta variable for the location of the automaton.
                     std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = result.manager->addMetaVariable("l_" + automaton.getName(), 0, automaton.getNumberOfLocations() - 1);
                     result.automatonToLocationVariableMap[automaton.getName()] = variablePair;
+                    result.rowColumnMetaVariablePairs.push_back(variablePair);
                     
                     // Add the location variable to the row/column variables.
                     result.rowMetaVariables.insert(variablePair.first);
@@ -256,6 +255,11 @@ namespace storm {
                 // Create global variables.
                 storm::dd::Bdd<Type> globalVariableRanges = result.manager->getBddOne();
                 for (auto const& variable : this->model.getGlobalVariables()) {
+                    // Only create the variable if it's non-transient.
+                    if (variable.isTransient()) {
+                        continue;
+                    }
+                    
                     createVariable(variable, result);
                     globalVariableRanges &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable()));
                 }
@@ -274,6 +278,11 @@ namespace storm {
                     
                     // Then create variables for the variables of the automaton.
                     for (auto const& variable : automaton.getVariables()) {
+                        // Only create the variable if it's non-transient.
+                        if (variable.isTransient()) {
+                            continue;
+                        }
+                        
                         createVariable(variable, result);
                         identity &= result.variableToIdentityMap.at(variable.getExpressionVariable()).toBdd();
                         range &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable()));
@@ -345,11 +354,13 @@ namespace storm {
         
         template <storm::dd::DdType Type, typename ValueType>
         struct ComposerResult {
-            ComposerResult(storm::dd::Add<Type, ValueType> const& transitions, storm::dd::Bdd<Type> const& illegalFragment, uint64_t numberOfNondeterminismVariables = 0) : transitions(transitions), illegalFragment(illegalFragment), numberOfNondeterminismVariables(numberOfNondeterminismVariables) {
+            ComposerResult(storm::dd::Add<Type, ValueType> const& transitions, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientLocationAssignments, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientEdgeAssignments, storm::dd::Bdd<Type> const& illegalFragment, uint64_t numberOfNondeterminismVariables = 0) : transitions(transitions), transientLocationAssignments(transientLocationAssignments), transientEdgeAssignments(transientEdgeAssignments), illegalFragment(illegalFragment), numberOfNondeterminismVariables(numberOfNondeterminismVariables) {
                 // Intentionally left empty.
             }
             
             storm::dd::Add<Type, ValueType> transitions;
+            std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientLocationAssignments;
+            std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
             storm::dd::Bdd<Type> illegalFragment;
             uint64_t numberOfNondeterminismVariables;
         };
@@ -358,7 +369,7 @@ namespace storm {
         template <storm::dd::DdType Type, typename ValueType>
         class SystemComposer : public storm::jani::CompositionVisitor {
         public:
-            SystemComposer(storm::jani::Model const& model, CompositionVariables<Type, ValueType> const& variables) : model(model), variables(variables) {
+            SystemComposer(storm::jani::Model const& model, CompositionVariables<Type, ValueType> const& variables, std::vector<storm::expressions::Variable> const& transientVariables) : model(model), variables(variables), transientVariables(transientVariables) {
                 // Intentionally left empty.
             }
             
@@ -370,6 +381,9 @@ namespace storm {
             
             // The variable to use when building an automaton.
             CompositionVariables<Type, ValueType> const& variables;
+            
+            // The transient variables to consider during system composition.
+            std::vector<storm::expressions::Variable> transientVariables;
         };
 
         // This structure represents an edge destination.
@@ -391,7 +405,7 @@ namespace storm {
             
             // Iterate over all assignments (boolean and integer) and build the DD for it.
             std::set<storm::expressions::Variable> assignedVariables;
-            for (auto const& assignment : destination.getAssignments()) {
+            for (auto const& assignment : destination.getNonTransientAssignments()) {
                 // Record the variable as being written.
                 STORM_LOG_TRACE("Assigning to variable " << variables.variableToRowMetaVariableMap->at(assignment.getExpressionVariable()).getName());
                 assignedVariables.insert(assignment.getExpressionVariable());
@@ -908,7 +922,7 @@ namespace storm {
         public:
             // This structure represents an edge.
             struct EdgeDd {
-                EdgeDd(storm::dd::Add<Type> const& guard = storm::dd::Add<Type>(), storm::dd::Add<Type, ValueType> const& transitions = storm::dd::Add<Type, ValueType>(), std::set<storm::expressions::Variable> const& writtenGlobalVariables = {}) : guard(guard), transitions(transitions), writtenGlobalVariables(writtenGlobalVariables) {
+                EdgeDd(storm::dd::Add<Type> const& guard = storm::dd::Add<Type>(), storm::dd::Add<Type, ValueType> const& transitions = storm::dd::Add<Type, ValueType>(), std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientEdgeAssignments = {}, std::set<storm::expressions::Variable> const& writtenGlobalVariables = {}) : guard(guard), transitions(transitions), transientEdgeAssignments(transientEdgeAssignments), writtenGlobalVariables(writtenGlobalVariables) {
                     // Intentionally left empty.
                 }
                 
@@ -918,13 +932,16 @@ namespace storm {
                 // A DD that represents the transitions of this edge.
                 storm::dd::Add<Type, ValueType> transitions;
                 
+                // A mapping from transient variables to the DDs representing their value assignments.
+                std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
+                
                 // The set of global variables written by this edge.
                 std::set<storm::expressions::Variable> writtenGlobalVariables;
             };
             
             // This structure represents an edge.
             struct ActionDd {
-                ActionDd(storm::dd::Add<Type> const& guard = storm::dd::Add<Type>(), storm::dd::Add<Type, ValueType> const& transitions = storm::dd::Add<Type, ValueType>(), std::pair<uint64_t, uint64_t> localNondeterminismVariables = std::pair<uint64_t, uint64_t>(0, 0), std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> const& variableToWritingFragment = {}, storm::dd::Bdd<Type> const& illegalFragment = storm::dd::Bdd<Type>()) : guard(guard), transitions(transitions), localNondeterminismVariables(localNondeterminismVariables), variableToWritingFragment(variableToWritingFragment), illegalFragment(illegalFragment) {
+                ActionDd(storm::dd::Add<Type> const& guard = storm::dd::Add<Type>(), storm::dd::Add<Type, ValueType> const& transitions = storm::dd::Add<Type, ValueType>(), std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientEdgeAssignments = {}, std::pair<uint64_t, uint64_t> localNondeterminismVariables = std::pair<uint64_t, uint64_t>(0, 0), std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> const& variableToWritingFragment = {}, storm::dd::Bdd<Type> const& illegalFragment = storm::dd::Bdd<Type>()) : guard(guard), transitions(transitions), transientEdgeAssignments(transientEdgeAssignments), localNondeterminismVariables(localNondeterminismVariables), variableToWritingFragment(variableToWritingFragment), illegalFragment(illegalFragment) {
                     // Intentionally left empty.
                 }
                 
@@ -946,6 +963,9 @@ namespace storm {
                 // A DD that represents the transitions of this edge.
                 storm::dd::Add<Type, ValueType> transitions;
                 
+                // A mapping from transient variables to their assignments.
+                std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
+                
                 // The local nondeterminism variables used by this action DD, given as the lowest
                 std::pair<uint64_t, uint64_t> localNondeterminismVariables;
                 
@@ -960,7 +980,7 @@ namespace storm {
             
             // This structure represents a subcomponent of a composition.
             struct AutomatonDd {
-                AutomatonDd(storm::dd::Add<Type, ValueType> const& identity) : actionIndexToAction(), identity(identity), localNondeterminismVariables(std::make_pair<uint64_t, uint64_t>(0, 0)) {
+                AutomatonDd(storm::dd::Add<Type, ValueType> const& identity, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientLocationAssignments = {}) : actionIndexToAction(), transientLocationAssignments(transientLocationAssignments), identity(identity), localNondeterminismVariables(std::make_pair<uint64_t, uint64_t>(0, 0)) {
                     // Intentionally left empty.
                 }
                 
@@ -988,6 +1008,9 @@ namespace storm {
                 // A mapping from action indices to the action DDs.
                 std::map<uint64_t, ActionDd> actionIndexToAction;
                 
+                // A mapping from transient variables to their location-based transient assignment values.
+                std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientLocationAssignments;
+                
                 // The identity of the automaton's variables.
                 storm::dd::Add<Type, ValueType> identity;
                 
@@ -996,7 +1019,7 @@ namespace storm {
 
             };
             
-            CombinedEdgesSystemComposer(storm::jani::Model const& model, CompositionVariables<Type, ValueType> const& variables) : SystemComposer<Type, ValueType>(model, variables) {
+            CombinedEdgesSystemComposer(storm::jani::Model const& model, CompositionVariables<Type, ValueType> const& variables, std::vector<storm::expressions::Variable> const& transientVariables) : SystemComposer<Type, ValueType>(model, variables, transientVariables) {
                 // Intentionally left empty.
             }
 
@@ -1080,6 +1103,7 @@ namespace storm {
         private:
             AutomatonDd composeInParallel(AutomatonDd const& automaton1, AutomatonDd const& automaton2, std::set<uint64_t> const& synchronizingActionIndices) {
                 AutomatonDd result(automaton1);
+                result.transientLocationAssignments = joinTransientAssignmentMaps(automaton1.transientLocationAssignments, automaton2.transientLocationAssignments);
                 
                 // Treat all actions of the first automaton.
                 for (auto const& action1 : automaton1.actionIndexToAction) {
@@ -1103,7 +1127,7 @@ namespace storm {
                         } else {
                             // If only the first automaton has this action, we only need to apply the identity of the
                             // second automaton.
-                            result.actionIndexToAction[action1.first] = ActionDd(action1.second.guard, action1.second.transitions * automaton2.identity, action1.second.localNondeterminismVariables, action1.second.variableToWritingFragment, action1.second.illegalFragment);
+                            result.actionIndexToAction[action1.first] = ActionDd(action1.second.guard, action1.second.transitions * automaton2.identity, action1.second.transientEdgeAssignments, action1.second.localNondeterminismVariables, action1.second.variableToWritingFragment, action1.second.illegalFragment);
                         }
                     }
                 }
@@ -1116,7 +1140,7 @@ namespace storm {
                         if (synchronizingActionIndices.find(action2.first) == synchronizingActionIndices.end()) {
                             // If only the second automaton has this action, we only need to apply the identity of the
                             // first automaton.
-                            result.actionIndexToAction[action2.first] = ActionDd(action2.second.guard, action2.second.transitions * automaton1.identity, action2.second.localNondeterminismVariables, action2.second.variableToWritingFragment, action2.second.illegalFragment);
+                            result.actionIndexToAction[action2.first] = ActionDd(action2.second.guard, action2.second.transitions * automaton1.identity, action2.second.transientEdgeAssignments, action2.second.localNondeterminismVariables, action2.second.variableToWritingFragment, action2.second.illegalFragment);
                         }
                     }
                 }
@@ -1152,7 +1176,7 @@ namespace storm {
                     }
                 }
                 
-                return ActionDd(action1.guard * action2.guard, action1.transitions * action2.transitions, std::make_pair(std::min(action1.getLowestLocalNondeterminismVariable(), action2.getLowestLocalNondeterminismVariable()), std::max(action1.getHighestLocalNondeterminismVariable(), action2.getHighestLocalNondeterminismVariable())), globalVariableToWritingFragment, illegalFragment);
+                return ActionDd(combinedGuard.template toAdd<ValueType>(), action1.transitions * action2.transitions, joinTransientAssignmentMaps(action1.transientEdgeAssignments, action2.transientEdgeAssignments), std::make_pair(std::min(action1.getLowestLocalNondeterminismVariable(), action2.getLowestLocalNondeterminismVariable()), std::max(action1.getHighestLocalNondeterminismVariable(), action2.getHighestLocalNondeterminismVariable())), globalVariableToWritingFragment, illegalFragment);
             }
             
             ActionDd combineUnsynchronizedActions(ActionDd action1, ActionDd action2, storm::dd::Add<Type, ValueType> const& identity1, storm::dd::Add<Type, ValueType> const& identity2) {
@@ -1169,7 +1193,7 @@ namespace storm {
                 STORM_LOG_TRACE("Combining unsynchronized actions.");
                 
                 if (this->model.getModelType() == storm::jani::ModelType::DTMC || this->model.getModelType() == storm::jani::ModelType::CTMC) {
-                    return ActionDd(action1.guard + action2.guard, action1.transitions + action2.transitions, std::make_pair<uint64_t, uint64_t>(0, 0), joinVariableWritingFragmentMaps(action1.variableToWritingFragment, action2.variableToWritingFragment), this->variables.manager->getBddZero());
+                    return ActionDd(action1.guard + action2.guard, action1.transitions + action2.transitions, joinTransientAssignmentMaps(action1.transientEdgeAssignments, action2.transientEdgeAssignments), std::make_pair<uint64_t, uint64_t>(0, 0), joinVariableWritingFragmentMaps(action1.variableToWritingFragment, action2.variableToWritingFragment), this->variables.manager->getBddZero());
                 } else if (this->model.getModelType() == storm::jani::ModelType::MDP) {
                     if (action1.transitions.isZero()) {
                         return action2;
@@ -1178,7 +1202,7 @@ namespace storm {
                     }
                     
                     // Bring both choices to the same number of variables that encode the nondeterminism.
-                    assert(action1.getLowestLocalNondeterminismVariable() == action2.getLowestLocalNondeterminismVariable());
+                    STORM_LOG_ASSERT(action1.getLowestLocalNondeterminismVariable() == action2.getLowestLocalNondeterminismVariable(), "Mismatching lowest nondeterminism variable indices.");
                     uint_fast64_t highestLocalNondeterminismVariable = std::max(action1.getHighestLocalNondeterminismVariable(), action2.getHighestLocalNondeterminismVariable());
                     if (action1.getHighestLocalNondeterminismVariable() > action2.getHighestLocalNondeterminismVariable()) {
                         storm::dd::Add<Type, ValueType> nondeterminismEncoding = this->variables.manager->template getAddOne<ValueType>();
@@ -1187,6 +1211,10 @@ namespace storm {
                             nondeterminismEncoding *= this->variables.manager->getEncoding(this->variables.localNondeterminismVariables[i], 0).template toAdd<ValueType>();
                         }
                         action2.transitions *= nondeterminismEncoding;
+                        
+                        for (auto& transientAssignment : action2.transientEdgeAssignments) {
+                            transientAssignment.second *= nondeterminismEncoding;
+                        }
                     } else if (action2.getHighestLocalNondeterminismVariable() > action1.getHighestLocalNondeterminismVariable()) {
                         storm::dd::Add<Type, ValueType> nondeterminismEncoding = this->variables.manager->template getAddOne<ValueType>();
                         
@@ -1194,6 +1222,10 @@ namespace storm {
                             nondeterminismEncoding *= this->variables.manager->getEncoding(this->variables.localNondeterminismVariables[i], 0).template toAdd<ValueType>();
                         }
                         action1.transitions *= nondeterminismEncoding;
+
+                        for (auto& transientAssignment : action1.transientEdgeAssignments) {
+                            transientAssignment.second *= nondeterminismEncoding;
+                        }
                     }
                     
                     // Add a new variable that resolves the nondeterminism between the two choices.
@@ -1207,14 +1239,14 @@ namespace storm {
                         entry.second = this->variables.manager->getEncoding(this->variables.localNondeterminismVariables[highestLocalNondeterminismVariable], 1) && entry.second;
                     }
                     
-                    return ActionDd((action1.guard.toBdd() || action2.guard.toBdd()).template toAdd<ValueType>(), combinedTransitions, std::make_pair(action1.getLowestLocalNondeterminismVariable(), highestLocalNondeterminismVariable + 1), joinVariableWritingFragmentMaps(action1.variableToWritingFragment, action2.variableToWritingFragment), action1.illegalFragment || action2.illegalFragment);
+                    return ActionDd((action1.guard.toBdd() || action2.guard.toBdd()).template toAdd<ValueType>(), combinedTransitions, joinTransientAssignmentMaps(action1.transientEdgeAssignments, action2.transientEdgeAssignments), std::make_pair(action1.getLowestLocalNondeterminismVariable(), highestLocalNondeterminismVariable + 1), joinVariableWritingFragmentMaps(action1.variableToWritingFragment, action2.variableToWritingFragment), action1.illegalFragment || action2.illegalFragment);
                 } else {
                     STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Illegal model type.");
                 }
             }
             
             AutomatonDd rename(AutomatonDd const& automaton, std::map<uint64_t, uint64_t> const& indexToIndex) {
-                AutomatonDd result(automaton.identity);
+                AutomatonDd result(automaton.identity, automaton.transientLocationAssignments);
                 
                 for (auto const& action : automaton.actionIndexToAction) {
                     auto renamingIt = indexToIndex.find(action.first);
@@ -1244,6 +1276,23 @@ namespace storm {
                 return result;
             }
             
+            void performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function<void (storm::jani::Assignment const&)> const& callback) {
+                auto transientVariableIt = this->transientVariables.begin();
+                auto transientVariableIte = this->transientVariables.end();
+                for (auto const& assignment : transientAssignments) {
+                    while (transientVariableIt != transientVariableIte && *transientVariableIt < assignment.getExpressionVariable()) {
+                        ++transientVariableIt;
+                    }
+                    if (transientVariableIt == transientVariableIte) {
+                        break;
+                    }
+                    if (*transientVariableIt == assignment.getExpressionVariable()) {
+                        callback(assignment);
+                        ++transientVariableIt;
+                    }
+                }
+            }
+            
             EdgeDd buildEdgeDd(storm::jani::Automaton const& automaton, storm::jani::Edge const& edge) {
                 STORM_LOG_TRACE("Translating guard " << edge.getGuard());
                 
@@ -1309,7 +1358,13 @@ namespace storm {
                         transitions *= this->variables.rowExpressionAdapter->translateExpression(edge.getRate());
                     }
                     
-                    return EdgeDd(guard, guard * transitions, globalVariablesInSomeDestination);
+                    // Finally treat the transient assignments.
+                    std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
+                    if (!this->transientVariables.empty()) {
+                        performTransientAssignments(edge.getAssignments().getTransientAssignments(), [this, &transientEdgeAssignments, &guard] (storm::jani::Assignment const& assignment) { transientEdgeAssignments[assignment.getExpressionVariable()] = guard * this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression()); } );
+                    }
+                    
+                    return EdgeDd(guard, guard * transitions, transientEdgeAssignments, globalVariablesInSomeDestination);
                 } else {
                     return EdgeDd(this->variables.manager->template getAddZero<ValueType>(), this->variables.manager->template getAddZero<ValueType>());
                 }
@@ -1338,16 +1393,52 @@ namespace storm {
                             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot translate model of this type.");
                     }
                 } else {
-                    return ActionDd(this->variables.manager->template getAddZero<ValueType>(), this->variables.manager->template getAddZero<ValueType>(), std::make_pair<uint64_t, uint64_t>(0, 0), {}, this->variables.manager->getBddZero());
+                    return ActionDd(this->variables.manager->template getAddZero<ValueType>(), this->variables.manager->template getAddZero<ValueType>(), {}, std::make_pair<uint64_t, uint64_t>(0, 0), {}, this->variables.manager->getBddZero());
                 }
             }
             
+            void addToTransientAssignmentMap(std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>>& transientAssignments, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& assignmentsToAdd) {
+                for (auto const& entry : assignmentsToAdd) {
+                    auto it = transientAssignments.find(entry.first);
+                    if (it != transientAssignments.end()) {
+                        it->second += entry.second;
+                    } else {
+                        transientAssignments[entry.first] = entry.second;
+                    }
+                }
+            }
+
+            void addToTransientAssignmentMap(std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>>& transientAssignments, storm::expressions::Variable const& variable, storm::dd::Add<Type, ValueType> const& assignmentToAdd) {
+                auto it = transientAssignments.find(variable);
+                if (it != transientAssignments.end()) {
+                    it->second += assignmentToAdd;
+                } else {
+                    transientAssignments[variable] = assignmentToAdd;
+                }
+            }
+
+            std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> joinTransientAssignmentMaps(std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientAssignments1, std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> const& transientAssignments2) {
+                std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> result = transientAssignments1;
+                
+                for (auto const& entry : transientAssignments2) {
+                    auto resultIt = result.find(entry.first);
+                    if (resultIt != result.end()) {
+                        resultIt->second += entry.second;
+                    } else {
+                        result[entry.first] = entry.second;
+                    }
+                }
+                
+                return result;
+            }
+
             ActionDd combineEdgesToActionMarkovChain(std::vector<EdgeDd> const& edgeDds) {
                 storm::dd::Bdd<Type> allGuards = this->variables.manager->getBddZero();
                 storm::dd::Add<Type, ValueType> allTransitions = this->variables.manager->template getAddZero<ValueType>();
                 storm::dd::Bdd<Type> temporary;
                 
                 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
+                std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
                 for (auto const& edgeDd : edgeDds) {
                     // Check for overlapping guards.
                     storm::dd::Bdd<Type> guardBdd = edgeDd.guard.toBdd();
@@ -1360,6 +1451,9 @@ namespace storm {
                     allGuards |= guardBdd;
                     allTransitions += edgeDd.transitions;
                     
+                    // Add the transient variable assignments to the resulting one.
+                    addToTransientAssignmentMap(transientEdgeAssignments, edgeDd.transientEdgeAssignments);
+                    
                     // Keep track of the fragment that is writing global variables.
                     for (auto const& variable : edgeDd.writtenGlobalVariables) {
                         auto it = globalVariableToWritingFragment.find(variable);
@@ -1371,7 +1465,7 @@ namespace storm {
                     }
                 }
                 
-                return ActionDd(allGuards.template toAdd<ValueType>(), allTransitions, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment, this->variables.manager->getBddZero());
+                return ActionDd(allGuards.template toAdd<ValueType>(), allTransitions, transientEdgeAssignments, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment, this->variables.manager->getBddZero());
             }
             
             void addToVariableWritingFragmentMap(std::map<storm::expressions::Variable, storm::dd::Bdd<Type>>& globalVariableToWritingFragment, storm::expressions::Variable const& variable, storm::dd::Bdd<Type> const& partToAdd) const {
@@ -1401,13 +1495,15 @@ namespace storm {
             ActionDd combineEdgesBySummation(storm::dd::Add<Type, ValueType> const& guard, std::vector<EdgeDd> const& edges) {
                 storm::dd::Add<Type, ValueType> transitions = this->variables.manager->template getAddZero<ValueType>();
                 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
+                std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
                 for (auto const& edge : edges) {
                     transitions += edge.transitions;
+                    addToTransientAssignmentMap(transientEdgeAssignments, edge.transientEdgeAssignments);
                     for (auto const& variable : edge.writtenGlobalVariables) {
                         addToVariableWritingFragmentMap(globalVariableToWritingFragment, variable, edge.guard.toBdd());
                     }
                 }
-                return ActionDd(guard, transitions, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment, this->variables.manager->getBddZero());
+                return ActionDd(guard, transitions, transientEdgeAssignments, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment, this->variables.manager->getBddZero());
             }
             
             ActionDd combineEdgesToActionMdp(std::vector<EdgeDd> const& edges, uint64_t localNondeterminismVariableOffset) {
@@ -1430,6 +1526,7 @@ namespace storm {
                     
                     storm::dd::Add<Type, ValueType> allEdges = this->variables.manager->template getAddZero<ValueType>();
                     std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
+                    std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientAssignments;
                     
                     storm::dd::Bdd<Type> equalsNumberOfChoicesDd;
                     std::vector<storm::dd::Add<Type, ValueType>> choiceDds(maxChoices, this->variables.manager->template getAddZero<ValueType>());
@@ -1480,6 +1577,11 @@ namespace storm {
                                     // Combine the overlapping part of the guard with command updates and add it to the resulting DD.
                                     choiceDds[k] += remainingGuardChoicesIntersection.template toAdd<ValueType>() * currentEdge.transitions;
                                     
+                                    // Keep track of the fragment of transient assignments.
+                                    for (auto const& transientAssignment : currentEdge.transientEdgeAssignments) {
+                                        addToTransientAssignmentMap(transientAssignments, transientAssignment.first, remainingGuardChoicesIntersection.template toAdd<ValueType>() * transientAssignment.second * indicesEncodedWithLocalNondeterminismVariables[k].first.template toAdd<ValueType>());
+                                    }
+                                    
                                     // Keep track of the written global variables of the fragment.
                                     for (auto const& variable : currentEdge.writtenGlobalVariables) {
                                         addToVariableWritingFragmentMap(globalVariableToWritingFragment, variable, remainingGuardChoicesIntersection && indicesEncodedWithLocalNondeterminismVariables[k].first);
@@ -1505,7 +1607,7 @@ namespace storm {
                         sumOfGuards = sumOfGuards * (!equalsNumberOfChoicesDd).template toAdd<ValueType>();
                     }
                     
-                    return ActionDd(allGuards.template toAdd<ValueType>(), allEdges, std::make_pair(localNondeterminismVariableOffset, localNondeterminismVariableOffset + numberOfBinaryVariables), globalVariableToWritingFragment, this->variables.manager->getBddZero());
+                    return ActionDd(allGuards.template toAdd<ValueType>(), allEdges, transientAssignments, std::make_pair(localNondeterminismVariableOffset, localNondeterminismVariableOffset + numberOfBinaryVariables), globalVariableToWritingFragment, this->variables.manager->getBddZero());
                 }
             }
             
@@ -1523,6 +1625,20 @@ namespace storm {
                     result.setLowestLocalNondeterminismVariable(std::max(result.getLowestLocalNondeterminismVariable(), actionDd.getLowestLocalNondeterminismVariable()));
                     result.setHighestLocalNondeterminismVariable(std::max(result.getHighestLocalNondeterminismVariable(), actionDd.getHighestLocalNondeterminismVariable()));
                 }
+                
+                for (uint64_t locationIndex = 0; locationIndex < automaton.getNumberOfLocations(); ++locationIndex) {
+                    auto const& location = automaton.getLocation(locationIndex);
+                    performTransientAssignments(location.getAssignments().getTransientAssignments(), [this,&automatonName,locationIndex,&result] (storm::jani::Assignment const& assignment) {
+                        storm::dd::Add<Type, ValueType> assignedValues = this->variables.manager->getEncoding(this->variables.automatonToLocationVariableMap.at(automatonName).first, locationIndex).template toAdd<ValueType>() * this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression());
+                        auto it = result.transientLocationAssignments.find(assignment.getExpressionVariable());
+                        if (it != result.transientLocationAssignments.end()) {
+                            it->second += assignedValues;
+                        } else {
+                            result.transientLocationAssignments[assignment.getExpressionVariable()] = assignedValues;
+                        }
+                    });
+                }
+                
                 return result;
             }
 
@@ -1553,28 +1669,36 @@ namespace storm {
                     uint64_t numberOfUsedNondeterminismVariables = automaton.getHighestLocalNondeterminismVariable();
                     
                     // Add missing global variable identities, action and nondeterminism encodings.
+                    std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
                     for (auto& action : automaton.actionIndexToAction) {
                         illegalFragment |= action.second.illegalFragment;
                         addMissingGlobalVariableIdentities(action.second);
                         storm::dd::Add<Type, ValueType> actionEncoding = encodeAction(action.first != this->model.getSilentActionIndex() ? boost::optional<uint64_t>(action.first) : boost::none, this->variables);
                         storm::dd::Add<Type, ValueType> missingNondeterminismEncoding = encodeIndex(0, action.second.getHighestLocalNondeterminismVariable(), numberOfUsedNondeterminismVariables - action.second.getHighestLocalNondeterminismVariable(), this->variables);
                         storm::dd::Add<Type, ValueType> extendedTransitions = actionEncoding * missingNondeterminismEncoding * action.second.transitions;
+                        
+                        for (auto const& transientAssignment : action.second.transientEdgeAssignments) {
+                            addToTransientAssignmentMap(transientEdgeAssignments, transientAssignment.first, actionEncoding * missingNondeterminismEncoding * transientAssignment.second);
+                        }
+                        
                         result += extendedTransitions;
                     }
                     
-                    return ComposerResult<Type, ValueType>(result, illegalFragment, numberOfUsedNondeterminismVariables);
+                    return ComposerResult<Type, ValueType>(result, automaton.transientLocationAssignments, transientEdgeAssignments, illegalFragment, numberOfUsedNondeterminismVariables);
                 } else if (this->model.getModelType() == storm::jani::ModelType::DTMC || this->model.getModelType() == storm::jani::ModelType::CTMC) {
                     // Simply add all actions, but make sure to include the missing global variable identities.
 
                     storm::dd::Add<Type, ValueType> result = this->variables.manager->template getAddZero<ValueType>();
                     storm::dd::Bdd<Type> illegalFragment = this->variables.manager->getBddZero();
+                    std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
                     for (auto& action : automaton.actionIndexToAction) {
                         illegalFragment |= action.second.illegalFragment;
                         addMissingGlobalVariableIdentities(action.second);
+                        addToTransientAssignmentMap(transientEdgeAssignments, action.second.transientEdgeAssignments);
                         result += action.second.transitions;
                     }
 
-                    return ComposerResult<Type, ValueType>(result, illegalFragment, 0);
+                    return ComposerResult<Type, ValueType>(result, automaton.transientLocationAssignments, transientEdgeAssignments, illegalFragment, 0);
                 } else {
                     STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Illegal model type.");
                 }
@@ -1718,31 +1842,100 @@ namespace storm {
         }
         
         template <storm::dd::DdType Type, typename ValueType>
-        std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdJaniModelBuilder<Type, ValueType>::build() {
+        std::vector<storm::expressions::Variable> selectRewardVariables(storm::jani::Model const& model, typename DdJaniModelBuilder<Type, ValueType>::Options const& options) {
+            std::vector<storm::expressions::Variable> result;
+            if (options.isBuildAllRewardModelsSet()) {
+                for (auto const& variable : model.getGlobalVariables()) {
+                    if (variable.isTransient()) {
+                        result.push_back(variable.getExpressionVariable());
+                    }
+                }
+            } else {
+                auto const& globalVariables = model.getGlobalVariables();
+                for (auto const& rewardModelName : options.getRewardModelNames()) {
+                    if (globalVariables.hasVariable(rewardModelName)) {
+                        result.push_back(globalVariables.getVariable(rewardModelName).getExpressionVariable());
+                    } else {
+                        STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException, "Cannot build unknown reward model '" << rewardModelName << "'.");
+                        STORM_LOG_THROW(globalVariables.getNumberOfTransientVariables() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous.");
+                    }
+                }
+                
+                // If no reward model was yet added, but there was one that was given in the options, we try to build the
+                // standard reward model.
+                if (result.empty() && !options.getRewardModelNames().empty()) {
+                    result.push_back(globalVariables.getTransientVariables().front()->getExpressionVariable());
+                }
+            }
+            
+            return result;
+        }
+        
+        template <storm::dd::DdType Type, typename ValueType>
+        std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<Type, ValueType>> buildRewardModels(ComposerResult<Type, ValueType> const& system, std::vector<storm::expressions::Variable> const& rewardVariables) {
+            std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<Type, ValueType>> result;
+            
+            for (auto const& variable : rewardVariables) {
+                boost::optional<storm::dd::Add<Type, ValueType>> stateRewards = boost::none;
+                boost::optional<storm::dd::Add<Type, ValueType>> stateActionRewards = boost::none;
+                boost::optional<storm::dd::Add<Type, ValueType>> transitionRewards = boost::none;
+                
+                auto it = system.transientLocationAssignments.find(variable);
+                if (it != system.transientLocationAssignments.end()) {
+                    stateRewards = it->second;
+                }
+                
+                it = system.transientEdgeAssignments.find(variable);
+                if (it != system.transientEdgeAssignments.end()) {
+                    stateActionRewards = it->second;
+                }
+                
+                result.emplace(variable.getName(), storm::models::symbolic::StandardRewardModel<Type, ValueType>(stateRewards, stateActionRewards, transitionRewards));
+            }
+            
+            return result;
+        }
+        
+        template <storm::dd::DdType Type, typename ValueType>
+        std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdJaniModelBuilder<Type, ValueType>::build(storm::jani::Model const& model, Options const& options) {
+            if (model.hasUndefinedConstants()) {
+                std::vector<std::reference_wrapper<storm::jani::Constant const>> undefinedConstants = model.getUndefinedConstants();
+                std::vector<std::string> strings;
+                for (auto const& constant : undefinedConstants) {
+                    std::stringstream stream;
+                    stream << constant.get().getName() << " (" << constant.get().getType() << ")";
+                    strings.push_back(stream.str());
+                }
+                STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Model still contains these undefined constants: " << boost::join(strings, ", ") << ".");
+            }
+            
             // Create all necessary variables.
-            CompositionVariableCreator<Type, ValueType> variableCreator(*this->model);
+            CompositionVariableCreator<Type, ValueType> variableCreator(model);
             CompositionVariables<Type, ValueType> variables = variableCreator.create();
             
+            // Determine which transient assignments need to be considered in the building process.
+            std::vector<storm::expressions::Variable> rewardVariables = selectRewardVariables<Type, ValueType>(model, options);
+            
             // Create a builder to compose and build the model.
-//            SeparateEdgesSystemComposer<Type, ValueType> composer(*this->model, variables);
-            CombinedEdgesSystemComposer<Type, ValueType> composer(*this->model, variables);
+//            SeparateEdgesSystemComposer<Type, ValueType> composer(model, variables);
+            CombinedEdgesSystemComposer<Type, ValueType> composer(model, variables, rewardVariables);
             ComposerResult<Type, ValueType> system = composer.compose();
             
             // Postprocess the variables in place.
-            postprocessVariables(this->model->getModelType(), system, variables);
+            postprocessVariables(model.getModelType(), system, variables);
             
             // Postprocess the system in place and get the states that were terminal (i.e. whose transitions were cut off).
-            storm::dd::Bdd<Type> terminalStates = postprocessSystem(*this->model, system, variables, options);
+            storm::dd::Bdd<Type> terminalStates = postprocessSystem(model, system, variables, options);
             
             // Start creating the model components.
             ModelComponents<Type, ValueType> modelComponents;
             
             // Build initial states.
-            modelComponents.initialStates = computeInitialStates(*this->model, variables);
+            modelComponents.initialStates = computeInitialStates(model, variables);
             
             // Perform reachability analysis to obtain reachable states.
             storm::dd::Bdd<Type> transitionMatrixBdd = system.transitions.notZero();
-            if (this->model->getModelType() == storm::jani::ModelType::MDP) {
+            if (model.getModelType() == storm::jani::ModelType::MDP) {
                 transitionMatrixBdd = transitionMatrixBdd.existsAbstract(variables.allNondeterminismVariables);
             }
             modelComponents.reachableStates = storm::utility::dd::computeReachableStates(modelComponents.initialStates, transitionMatrixBdd, variables.rowMetaVariables, variables.columnMetaVariables);
@@ -1756,13 +1949,16 @@ namespace storm {
             modelComponents.transitionMatrix = system.transitions * reachableStatesAdd;
             
             // Fix deadlocks if existing.
-            modelComponents.deadlockStates = fixDeadlocks(this->model->getModelType(), modelComponents.transitionMatrix, transitionMatrixBdd, modelComponents.reachableStates, variables);
+            modelComponents.deadlockStates = fixDeadlocks(model.getModelType(), modelComponents.transitionMatrix, transitionMatrixBdd, modelComponents.reachableStates, variables);
             
             // Cut the deadlock states by removing all states that we 'converted' to deadlock states by making them terminal.
             modelComponents.deadlockStates = modelComponents.deadlockStates && !terminalStates;
             
+            // Build the reward models.
+            modelComponents.rewardModels = buildRewardModels(system, rewardVariables);
+            
             // Finally, create the model.
-            return createModel(this->model->getModelType(), variables, modelComponents);
+            return createModel(model.getModelType(), variables, modelComponents);
         }
         
         template class DdJaniModelBuilder<storm::dd::DdType::CUDD, double>;
diff --git a/src/builder/DdJaniModelBuilder.h b/src/builder/DdJaniModelBuilder.h
index 348d017ad..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;
                 
@@ -77,11 +87,6 @@ namespace storm {
                 boost::optional<storm::expressions::Expression> negatedTerminalStates;
             };
             
-            /*!
-             * Creates a builder for the given model that uses the given options.
-             */
-            DdJaniModelBuilder(storm::jani::Model const& model, Options const& options = Options());
-            
             /*!
              * Translates the given program into a symbolic model (i.e. one that stores the transition relation as a
              * decision diagram).
@@ -89,22 +94,7 @@ namespace storm {
              * @param model The model to translate.
              * @return A pointer to the resulting model.
              */
-            std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> build();
-            
-            /*!
-             * Retrieves the model that was actually translated (i.e. including constant substitutions etc.). Note
-             * that this function may only be called after a succesful translation.
-             *
-             * @return The translated model.
-             */
-            storm::jani::Model const& getTranslatedModel() const;
-                        
-        private:
-            /// The model to translate.
-            boost::optional<storm::jani::Model> model;
-            
-            /// The options to use for building the model.
-            Options options;
+            std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> build(storm::jani::Model const& model, Options const& options = Options());
         };
         
     }
diff --git a/src/builder/DdPrismModelBuilder.cpp b/src/builder/DdPrismModelBuilder.cpp
index a397b0de0..b45269dc4 100644
--- a/src/builder/DdPrismModelBuilder.cpp
+++ b/src/builder/DdPrismModelBuilder.cpp
@@ -1219,20 +1219,15 @@ namespace storm {
                 }
             }
             
+            stateActionRewards.get().exportToDot("prismrew.dot");
+            
             return storm::models::symbolic::StandardRewardModel<Type, ValueType>(stateRewards, stateActionRewards, transitionRewards);
         }
         
-        template <storm::dd::DdType Type, typename ValueType>
-        storm::prism::Program const& DdPrismModelBuilder<Type, ValueType>::getTranslatedProgram() const {
-            return preparedProgram.get();
-        }
-        
         template <storm::dd::DdType Type, typename ValueType>
         std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdPrismModelBuilder<Type, ValueType>::build(storm::prism::Program const& program, Options const& options) {
-            preparedProgram = program;
-            
-            if (preparedProgram->hasUndefinedConstants()) {
-                std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = preparedProgram->getUndefinedConstants();
+            if (program.hasUndefinedConstants()) {
+                std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = program.getUndefinedConstants();
                 std::stringstream stream;
                 bool printComma = false;
                 for (auto const& constant : undefinedConstants) {
@@ -1247,13 +1242,11 @@ namespace storm {
                 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " + stream.str());
             }
             
-            preparedProgram = preparedProgram->substituteConstants();
-            
-            STORM_LOG_DEBUG("Building representation of program:" << std::endl << *preparedProgram << std::endl);
+            STORM_LOG_DEBUG("Building representation of program:" << std::endl << program << std::endl);
             
             // Start by initializing the structure used for storing all information needed during the model generation.
             // In particular, this creates the meta variables used to encode the model.
-            GenerationInformation generationInfo(*preparedProgram);
+            GenerationInformation generationInfo(program);
             
             SystemResult system = createSystemDecisionDiagram(generationInfo);
             storm::dd::Add<Type, ValueType> transitionMatrix = system.allTransitionsDd;
@@ -1264,7 +1257,7 @@ namespace storm {
             // If we were asked to treat some states as terminal states, we cut away their transitions now.
             storm::dd::Bdd<Type> terminalStatesBdd = generationInfo.manager->getBddZero();
             if (options.terminalStates || options.negatedTerminalStates) {
-                std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = preparedProgram->getConstantsSubstitution();
+                std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = program.getConstantsSubstitution();
                 
                 if (options.terminalStates) {
                     storm::expressions::Expression terminalExpression;
@@ -1273,7 +1266,7 @@ namespace storm {
                     } else {
                         std::string const& labelName = boost::get<std::string>(options.terminalStates.get());
                         if (program.hasLabel(labelName)) {
-                            terminalExpression = preparedProgram->getLabelExpression(labelName);
+                            terminalExpression = program.getLabelExpression(labelName);
                         } else {
                             STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'.");
                         }
@@ -1294,7 +1287,7 @@ namespace storm {
                     } else {
                         std::string const& labelName = boost::get<std::string>(options.negatedTerminalStates.get());
                         if (program.hasLabel(labelName)) {
-                            negatedTerminalExpression = preparedProgram->getLabelExpression(labelName);
+                            negatedTerminalExpression = program.getLabelExpression(labelName);
                         } else {
                             STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'.");
                         }
@@ -1377,18 +1370,18 @@ namespace storm {
             
             // First, we make sure that all selected reward models actually exist.
             for (auto const& rewardModelName : options.rewardModelsToBuild) {
-                STORM_LOG_THROW(rewardModelName.empty() || preparedProgram->hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException, "Model does not possess a reward model with the name '" << rewardModelName << "'.");
+                STORM_LOG_THROW(rewardModelName.empty() || program.hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException, "Model does not possess a reward model with the name '" << rewardModelName << "'.");
             }
             
-            for (auto const& rewardModel : preparedProgram->getRewardModels()) {
+            for (auto const& rewardModel : program.getRewardModels()) {
                 if (options.buildAllRewardModels || options.rewardModelsToBuild.find(rewardModel.getName()) != options.rewardModelsToBuild.end()) {
                     selectedRewardModels.push_back(rewardModel);
                 }
             }
             // If no reward model was selected until now and a referenced reward model appears to be unique, we build
             // the only existing reward model (given that no explicit name was given for the referenced reward model).
-            if (selectedRewardModels.empty() && preparedProgram->getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") {
-                selectedRewardModels.push_back(preparedProgram->getRewardModel(0));
+            if (selectedRewardModels.empty() && program.getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") {
+                selectedRewardModels.push_back(program.getRewardModel(0));
             }
             
             std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<Type, ValueType>> rewardModels;
@@ -1398,7 +1391,7 @@ namespace storm {
             
             // Build the labels that can be accessed as a shortcut.
             std::map<std::string, storm::expressions::Expression> labelToExpressionMapping;
-            for (auto const& label : preparedProgram->getLabels()) {
+            for (auto const& label : program.getLabels()) {
                 labelToExpressionMapping.emplace(label.getName(), label.getStatePredicateExpression());
             }
             
@@ -1415,7 +1408,7 @@ namespace storm {
         
         template <storm::dd::DdType Type, typename ValueType>
         storm::dd::Bdd<Type> DdPrismModelBuilder<Type, ValueType>::createInitialStatesDecisionDiagram(GenerationInformation& generationInfo) {
-            storm::dd::Bdd<Type> initialStates = generationInfo.rowExpressionAdapter->translateExpression(generationInfo.program.getInitialConstruct().getInitialStatesExpression()).toBdd();
+            storm::dd::Bdd<Type> initialStates = generationInfo.rowExpressionAdapter->translateExpression(generationInfo.program.getInitialStatesExpression()).toBdd();
             
             for (auto const& metaVariable : generationInfo.rowMetaVariables) {
                 initialStates &= generationInfo.manager->getRange(metaVariable);
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 148c8d357..755674cd1 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,42 +208,46 @@ namespace storm {
                 storm::utility::initializeFileLogging();
             }
 
-            if (storm::settings::getModule<storm::settings::modules::IOSettings>().isSymbolicSet()) {
-                // If we have to build the model from a symbolic representation, we need to parse the representation first.
-                storm::prism::Program program = storm::parseProgram(storm::settings::getModule<storm::settings::modules::IOSettings>().getSymbolicModelFilename());
+            auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
+            if (ioSettings.isPrismOrJaniInputSet()) {
+                storm::storage::SymbolicModelDescription model;
+                if (ioSettings.isPrismInputSet()) {
+                    model = storm::parseProgram(ioSettings.getPrismInputFilename());
+                    if (ioSettings.isPrismToJaniSet()) {
+                        model = model.toJani(true);
+                    }
+                } else if (ioSettings.isJaniInputSet()) {
+                    model = storm::parseJaniModel(ioSettings.getJaniInputFilename()).first;
+                }
                 
                 // Get the string that assigns values to the unknown currently undefined constants in the model.
-                std::string constantDefinitionString = storm::settings::getModule<storm::settings::modules::IOSettings>().getConstantDefinitionString();
-                storm::prism::Program preprocessedProgram = storm::utility::prism::preprocess(program, constantDefinitionString);
-                std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = preprocessedProgram.getConstantsSubstitution();
+                std::string constantDefinitionString = ioSettings.getConstantDefinitionString();
+                model = model.preprocess(constantDefinitionString);
 
                 // Then proceed to parsing the properties (if given), since the model we are building may depend on the property.
                 std::vector<std::shared_ptr<storm::logic::Formula const>> formulas;
                 if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isPropertySet()) {
-                    formulas = storm::parseFormulasForProgram(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), preprocessedProgram);
-                }
-
-                // There may be constants of the model appearing in the formulas, so we replace all their occurrences
-                // by their definitions in the translated program.
-                std::vector<std::shared_ptr<storm::logic::Formula const>> preprocessedFormulas;
-                for (auto const& formula : formulas) {
-                    preprocessedFormulas.emplace_back(formula->substitute(constantsSubstitution));
+                    if (model.isJaniModel()) {
+                        formulas = storm::parseFormulasForJaniModel(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), model.asJaniModel());
+                    } else {
+                        formulas = storm::parseFormulasForPrismProgram(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty(), model.asPrismProgram());
+                    }
                 }
 
                 if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isParametricSet()) {
 #ifdef STORM_HAVE_CARL
-                    buildAndCheckSymbolicModel<storm::RationalFunction>(preprocessedProgram, preprocessedFormulas, true);
+                    buildAndCheckSymbolicModel<storm::RationalFunction>(model, formulas, true);
 #else
                     STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No parameters are supported in this build.");
 #endif
                 } else if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isExactSet()) {
 #ifdef STORM_HAVE_CARL
-                    buildAndCheckSymbolicModel<storm::RationalNumber>(preprocessedProgram, preprocessedFormulas, true);
+                    buildAndCheckSymbolicModel<storm::RationalNumber>(model, formulas, true);
 #else
                     STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No exact numbers are supported in this build.");
 #endif
                 } else {
-                    buildAndCheckSymbolicModel<double>(preprocessedProgram, preprocessedFormulas, true);
+                    buildAndCheckSymbolicModel<double>(model, formulas, true);
                 }
             } else if (storm::settings::getModule<storm::settings::modules::IOSettings>().isExplicitSet()) {
                 STORM_LOG_THROW(storm::settings::getModule<storm::settings::modules::CoreSettings>().getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Only the sparse engine supports explicit model input.");
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/counterexamples/SMTMinimalCommandSetGenerator.h b/src/counterexamples/SMTMinimalCommandSetGenerator.h
index 44ebb71ec..64665a8fc 100644
--- a/src/counterexamples/SMTMinimalCommandSetGenerator.h
+++ b/src/counterexamples/SMTMinimalCommandSetGenerator.h
@@ -628,7 +628,7 @@ namespace storm {
                 }
                 
                 // Construct an expression that exactly characterizes the initial state.
-                storm::expressions::Expression initialStateExpression = program.getInitialConstruct().getInitialStatesExpression();
+                storm::expressions::Expression initialStateExpression = program.getInitialStatesExpression();
                 
                 // Store the found implications in a container similar to the preceding label sets.
                 std::map<boost::container::flat_set<uint_fast64_t>, std::set<boost::container::flat_set<uint_fast64_t>>> backwardImplications;
diff --git a/src/generator/JaniNextStateGenerator.cpp b/src/generator/JaniNextStateGenerator.cpp
index cfb08fb79..5b5f54151 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,39 @@ namespace storm {
         }
         
         template<typename ValueType, typename StateType>
-        JaniNextStateGenerator<ValueType, StateType>::JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options, bool flag) : NextStateGenerator<ValueType, StateType>(model.getExpressionManager(), VariableInformation(model), options), model(model) {
+        JaniNextStateGenerator<ValueType, StateType>::JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options, bool flag) : NextStateGenerator<ValueType, StateType>(model.getExpressionManager(), VariableInformation(model), options), model(model), rewardVariables() {
             STORM_LOG_THROW(model.hasDefaultComposition(), storm::exceptions::WrongFormatException, "The explicit next-state generator currently does not support custom system compositions.");
-            STORM_LOG_THROW(!this->options.isBuildAllRewardModelsSet() && this->options.getRewardModelNames().empty(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support building reward models.");
+            STORM_LOG_THROW(!model.hasNonGlobalTransientVariable(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support automata-local transient variables.");
             STORM_LOG_THROW(!this->options.isBuildChoiceLabelsSet(), storm::exceptions::InvalidSettingsException, "JANI next-state generator cannot generate choice labels.");
             
+            if (this->options.isBuildAllRewardModelsSet()) {
+                for (auto const& variable : model.getGlobalVariables()) {
+                    if (variable.isTransient()) {
+                        rewardVariables.push_back(variable.getExpressionVariable());
+                    }
+                }
+            } else {
+                // Extract the reward models from the program based on the names we were given.
+                auto const& globalVariables = model.getGlobalVariables();
+                for (auto const& rewardModelName : this->options.getRewardModelNames()) {
+                    if (globalVariables.hasVariable(rewardModelName)) {
+                        rewardVariables.push_back(globalVariables.getVariable(rewardModelName).getExpressionVariable());
+                    } else {
+                        STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException, "Cannot build unknown reward model '" << rewardModelName << "'.");
+                        STORM_LOG_THROW(globalVariables.getNumberOfTransientVariables() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous.");
+                    }
+                }
+                
+                // If no reward model was yet added, but there was one that was given in the options, we try to build the
+                // standard reward model.
+                if (rewardVariables.empty() && !this->options.getRewardModelNames().empty()) {
+                    rewardVariables.push_back(globalVariables.getTransientVariables().front()->getExpressionVariable());
+                }
+            }
+            
+            // Build the information structs for the reward models.
+            buildRewardModelInformation();
+            
             // If there are terminal states we need to handle, we now need to translate all labels to expressions.
             if (this->options.hasTerminalStates()) {
                 for (auto const& expressionOrLabelAndBool : this->options.getTerminalStates()) {
@@ -161,6 +190,9 @@ namespace storm {
                 }
                 
                 // Block the current initial state to search for the next one.
+                if (!blockingExpression.isInitialized()) {
+                    break;
+                }
                 solver->add(blockingExpression);
             }
             
@@ -171,13 +203,8 @@ namespace storm {
         CompressedState JaniNextStateGenerator<ValueType, StateType>::applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& destination) {
             CompressedState newState(state);
             
-            // NOTE: the following process assumes that the assignments of the destination are ordered in such a way
-            // that the assignments to boolean variables precede the assignments to all integer variables and that
-            // within the types, the assignments to variables are ordered (in ascending order) by the expression variables.
-            // This is guaranteed for JANI models, by sorting the assignments as soon as an edge destination is created.
-            
-            auto assignmentIt = destination.getAssignments().begin();
-            auto assignmentIte = destination.getAssignments().end();
+            auto assignmentIt = destination.getNonTransientAssignments().begin();
+            auto assignmentIte = destination.getNonTransientAssignments().end();
             
             // Iterate over all boolean assignments and carry them out.
             auto boolIt = this->variableInformation.booleanVariables.begin();
@@ -211,6 +238,22 @@ namespace storm {
             // Prepare the result, in case we return early.
             StateBehavior<ValueType, StateType> result;
             
+            // Retrieve the locations from the state.
+            std::vector<uint64_t> locations = getLocations(*this->state);
+
+            // First, construct the state rewards, as we may return early if there are no choices later and we already
+            // need the state rewards then.
+            std::vector<ValueType> stateRewards(this->rewardVariables.size(), storm::utility::zero<ValueType>());
+            uint64_t automatonIndex = 0;
+            for (auto const& automaton : model.getAutomata()) {
+                uint64_t currentLocationIndex = locations[automatonIndex];
+                storm::jani::Location const& location = automaton.getLocation(currentLocationIndex);
+                auto valueIt = stateRewards.begin();
+                performTransientAssignments(location.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } );
+                ++automatonIndex;
+            }
+            result.addStateRewards(std::move(stateRewards));
+            
             // If a terminal expression was set and we must not expand this state, return now.
             if (!this->terminalStates.empty()) {
                 for (auto const& expressionBool : this->terminalStates) {
@@ -220,9 +263,6 @@ namespace storm {
                 }
             }
             
-            // Retrieve the locations from the state.
-            std::vector<uint64_t> locations = getLocations(*this->state);
-            
             // Get all choices for the state.
             std::vector<Choice<ValueType>> allChoices = getSilentActionChoices(locations, *this->state, stateToIdCallback);
             std::vector<Choice<ValueType>> allLabeledChoices = getNonsilentActionChoices(locations, *this->state, stateToIdCallback);
@@ -308,6 +348,9 @@ namespace storm {
                         probabilitySum += probability;
                     }
                     
+                    // Create the state-action reward for the newly created choice.
+                    performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&choice] (ValueType const& value) { choice.addChoiceReward(value); } );
+
                     // Check that the resulting distribution is in fact a distribution.
                     STORM_LOG_THROW(!this->isDiscreteTimeModel() || this->comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Probabilities do not sum to one for edge (actually sum to " << probabilitySum << ").");
                 }
@@ -477,13 +520,12 @@ namespace storm {
         
         template<typename ValueType, typename StateType>
         std::size_t JaniNextStateGenerator<ValueType, StateType>::getNumberOfRewardModels() const {
-            return 0;
+            return rewardVariables.size();
         }
         
         template<typename ValueType, typename StateType>
         RewardModelInformation JaniNextStateGenerator<ValueType, StateType>::getRewardModelInformation(uint64_t const& index) const {
-            STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Cannot retrieve reward model information.");
-            return RewardModelInformation("", false, false, false);
+            return rewardModelInformation[index];
         }
         
         template<typename ValueType, typename StateType>
@@ -491,6 +533,81 @@ namespace storm {
             return NextStateGenerator<ValueType, StateType>::label(states, initialStateIndices, deadlockStateIndices, {});
         }
         
+        template<typename ValueType, typename StateType>
+        void JaniNextStateGenerator<ValueType, StateType>::performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function<void (ValueType const&)> const& callback) {
+            // If there are no reward variables, there is no need to iterate at all.
+            if (rewardVariables.empty()) {
+                return;
+            }
+            
+            // Otherwise, perform the callback for all selected reward variables.
+            auto rewardVariableIt = rewardVariables.begin();
+            auto rewardVariableIte = rewardVariables.end();
+            for (auto const& assignment : transientAssignments) {
+                while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) {
+                    callback(storm::utility::zero<ValueType>());
+                    ++rewardVariableIt;
+                }
+                if (rewardVariableIt == rewardVariableIte) {
+                    break;
+                } else if (*rewardVariableIt == assignment.getExpressionVariable()) {
+                    callback(ValueType(this->evaluator.asRational(assignment.getAssignedExpression())));
+                    ++rewardVariableIt;
+                }
+            }
+            // Add a value of zero for all variables that have no assignment.
+            for (; rewardVariableIt != rewardVariableIte; ++rewardVariableIt) {
+                callback(storm::utility::zero<ValueType>());
+            }
+        }
+        
+        template<typename ValueType, typename StateType>
+        void JaniNextStateGenerator<ValueType, StateType>::buildRewardModelInformation() {
+            // Prepare all reward model information structs.
+            for (auto const& variable : rewardVariables) {
+                rewardModelInformation.emplace_back(variable.getName(), false, false, false);
+            }
+            
+            // Then fill them.
+            for (auto const& automaton : model.getAutomata()) {
+                for (auto const& location : automaton.getLocations()) {
+                    auto rewardVariableIt = rewardVariables.begin();
+                    auto rewardVariableIte = rewardVariables.end();
+                    
+                    for (auto const& assignment : location.getAssignments().getTransientAssignments()) {
+                        while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) {
+                            ++rewardVariableIt;
+                        }
+                        if (rewardVariableIt == rewardVariableIte) {
+                            break;
+                        }
+                        if (*rewardVariableIt == assignment.getExpressionVariable()) {
+                            rewardModelInformation[std::distance(rewardVariables.begin(), rewardVariableIt)].setHasStateRewards();
+                            ++rewardVariableIt;
+                        }
+                    }
+                }
+
+                for (auto const& edge : automaton.getEdges()) {
+                    auto rewardVariableIt = rewardVariables.begin();
+                    auto rewardVariableIte = rewardVariables.end();
+                    
+                    for (auto const& assignment : edge.getAssignments().getTransientAssignments()) {
+                        while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) {
+                            ++rewardVariableIt;
+                        }
+                        if (rewardVariableIt == rewardVariableIte) {
+                            break;
+                        }
+                        if (*rewardVariableIt == assignment.getExpressionVariable()) {
+                            rewardModelInformation[std::distance(rewardVariables.begin(), rewardVariableIt)].setHasStateActionRewards();
+                            ++rewardVariableIt;
+                        }
+                    }
+                }
+            }
+        }
+        
         template class JaniNextStateGenerator<double>;
 
 #ifdef STORM_HAVE_CARL
diff --git a/src/generator/JaniNextStateGenerator.h b/src/generator/JaniNextStateGenerator.h
index 316d6e074..d9932f60a 100644
--- a/src/generator/JaniNextStateGenerator.h
+++ b/src/generator/JaniNextStateGenerator.h
@@ -89,8 +89,25 @@ namespace storm {
              */
             void checkGlobalVariableWritesValid(std::vector<std::vector<storm::jani::Edge const*>> const& enabledEdges) const;
             
+            /*!
+             * Treats the given transient assignments by calling the callback function whenever a transient assignment
+             * to one of the reward variables of this generator is performed.
+             */
+            void performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function<void (ValueType const&)> const& callback);
+            
+            /*!
+             * Builds the information structs for the reward models.
+             */
+            void buildRewardModelInformation();
+            
             /// The model used for the generation of next states.
             storm::jani::Model model;
+            
+            /// The transient variables of reward models that need to be considered.
+            std::vector<storm::expressions::Variable> rewardVariables;
+            
+            /// A vector storing information about the corresponding reward models (variables).
+            std::vector<RewardModelInformation> rewardModelInformation;
         };
         
     }
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/generator/PrismNextStateGenerator.cpp b/src/generator/PrismNextStateGenerator.cpp
index c0026a98d..1ecbec2ab 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);
@@ -41,11 +42,10 @@ namespace storm {
                     } else {
                         STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException, "Cannot build unknown reward model '" << rewardModelName << "'.");
                         STORM_LOG_THROW(this->program.getNumberOfRewardModels() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous.");
-                        STORM_LOG_THROW(this->program.getNumberOfRewardModels() > 0, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is invalid, because there is no reward model.");
                     }
                 }
                 
-                // If no reward model was yet added, but there was one that was given in the options, we try to build
+                // If no reward model was yet added, but there was one that was given in the options, we try to build the
                 // standard reward model.
                 if (rewardModels.empty() && !this->options.getRewardModelNames().empty()) {
                     rewardModels.push_back(this->program.getRewardModel(0));
@@ -136,7 +136,7 @@ namespace storm {
             for (auto const& expression : rangeExpressions) {
                 solver->add(expression);
             }
-            solver->add(program.getInitialConstruct().getInitialStatesExpression());
+            solver->add(program.getInitialStatesExpression());
             
             // Proceed ss long as the solver can still enumerate initial states.
             std::vector<StateType> initialStateIndices;
@@ -166,6 +166,9 @@ namespace storm {
                 initialStateIndices.push_back(id);
                 
                 // Block the current initial state to search for the next one.
+                if (!blockingExpression.isInitialized()) {
+                    break;
+                }
                 solver->add(blockingExpression);
             }
             
@@ -314,7 +317,7 @@ namespace storm {
         template<typename ValueType, typename StateType>
         boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> PrismNextStateGenerator<ValueType, StateType>::getActiveCommandsByActionIndex(uint_fast64_t const& actionIndex) {
             boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> result((std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>()));
-            
+                        
             // Iterate over all modules.
             for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
                 storm::prism::Module const& module = program.getModule(i);
@@ -445,7 +448,6 @@ namespace storm {
                         
                         for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) {
                             storm::prism::Command const& command = *iteratorList[i];
-                            
                             for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) {
                                 storm::prism::Update const& update = command.getUpdate(j);
                                 
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/modelchecker/AbstractModelChecker.cpp b/src/modelchecker/AbstractModelChecker.cpp
index 616dcf828..660906acb 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/symbolic/StandardRewardModel.h"
 #include "src/storage/dd/Add.h"
 #include "src/storage/dd/Bdd.h"
 
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/parser/ExpressionParser.cpp b/src/parser/ExpressionParser.cpp
index 20982bd20..3054f2fe0 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::createRationalLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)] | qi::int_[qi::_val = phoenix::bind(&ExpressionParser::createIntegerLiteralExpression, phoenix::ref(*this), qi::_1, qi::_pass)];
             literalExpression.name("literal expression");
             
             atomicExpression = floorCeilExpression | prefixPowerExpression | minMaxExpression | (qi::lit("(") >> expression >> qi::lit(")")) | literalExpression | identifierExpression;
@@ -295,7 +323,7 @@ namespace storm {
             return manager->boolean(false);
         }
                 
-        storm::expressions::Expression ExpressionParser::createDoubleLiteralExpression(double value, bool& pass) const {
+        storm::expressions::Expression ExpressionParser::createRationalLiteralExpression(storm::RationalNumber const& value, bool& pass) const {
             // If we are not supposed to accept double expressions, we reject it by setting pass to false.
             if (!this->acceptDoubleLiterals) {
                 pass = false;
diff --git a/src/parser/ExpressionParser.h b/src/parser/ExpressionParser.h
index 66d851707..077be8db2 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 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/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/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/parser/JaniParser.h b/src/parser/JaniParser.h
index 82165b5ef..80b4ca0d7 100644
--- a/src/parser/JaniParser.h
+++ b/src/parser/JaniParser.h
@@ -42,7 +42,8 @@ namespace storm {
             storm::jani::Property parseProperty(json const& propertyStructure);
             storm::jani::Automaton parseAutomaton(json const& automatonStructure, storm::jani::Model const& parentModel);
             std::shared_ptr<storm::jani::Variable>  parseVariable(json const& variableStructure, std::string const& scopeDescription, bool prefWithScope = false);
-            storm::expressions::Expression parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars = {});
+            storm::expressions::Expression parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>> const& localVars = std::unordered_map<std::string, std::shared_ptr<storm::jani::Variable>>());
+            
         private:
             std::shared_ptr<storm::jani::Constant> parseConstant(json const& constantStructure, std::string const& scopeDescription = "global");
 
diff --git a/src/parser/PrismParser.cpp b/src/parser/PrismParser.cpp
index 7d54f18c6..d3e5191e2 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;
         }
         
@@ -103,10 +105,10 @@ namespace storm {
             formulaDefinition = (qi::lit("formula") > identifier > qi::lit("=") > expressionParser > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createFormula, phoenix::ref(*this), qi::_1, qi::_2)];
             formulaDefinition.name("formula definition");
             
-            booleanVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("bool")) > ((qi::lit("init") > expressionParser) | qi::attr(manager->boolean(false))) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createBooleanVariable, phoenix::ref(*this), qi::_1, qi::_2)];
+            booleanVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("bool")) > -((qi::lit("init") > expressionParser[qi::_a = qi::_1]) | qi::attr(manager->boolean(false))) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createBooleanVariable, phoenix::ref(*this), qi::_1, qi::_a)];
             booleanVariableDefinition.name("boolean variable definition");
             
-            integerVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("[")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), false)]) > expressionParser[qi::_a = qi::_1] > qi::lit("..") > expressionParser > qi::lit("]")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), true)] > -(qi::lit("init") > expressionParser[qi::_a = qi::_1]) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createIntegerVariable, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_a)];
+            integerVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("[")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), false)]) > expressionParser > qi::lit("..") > expressionParser > qi::lit("]")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), true)] > -(qi::lit("init") > expressionParser[qi::_a = qi::_1]) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createIntegerVariable, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_a)];
             integerVariableDefinition.name("integer variable definition");
             
             variableDefinition = (booleanVariableDefinition[phoenix::push_back(qi::_r1, qi::_1)] | integerVariableDefinition[phoenix::push_back(qi::_r2, qi::_1)]);
@@ -208,7 +210,7 @@ namespace storm {
             moduleDefinitionList %= +(moduleRenaming(qi::_r1) | moduleDefinition(qi::_r1))[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::modules, qi::_r1), qi::_1)];
             moduleDefinitionList.name("module list");
             
-            start = (qi::eps
+            start = (qi::eps[phoenix::bind(&PrismParser::removeInitialConstruct, phoenix::ref(*this), qi::_a)]
                      > modelTypeDefinition[phoenix::bind(&GlobalProgramInformation::modelType, qi::_a) = qi::_1]
                      > *(definedConstantDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::constants, qi::_a), qi::_1)] 
                          | undefinedConstantDefinition[phoenix::push_back(phoenix::bind(&GlobalProgramInformation::constants, qi::_a), qi::_1)]
@@ -276,7 +278,7 @@ namespace storm {
             return true;
         }
         
-        bool PrismParser::addInitialStatesConstruct(storm::expressions::Expression initialStatesExpression, GlobalProgramInformation& globalProgramInformation) {
+        bool PrismParser::addInitialStatesConstruct(storm::expressions::Expression const& initialStatesExpression, GlobalProgramInformation& globalProgramInformation) {
             STORM_LOG_THROW(!globalProgramInformation.hasInitialConstruct, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": Program must not define two initial constructs.");
             if (globalProgramInformation.hasInitialConstruct) {
                 return false;
@@ -585,7 +587,7 @@ namespace storm {
                     auto const& renamingPair = renaming.find(variable.getName());
                     STORM_LOG_THROW(renamingPair != renaming.end(), storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": Boolean variable '" << variable.getName() << " was not renamed.");
                     
-                    booleanVariables.push_back(storm::prism::BooleanVariable(manager->getVariable(renamingPair->second), variable.getInitialValueExpression().substitute(expressionRenaming), this->getFilename(), get_line(qi::_1)));
+                    booleanVariables.push_back(storm::prism::BooleanVariable(manager->getVariable(renamingPair->second), variable.hasInitialValue() ? variable.getInitialValueExpression().substitute(expressionRenaming) : variable.getInitialValueExpression(), this->getFilename(), get_line(qi::_1)));
                 }
                 
                 // Rename the integer variables.
@@ -594,7 +596,7 @@ namespace storm {
                     auto const& renamingPair = renaming.find(variable.getName());
                     STORM_LOG_THROW(renamingPair != renaming.end(), storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": Integer variable '" << variable.getName() << " was not renamed.");
                     
-                    integerVariables.push_back(storm::prism::IntegerVariable(manager->getVariable(renamingPair->second), variable.getLowerBoundExpression().substitute(expressionRenaming), variable.getUpperBoundExpression().substitute(expressionRenaming), variable.getInitialValueExpression().substitute(expressionRenaming), this->getFilename(), get_line(qi::_1)));
+                    integerVariables.push_back(storm::prism::IntegerVariable(manager->getVariable(renamingPair->second), variable.getLowerBoundExpression().substitute(expressionRenaming), variable.getUpperBoundExpression().substitute(expressionRenaming), variable.hasInitialValue() ? variable.getInitialValueExpression().substitute(expressionRenaming) : variable.getInitialValueExpression(), this->getFilename(), get_line(qi::_1)));
                 }
                 
                 // Rename commands.
@@ -640,7 +642,11 @@ namespace storm {
         }
         
         storm::prism::Program PrismParser::createProgram(GlobalProgramInformation const& globalProgramInformation) const {
-            return storm::prism::Program(manager, globalProgramInformation.modelType, globalProgramInformation.constants, globalProgramInformation.globalBooleanVariables, globalProgramInformation.globalIntegerVariables, globalProgramInformation.formulas, globalProgramInformation.modules, globalProgramInformation.actionIndices, globalProgramInformation.rewardModels, globalProgramInformation.labels, secondRun && !globalProgramInformation.hasInitialConstruct ? boost::none : boost::optional<storm::prism::InitialConstruct>(storm::prism::InitialConstruct(manager->boolean(false))), globalProgramInformation.systemCompositionConstruct, this->getFilename(), 1, this->secondRun);
+            return storm::prism::Program(manager, globalProgramInformation.modelType, globalProgramInformation.constants, globalProgramInformation.globalBooleanVariables, globalProgramInformation.globalIntegerVariables, globalProgramInformation.formulas, globalProgramInformation.modules, globalProgramInformation.actionIndices, globalProgramInformation.rewardModels, globalProgramInformation.labels, secondRun && !globalProgramInformation.hasInitialConstruct ? boost::none : boost::make_optional(globalProgramInformation.initialConstruct), globalProgramInformation.systemCompositionConstruct, this->getFilename(), 1, this->secondRun);
+        }
+        
+        void PrismParser::removeInitialConstruct(GlobalProgramInformation& globalProgramInformation) const {
+            globalProgramInformation.hasInitialConstruct = false;
         }
     } // namespace parser
 } // namespace storm
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/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
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..c174f1f51 100644
--- a/src/settings/modules/IOSettings.cpp
+++ b/src/settings/modules/IOSettings.cpp
@@ -17,8 +17,9 @@ namespace storm {
             const std::string IOSettings::exportMatOptionName = "exportmat";
             const std::string IOSettings::explicitOptionName = "explicit";
             const std::string IOSettings::explicitOptionShortName = "exp";
-            const std::string IOSettings::symbolicOptionName = "symbolic";
-            const std::string IOSettings::symbolicOptionShortName = "s";
+            const std::string IOSettings::prismInputOptionName = "prism";
+            const std::string IOSettings::janiInputOptionName = "jani";
+            const std::string IOSettings::prismToJaniOptionName = "prism2jani";
             const std::string IOSettings::explorationOrderOptionName = "explorder";
             const std::string IOSettings::explorationOrderOptionShortName = "eo";
             const std::string IOSettings::transitionRewardsOptionName = "transrew";
@@ -38,8 +39,11 @@ namespace storm {
                 this->addOption(storm::settings::OptionBuilder(moduleName, explicitOptionName, false, "Parses the model given in an explicit (sparse) representation.").setShortName(explicitOptionShortName)
                                 .addArgument(storm::settings::ArgumentBuilder::createStringArgument("transition filename", "The name of the file from which to read the transitions.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build())
                                 .addArgument(storm::settings::ArgumentBuilder::createStringArgument("labeling filename", "The name of the file from which to read the state labeling.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
-                this->addOption(storm::settings::OptionBuilder(moduleName, symbolicOptionName, false, "Parses the model given in a symbolic representation.").setShortName(symbolicOptionShortName)
-                                .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the symbolic model.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
+                this->addOption(storm::settings::OptionBuilder(moduleName, prismInputOptionName, false, "Parses the model given in the PRISM format.")
+                                .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the PRISM input.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
+                this->addOption(storm::settings::OptionBuilder(moduleName, janiInputOptionName, false, "Parses the model given in the JANI format.")
+                                .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the JANI input.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
+                this->addOption(storm::settings::OptionBuilder(moduleName, prismToJaniOptionName, false, "If set, the input PRISM model is transformed to JANI.").build());
 
                 std::vector<std::string> explorationOrders = {"dfs", "bfs"};
                 this->addOption(storm::settings::OptionBuilder(moduleName, explorationOrderOptionName, false, "Sets which exploration order to use.").setShortName(explorationOrderOptionShortName)
@@ -51,7 +55,7 @@ namespace storm {
                                 .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The file from which to read the state rewards.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, choiceLabelingOptionName, false, "If given, the choice labels are read from this file and added to the explicit model. Note that this requires the model to be given as an explicit model (i.e., via --" + explicitOptionName + ").")
                                 .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The file from which to read the choice labels.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
-                this->addOption(storm::settings::OptionBuilder(moduleName, constantsOptionName, false, "Specifies the constant replacements to use in symbolic models. Note that Note that this requires the model to be given as an symbolic model (i.e., via --" + symbolicOptionName + ").").setShortName(constantsOptionShortName)
+                this->addOption(storm::settings::OptionBuilder(moduleName, constantsOptionName, false, "Specifies the constant replacements to use in symbolic models. Note that this requires the model to be given as an symbolic model (i.e., via --" + prismInputOptionName + " or --" + janiInputOptionName + ").").setShortName(constantsOptionShortName)
                                 .addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of constants and their value, e.g. a=1,b=2,c=3.").setDefaultValueString("").build()).build());
             }
 
@@ -75,14 +79,30 @@ namespace storm {
                 return this->getOption(explicitOptionName).getArgumentByName("labeling filename").getValueAsString();
             }
             
-            bool IOSettings::isSymbolicSet() const {
-                return this->getOption(symbolicOptionName).getHasOptionBeenSet();
+            bool IOSettings::isPrismInputSet() const {
+                return this->getOption(prismInputOptionName).getHasOptionBeenSet();
             }
             
-            std::string IOSettings::getSymbolicModelFilename() const {
-                return this->getOption(symbolicOptionName).getArgumentByName("filename").getValueAsString();
+            bool IOSettings::isPrismOrJaniInputSet() const {
+                return isJaniInputSet() || isPrismInputSet();
             }
             
+            bool IOSettings::isPrismToJaniSet() const {
+                return this->getOption(prismToJaniOptionName).getHasOptionBeenSet();
+            }
+            
+            std::string IOSettings::getPrismInputFilename() const {
+                return this->getOption(prismInputOptionName).getArgumentByName("filename").getValueAsString();
+            }
+
+            bool IOSettings::isJaniInputSet() const {
+                return this->getOption(janiInputOptionName).getHasOptionBeenSet();
+            }
+
+            std::string IOSettings::getJaniInputFilename() const {
+                return this->getOption(janiInputOptionName).getArgumentByName("filename").getValueAsString();
+            }
+
             bool IOSettings::isExplorationOrderSet() const {
                 return this->getOption(explorationOrderOptionName).getHasOptionBeenSet();
             }
@@ -141,8 +161,15 @@ namespace storm {
             }
 
             bool IOSettings::check() const {
+                // Ensure that not two symbolic input models were given.
+                STORM_LOG_THROW(!isJaniInputSet() || !isPrismInputSet(), storm::exceptions::InvalidSettingsException, "Symbolic model ");
+                
                 // Ensure that the model was given either symbolically or explicitly.
-                STORM_LOG_THROW(!isSymbolicSet() || !isExplicitSet(), storm::exceptions::InvalidSettingsException, "The model may be either given in an explicit or a symbolic format, but not both.");
+                STORM_LOG_THROW(!isJaniInputSet() || !isPrismInputSet() || !isExplicitSet(), storm::exceptions::InvalidSettingsException, "The model may be either given in an explicit or a symbolic format (PRISM or JANI), but not both.");
+                
+                // Make sure PRISM-to-JANI conversion is only set if the actual input is in PRISM format.
+                STORM_LOG_THROW(!isPrismToJaniSet() || isPrismInputSet(), storm::exceptions::InvalidSettingsException, "For the transformation from PRISM to JANI, the input model must be given in the prism format.");
+                
                 return true;
             }
 
diff --git a/src/settings/modules/IOSettings.h b/src/settings/modules/IOSettings.h
index eb1ced407..ae6ce6831 100644
--- a/src/settings/modules/IOSettings.h
+++ b/src/settings/modules/IOSettings.h
@@ -59,20 +59,49 @@ namespace storm {
                 std::string getLabelingFilename() const;
 
                 /*!
-                 * Retrieves whether the symbolic option was set.
+                 * Retrieves whether the PRISM language option was set.
                  *
-                 * @return True if the symbolic option was set.
+                 * @return True if the PRISM input option was set.
                  */
-                bool isSymbolicSet() const;
+                bool isPrismInputSet() const;
+                
+                /*!
+                 * Retrieves whether the JANI input option was set.
+                 *
+                 * @return True if the JANI input option was set.
+                 */
+                bool isJaniInputSet() const;
 
                 /*!
-                 * Retrieves the name of the file that contains the symbolic model specification if the model was given
-                 * using the symbolic option.
+                 * Retrieves whether the JANI or PRISM input option was set.
+                 *
+                 * @return True if either of the two options was set.
+                 */
+                bool isPrismOrJaniInputSet() const;
+                
+                /*!
+                 * Retrieves whether the option to convert PRISM to JANI input was set.
                  *
-                 * @return The name of the file that contains the symbolic model specification.
+                 * @return True if the option was set.
                  */
-                std::string getSymbolicModelFilename() const;
+                bool isPrismToJaniSet() const;
                 
+                /*!
+                 * Retrieves the name of the file that contains the PRISM model specification if the model was given
+                 * using the PRISM input option.
+                 *
+                 * @return The name of the file that contains the PRISM model specification.
+                 */
+                std::string getPrismInputFilename() const;
+
+                /*!
+                 * Retrieves the name of the file that contains the JANI model specification if the model was given
+                 * using the JANI input option.
+                 *
+                 * @return The name of the file that contains the JANI model specification.
+                 */
+                std::string getJaniInputFilename() const;
+
                 /*!
                  * Retrieves whether the model exploration order was set.
                  *
@@ -174,8 +203,9 @@ namespace storm {
                 static const std::string exportMatOptionName;
                 static const std::string explicitOptionName;
                 static const std::string explicitOptionShortName;
-                static const std::string symbolicOptionName;
-                static const std::string symbolicOptionShortName;
+                static const std::string prismInputOptionName;
+                static const std::string janiInputOptionName;
+                static const std::string prismToJaniOptionName;
                 static const std::string explorationOrderOptionName;
                 static const std::string explorationOrderOptionShortName;
                 static const std::string transitionRewardsOptionName;
diff --git a/src/storage/SymbolicModelDescription.cpp b/src/storage/SymbolicModelDescription.cpp
new file mode 100644
index 000000000..1058e464f
--- /dev/null
+++ b/src/storage/SymbolicModelDescription.cpp
@@ -0,0 +1,83 @@
+#include "src/storage/SymbolicModelDescription.h"
+
+#include "src/utility/prism.h"
+#include "src/utility/jani.h"
+
+#include "src/utility/macros.h"
+#include "src/exceptions/InvalidOperationException.h"
+
+namespace storm {
+    namespace storage {
+        
+        SymbolicModelDescription::SymbolicModelDescription(storm::jani::Model const& model) : modelDescription(model) {
+            // Intentionally left empty.
+        }
+        
+        SymbolicModelDescription::SymbolicModelDescription(storm::prism::Program const& program) : modelDescription(program) {
+            // Intentionally left empty.
+        }
+        
+        SymbolicModelDescription& SymbolicModelDescription::operator=(storm::jani::Model const& model) {
+            this->modelDescription = model;
+            return *this;
+        }
+        
+        SymbolicModelDescription& SymbolicModelDescription::operator=(storm::prism::Program const& program) {
+            this->modelDescription = program;
+            return *this;
+        }
+        
+        bool SymbolicModelDescription::hasModel() const {
+            return static_cast<bool>(modelDescription);
+        }
+        
+        bool SymbolicModelDescription::isJaniModel() const {
+            return modelDescription.get().which() == 0;
+        }
+        
+        bool SymbolicModelDescription::isPrismProgram() const {
+            return modelDescription.get().which() == 1;
+        }
+        
+        void SymbolicModelDescription::setModel(storm::jani::Model const& model) {
+            modelDescription = model;
+        }
+        
+        void SymbolicModelDescription::setModel(storm::prism::Program const& program) {
+            modelDescription = program;
+        }
+        
+        storm::jani::Model const& SymbolicModelDescription::asJaniModel() const {
+            STORM_LOG_THROW(isJaniModel(), storm::exceptions::InvalidOperationException, "Cannot retrieve JANI model, because the symbolic description has a different type.");
+            return boost::get<storm::jani::Model>(modelDescription.get());
+        }
+        
+        storm::prism::Program const& SymbolicModelDescription::asPrismProgram() const {
+            STORM_LOG_THROW(isPrismProgram(), storm::exceptions::InvalidOperationException, "Cannot retrieve JANI model, because the symbolic description has a different type.");
+            return boost::get<storm::prism::Program>(modelDescription.get());
+        }
+        
+        SymbolicModelDescription SymbolicModelDescription::toJani(bool makeVariablesGlobal) const {
+            if (this->isJaniModel()) {
+                return *this;
+            }
+            if (this->isPrismProgram()) {
+                return SymbolicModelDescription(this->asPrismProgram().toJani(makeVariablesGlobal));
+            } else {
+                STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot transform model description to the JANI format.");
+            }
+        }
+        
+        SymbolicModelDescription SymbolicModelDescription::preprocess(std::string const& constantDefinitionString) const {
+            if (this->isJaniModel()) {
+                std::map<storm::expressions::Variable, storm::expressions::Expression> substitution = storm::utility::jani::parseConstantDefinitionString(this->asJaniModel(), constantDefinitionString);
+                return SymbolicModelDescription(this->asJaniModel().defineUndefinedConstants(substitution).substituteConstants());
+            } else if (this->isPrismProgram()) {
+                std::map<storm::expressions::Variable, storm::expressions::Expression> substitution = storm::utility::prism::parseConstantDefinitionString(this->asPrismProgram(), constantDefinitionString);
+                return SymbolicModelDescription(this->asPrismProgram().defineUndefinedConstants(substitution).substituteConstants());
+            }
+            return *this;
+        }
+        
+    }
+}
\ No newline at end of file
diff --git a/src/storage/SymbolicModelDescription.h b/src/storage/SymbolicModelDescription.h
new file mode 100644
index 000000000..8b5b85d88
--- /dev/null
+++ b/src/storage/SymbolicModelDescription.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <boost/variant.hpp>
+
+#include "src/storage/jani/Model.h"
+#include "src/storage/prism/Program.h"
+
+namespace storm {
+    namespace storage {
+        
+        class SymbolicModelDescription {
+        public:
+            SymbolicModelDescription() = default;
+            SymbolicModelDescription(storm::jani::Model const& model);
+            SymbolicModelDescription(storm::prism::Program const& program);
+
+            SymbolicModelDescription& operator=(storm::jani::Model const& model);
+            SymbolicModelDescription& operator=(storm::prism::Program const& program);
+            
+            bool hasModel() const;
+            bool isJaniModel() const;
+            bool isPrismProgram() const;
+
+            void setModel(storm::jani::Model const& model);
+            void setModel(storm::prism::Program const& program);
+            
+            storm::jani::Model const& asJaniModel() const;
+            storm::prism::Program const& asPrismProgram() const;
+            
+            SymbolicModelDescription toJani(bool makeVariablesGlobal = true) const;
+            
+            SymbolicModelDescription preprocess(std::string const& constantDefinitionString = "") const;
+            
+        private:
+            boost::optional<boost::variant<storm::jani::Model, storm::prism::Program>> modelDescription;
+        };
+        
+    }
+}
\ No newline at end of file
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 95a326de1..eda2d0377 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));
                 }
             }
             
@@ -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/DoubleLiteralExpression.cpp b/src/storage/expressions/DoubleLiteralExpression.cpp
deleted file mode 100644
index cab9fc31b..000000000
--- a/src/storage/expressions/DoubleLiteralExpression.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#include "src/storage/expressions/DoubleLiteralExpression.h"
-#include "src/storage/expressions/ExpressionManager.h"
-#include "src/storage/expressions/ExpressionVisitor.h"
-
-namespace storm {
-    namespace expressions {
-        DoubleLiteralExpression::DoubleLiteralExpression(ExpressionManager const& manager, double value) : BaseExpression(manager, manager.getRationalType()), value(value) {
-            // Intentionally left empty.
-        }
-        
-        double DoubleLiteralExpression::evaluateAsDouble(Valuation const* valuation) const {
-            return this->getValue();
-        }
-        
-        bool DoubleLiteralExpression::isLiteral() const {
-            return true;
-        }
-        
-        void DoubleLiteralExpression::gatherVariables(std::set<storm::expressions::Variable>& variables) const {
-            return;
-		}
-        
-        std::shared_ptr<BaseExpression const> DoubleLiteralExpression::simplify() const {
-            return this->shared_from_this();
-        }
-        
-        boost::any DoubleLiteralExpression::accept(ExpressionVisitor& visitor) const {
-            return visitor.visit(*this);
-        }
-        
-        double DoubleLiteralExpression::getValue() const {
-            return this->value;
-        }
-        
-        void DoubleLiteralExpression::printToStream(std::ostream& stream) const {
-            stream << this->getValue();
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/storage/expressions/DoubleLiteralExpression.h b/src/storage/expressions/DoubleLiteralExpression.h
deleted file mode 100644
index 676291a77..000000000
--- a/src/storage/expressions/DoubleLiteralExpression.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef STORM_STORAGE_EXPRESSIONS_DOUBLELITERALEXPRESSION_H_
-#define STORM_STORAGE_EXPRESSIONS_DOUBLELITERALEXPRESSION_H_
-
-#include "src/storage/expressions/BaseExpression.h"
-#include "src/utility/OsDetection.h"
-
-namespace storm {
-    namespace expressions {
-        class DoubleLiteralExpression : public BaseExpression {
-        public:
-            /*!
-             * Creates an double literal expression with the given value.
-             *
-             * @param manager The manager responsible for this expression.
-             * @param value The value of the double literal.
-             */
-            DoubleLiteralExpression(ExpressionManager const& manager, double value);
-            
-            // Instantiate constructors and assignments with their default implementations.
-            DoubleLiteralExpression(DoubleLiteralExpression const& other) = default;
-            DoubleLiteralExpression& operator=(DoubleLiteralExpression const& other) = delete;
-#ifndef WINDOWS
-            DoubleLiteralExpression(DoubleLiteralExpression&&) = default;
-            DoubleLiteralExpression& operator=(DoubleLiteralExpression&&) = delete;
-#endif
-            virtual ~DoubleLiteralExpression() = default;
-            
-            // Override base class methods.
-            virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override;
-            virtual bool isLiteral() const override;
-            virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override;
-            virtual std::shared_ptr<BaseExpression const> simplify() const override;
-            virtual boost::any accept(ExpressionVisitor& visitor) const override;
-
-            /*!
-             * Retrieves the value of the double literal.
-             *
-             * @return The value of the double literal.
-             */
-            double getValue() const;
-            
-        protected:
-            // Override base class method.
-            virtual void printToStream(std::ostream& stream) const override;
-            
-        private:
-            // The value of the double literal.
-            double value;
-        };
-    }
-}
-
-#endif /* STORM_STORAGE_EXPRESSIONS_DOUBLELITERALEXPRESSION_H_ */
\ No newline at end of file
diff --git a/src/storage/expressions/Expression.cpp b/src/storage/expressions/Expression.cpp
index 410b613ec..7493e5ee1 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 176d9316d..334a4f829 100644
--- a/src/storage/expressions/Expression.h
+++ b/src/storage/expressions/Expression.h
@@ -302,7 +302,7 @@ namespace storm {
              *
              * @param visitor The visitor to accept.
              */
-            boost::any accept(ExpressionVisitor& visitor) const;
+            boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const;
             
             /*!
              * Converts the expression into a string.
@@ -311,11 +311,16 @@ namespace storm {
              */
             std::string toString() const;
 
-            /**
+            /*!
              * Checks whether the object encapsulates a base-expression.
              */
             bool isInitialized() const;
 
+            /*!
+             * Checks whether the two expressions are syntatically the same.
+             */
+            bool isSyntacticallyEqual(storm::expressions::Expression const& other) const;
+            
             friend std::ostream& operator<<(std::ostream& stream, Expression const& expression);
 
         private:
diff --git a/src/storage/expressions/ExpressionManager.cpp b/src/storage/expressions/ExpressionManager.cpp
index 36b32caaf..deed0e557 100644
--- a/src/storage/expressions/ExpressionManager.cpp
+++ b/src/storage/expressions/ExpressionManager.cpp
@@ -65,7 +65,11 @@ namespace storm {
         }
 
         Expression ExpressionManager::rational(double value) const {
-            return Expression(std::shared_ptr<BaseExpression>(new DoubleLiteralExpression(*this, value)));
+            return Expression(std::shared_ptr<BaseExpression>(new RationalLiteralExpression(*this, value)));
+        }
+        
+        Expression ExpressionManager::rational(storm::RationalNumber const& value) const {
+            return Expression(std::shared_ptr<BaseExpression>(new RationalLiteralExpression(*this, value)));
         }
         
         bool ExpressionManager::operator==(ExpressionManager const& other) const {
diff --git a/src/storage/expressions/ExpressionManager.h b/src/storage/expressions/ExpressionManager.h
index 3e39369ba..31cef2942 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.
diff --git a/src/storage/expressions/ExpressionVisitor.h b/src/storage/expressions/ExpressionVisitor.h
index 5fdb486c2..cfe2ce9b6 100644
--- a/src/storage/expressions/ExpressionVisitor.h
+++ b/src/storage/expressions/ExpressionVisitor.h
@@ -15,20 +15,20 @@ namespace storm {
         class UnaryNumericalFunctionExpression;
         class BooleanLiteralExpression;
         class IntegerLiteralExpression;
-        class DoubleLiteralExpression;
+        class RationalLiteralExpression;
         
         class ExpressionVisitor {
         public:
-            virtual boost::any visit(IfThenElseExpression const& expression) = 0;
-            virtual boost::any visit(BinaryBooleanFunctionExpression const& expression) = 0;
-            virtual boost::any visit(BinaryNumericalFunctionExpression const& expression) = 0;
-            virtual boost::any visit(BinaryRelationExpression const& expression) = 0;
-            virtual boost::any visit(VariableExpression const& expression) = 0;
-            virtual boost::any visit(UnaryBooleanFunctionExpression const& expression) = 0;
-            virtual boost::any visit(UnaryNumericalFunctionExpression const& expression) = 0;
-            virtual boost::any visit(BooleanLiteralExpression const& expression) = 0;
-            virtual boost::any visit(IntegerLiteralExpression const& expression) = 0;
-            virtual boost::any visit(DoubleLiteralExpression const& expression) = 0;
+            virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) = 0;
+            virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) = 0;
+            virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) = 0;
+            virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) = 0;
+            virtual boost::any visit(VariableExpression const& expression, boost::any const& data) = 0;
+            virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) = 0;
+            virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) = 0;
+            virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) = 0;
+            virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) = 0;
+            virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) = 0;
         };
     }
 }
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/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 8d7f39278..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,16 +143,16 @@ namespace storm {
             }
         }
         
-        boost::any LinearCoefficientVisitor::visit(BooleanLiteralExpression const& expression) {
+        boost::any LinearCoefficientVisitor::visit(BooleanLiteralExpression const& expression, boost::any const& data) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
         }
         
-        boost::any LinearCoefficientVisitor::visit(IntegerLiteralExpression const& expression) {
+        boost::any LinearCoefficientVisitor::visit(IntegerLiteralExpression const& expression, boost::any const& data) {
             return VariableCoefficients(static_cast<double>(expression.getValue()));
         }
         
-        boost::any LinearCoefficientVisitor::visit(DoubleLiteralExpression const& expression) {
-            return VariableCoefficients(expression.getValue());
+        boost::any LinearCoefficientVisitor::visit(RationalLiteralExpression const& expression, boost::any const& data) {
+            return VariableCoefficients(expression.getValueAsDouble());
         }
     }
 }
\ No newline at end of file
diff --git a/src/storage/expressions/LinearCoefficientVisitor.h b/src/storage/expressions/LinearCoefficientVisitor.h
index b48c53d09..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(DoubleLiteralExpression const& expression) override;
+            virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
         };
     }
 }
diff --git a/src/storage/expressions/LinearityCheckVisitor.cpp b/src/storage/expressions/LinearityCheckVisitor.cpp
index 35e1e5c76..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(DoubleLiteralExpression 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 2df8f8084..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(DoubleLiteralExpression const& expression) override;
+            virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
             
         private:
             enum class LinearityStatus { NonLinear, LinearContainsVariables, LinearWithoutVariables };
diff --git a/src/storage/expressions/RationalLiteralExpression.cpp b/src/storage/expressions/RationalLiteralExpression.cpp
new file mode 100644
index 000000000..6c6ee88ff
--- /dev/null
+++ b/src/storage/expressions/RationalLiteralExpression.cpp
@@ -0,0 +1,53 @@
+#include "src/storage/expressions/RationalLiteralExpression.h"
+#include "src/storage/expressions/ExpressionManager.h"
+#include "src/storage/expressions/ExpressionVisitor.h"
+
+#include "src/utility/constants.h"
+
+namespace storm {
+    namespace expressions {
+        RationalLiteralExpression::RationalLiteralExpression(ExpressionManager const& manager, double value) : BaseExpression(manager, manager.getRationalType()), value(storm::utility::convertNumber<storm::RationalNumber>(value)) {
+            // Intentionally left empty.
+        }
+        
+        RationalLiteralExpression::RationalLiteralExpression(ExpressionManager const& manager, std::string const& valueAsString) : BaseExpression(manager, manager.getRationalType()), value(storm::utility::convertNumber<storm::RationalNumber>(valueAsString)) {
+            // Intentionally left empty.
+        }
+        
+        RationalLiteralExpression::RationalLiteralExpression(ExpressionManager const& manager, storm::RationalNumber const& value) : BaseExpression(manager, manager.getRationalType()), value(value) {
+            // Intentionally left empty.
+        }
+        
+        double RationalLiteralExpression::evaluateAsDouble(Valuation const* valuation) const {
+            return this->getValueAsDouble();
+        }
+        
+        bool RationalLiteralExpression::isLiteral() const {
+            return true;
+        }
+        
+        void RationalLiteralExpression::gatherVariables(std::set<storm::expressions::Variable>& variables) const {
+            return;
+		}
+        
+        std::shared_ptr<BaseExpression const> RationalLiteralExpression::simplify() const {
+            return this->shared_from_this();
+        }
+        
+        boost::any RationalLiteralExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
+            return visitor.visit(*this, data);
+        }
+        
+        double RationalLiteralExpression::getValueAsDouble() const {
+            return storm::utility::convertNumber<double>(this->value);
+        }
+        
+        storm::RationalNumber RationalLiteralExpression::getValue() const {
+            return this->value;
+        }
+        
+        void RationalLiteralExpression::printToStream(std::ostream& stream) const {
+            stream << this->getValue();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/storage/expressions/RationalLiteralExpression.h b/src/storage/expressions/RationalLiteralExpression.h
new file mode 100644
index 000000000..e18cf8c43
--- /dev/null
+++ b/src/storage/expressions/RationalLiteralExpression.h
@@ -0,0 +1,78 @@
+#ifndef STORM_STORAGE_EXPRESSIONS_RationalLiteralExpression_H_
+#define STORM_STORAGE_EXPRESSIONS_RationalLiteralExpression_H_
+
+#include "src/storage/expressions/BaseExpression.h"
+#include "src/utility/OsDetection.h"
+
+#include "src/adapters/CarlAdapter.h"
+
+namespace storm {
+    namespace expressions {
+        class RationalLiteralExpression : public BaseExpression {
+        public:
+            /*!
+             * Creates an double literal expression with the given value.
+             *
+             * @param manager The manager responsible for this expression.
+             * @param value The value of the double literal.
+             */
+            RationalLiteralExpression(ExpressionManager const& manager, double value);
+
+            /*!
+             * Creates an double literal expression with the value given as a string.
+             *
+             * @param manager The manager responsible for this expression.
+             * @param value The string representation of the value of the literal.
+             */
+            RationalLiteralExpression(ExpressionManager const& manager, std::string const& valueAsString);
+
+            /*!
+             * Creates an double literal expression with the rational value.
+             *
+             * @param manager The manager responsible for this expression.
+             * @param value The rational number that is the value of this literal expression.
+             */
+            RationalLiteralExpression(ExpressionManager const& manager, storm::RationalNumber const& value);
+
+            // Instantiate constructors and assignments with their default implementations.
+            RationalLiteralExpression(RationalLiteralExpression const& other) = default;
+            RationalLiteralExpression& operator=(RationalLiteralExpression const& other) = delete;
+#ifndef WINDOWS
+            RationalLiteralExpression(RationalLiteralExpression&&) = default;
+            RationalLiteralExpression& operator=(RationalLiteralExpression&&) = delete;
+#endif
+            virtual ~RationalLiteralExpression() = default;
+            
+            // Override base class methods.
+            virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override;
+            virtual bool isLiteral() const override;
+            virtual void gatherVariables(std::set<storm::expressions::Variable>& variables) const override;
+            virtual std::shared_ptr<BaseExpression const> simplify() const override;
+            virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override;
+
+            /*!
+             * Retrieves the value of the double literal.
+             *
+             * @return The value of the double literal.
+             */
+            double getValueAsDouble() const;
+
+            /*!
+             * Retrieves the value of the double literal.
+             *
+             * @return The value of the double literal.
+             */
+            storm::RationalNumber getValue() const;
+            
+        protected:
+            // Override base class method.
+            virtual void printToStream(std::ostream& stream) const override;
+            
+        private:
+            // The value of the literal.
+            storm::RationalNumber value;
+        };
+    }
+}
+
+#endif /* STORM_STORAGE_EXPRESSIONS_RationalLiteralExpression_H_ */
\ No newline at end of file
diff --git a/src/storage/expressions/SubstitutionVisitor.cpp b/src/storage/expressions/SubstitutionVisitor.cpp
index c736de156..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(DoubleLiteralExpression 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 343521335..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(DoubleLiteralExpression const& expression) override;
+            virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
             
         private:
             // A mapping of variables to expressions with which they shall be replaced.
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 51d9c1f34..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(DoubleLiteralExpression 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 6c285ff28..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(DoubleLiteralExpression const& expression) override;
+            virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
             
         private:
             std::stringstream stream;
diff --git a/src/storage/expressions/ToRationalFunctionVisitor.cpp b/src/storage/expressions/ToRationalFunctionVisitor.cpp
index 1a3dd0fc3..91a3cdc94 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"
 
@@ -16,23 +17,24 @@ namespace storm {
         
         template<typename RationalFunctionType>
         RationalFunctionType ToRationalFunctionVisitor<RationalFunctionType>::toRationalFunction(Expression const& expression) {
-            return boost::any_cast<RationalFunctionType>(expression.accept(*this));
+            return boost::any_cast<RationalFunctionType>(expression.accept(*this, boost::none));
         }
         
         template<typename RationalFunctionType>
-        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(IfThenElseExpression const& expression) {
+        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(IfThenElseExpression const& expression, boost::any const& data) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function.");
         }
         
         template<typename RationalFunctionType>
-        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryBooleanFunctionExpression const& expression) {
+        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function.");
         }
         
         template<typename RationalFunctionType>
-        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryNumericalFunctionExpression const& expression) {
-            RationalFunctionType firstOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getFirstOperand()->accept(*this));
-            RationalFunctionType secondOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getSecondOperand()->accept(*this));
+        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
+            RationalFunctionType firstOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getFirstOperand()->accept(*this, data));
+            RationalFunctionType secondOperandAsRationalFunction = boost::any_cast<RationalFunctionType>(expression.getSecondOperand()->accept(*this, data));
+            uint_fast64_t exponentAsInteger = 0;
             switch(expression.getOperatorType()) {
                 case BinaryNumericalFunctionExpression::OperatorType::Plus:
                     return firstOperandAsRationalFunction + secondOperandAsRationalFunction;
@@ -46,6 +48,11 @@ namespace storm {
                 case BinaryNumericalFunctionExpression::OperatorType::Divide:
                     return firstOperandAsRationalFunction / secondOperandAsRationalFunction;
                     break;
+                case BinaryNumericalFunctionExpression::OperatorType::Power:
+                    STORM_LOG_THROW(storm::utility::isInteger(secondOperandAsRationalFunction), storm::exceptions::InvalidArgumentException, "Exponent of power operator must be a positive integer.");
+                    exponentAsInteger = storm::utility::convertNumber<uint_fast64_t>(secondOperandAsRationalFunction);
+                    return storm::utility::pow(firstOperandAsRationalFunction, exponentAsInteger);
+                    break;
                 default:
                     STORM_LOG_ASSERT(false, "Illegal operator type.");
             }
@@ -55,12 +62,12 @@ namespace storm {
         }
         
         template<typename RationalFunctionType>
-        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryRelationExpression const& expression) {
+        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BinaryRelationExpression const& expression, boost::any const& data) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function.");
         }
         
         template<typename RationalFunctionType>
-        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(VariableExpression const& expression) {
+        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(VariableExpression const& expression, boost::any const& data) {
             auto variablePair = variableToVariableMap.find(expression.getVariable());
             if (variablePair != variableToVariableMap.end()) {
                 return convertVariableToPolynomial(variablePair->second);
@@ -72,28 +79,28 @@ namespace storm {
         }
         
         template<typename RationalFunctionType>
-        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(UnaryBooleanFunctionExpression const& expression) {
+        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function.");
         }
         
         template<typename RationalFunctionType>
-        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(UnaryNumericalFunctionExpression const& expression) {
+        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function.");
         }
         
         template<typename RationalFunctionType>
-        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BooleanLiteralExpression const& expression) {
+        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(BooleanLiteralExpression const& expression, boost::any const& data) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational function.");
         }
         
         template<typename RationalFunctionType>
-        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(IntegerLiteralExpression const& expression) {
+        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(IntegerLiteralExpression const& expression, boost::any const& data) {
             return RationalFunctionType(carl::rationalize<storm::RationalNumber>(static_cast<size_t>(expression.getValue())));
         }
         
         template<typename RationalFunctionType>
-        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(DoubleLiteralExpression const& expression) {
-            return RationalFunctionType(carl::rationalize<storm::RationalNumber>(expression.getValue()));
+        boost::any ToRationalFunctionVisitor<RationalFunctionType>::visit(RationalLiteralExpression const& expression, boost::any const& data) {
+            return storm::utility::convertNumber<storm::RationalFunction>(expression.getValue());
         }
 
         template class ToRationalFunctionVisitor<storm::RationalFunction>;
diff --git a/src/storage/expressions/ToRationalFunctionVisitor.h b/src/storage/expressions/ToRationalFunctionVisitor.h
index 12603f44e..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(DoubleLiteralExpression const& expression) override;
+            virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
             
         private:
             template<typename TP = typename RationalFunctionType::PolyType, carl::EnableIf<carl::needs_cache<TP>> = carl::dummy>
diff --git a/src/storage/expressions/ToRationalNumberVisitor.cpp b/src/storage/expressions/ToRationalNumberVisitor.cpp
index 785f36950..cfe2cbb35 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"
 
@@ -13,71 +14,81 @@ namespace storm {
         
         template<typename RationalNumberType>
         RationalNumberType ToRationalNumberVisitor<RationalNumberType>::toRationalNumber(Expression const& expression) {
-            return boost::any_cast<RationalNumberType>(expression.accept(*this));
+            return boost::any_cast<RationalNumberType>(expression.accept(*this, boost::none));
         }
         
         template<typename RationalNumberType>
-        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(IfThenElseExpression const& expression) {
+        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(IfThenElseExpression const& expression, boost::any const& data) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
         }
         
         template<typename RationalNumberType>
-        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryBooleanFunctionExpression const& expression) {
+        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
         }
         
         template<typename RationalNumberType>
-        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryNumericalFunctionExpression const& expression) {
-            RationalNumberType firstOperandAsRationalFunction = boost::any_cast<RationalNumberType>(expression.getFirstOperand()->accept(*this));
-            RationalNumberType secondOperandAsRationalFunction = boost::any_cast<RationalNumberType>(expression.getSecondOperand()->accept(*this));
+        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
+            RationalNumberType firstOperandAsRationalNumber = boost::any_cast<RationalNumberType>(expression.getFirstOperand()->accept(*this, data));
+            RationalNumberType secondOperandAsRationalNumber = boost::any_cast<RationalNumberType>(expression.getSecondOperand()->accept(*this, data));
             switch(expression.getOperatorType()) {
                 case BinaryNumericalFunctionExpression::OperatorType::Plus:
-                    return firstOperandAsRationalFunction + secondOperandAsRationalFunction;
+                    return firstOperandAsRationalNumber + secondOperandAsRationalNumber;
                     break;
                 case BinaryNumericalFunctionExpression::OperatorType::Minus:
-                    return firstOperandAsRationalFunction - secondOperandAsRationalFunction;
+                    return firstOperandAsRationalNumber - secondOperandAsRationalNumber;
                     break;
                 case BinaryNumericalFunctionExpression::OperatorType::Times:
-                    return firstOperandAsRationalFunction * secondOperandAsRationalFunction;
+                    return firstOperandAsRationalNumber * secondOperandAsRationalNumber;
                     break;
                 case BinaryNumericalFunctionExpression::OperatorType::Divide:
-                    return firstOperandAsRationalFunction / secondOperandAsRationalFunction;
+                    return firstOperandAsRationalNumber / secondOperandAsRationalNumber;
+                    break;
+                case BinaryNumericalFunctionExpression::OperatorType::Min:
+                    return std::min(firstOperandAsRationalNumber, secondOperandAsRationalNumber);
+                    break;
+                case BinaryNumericalFunctionExpression::OperatorType::Max:
+                    return std::max(firstOperandAsRationalNumber, secondOperandAsRationalNumber);
+                    break;
+                case BinaryNumericalFunctionExpression::OperatorType::Power:
+                    STORM_LOG_THROW(storm::utility::isInteger(secondOperandAsRationalNumber), storm::exceptions::InvalidArgumentException, "Exponent of power operator must be a positive integer.");
+                    uint_fast64_t exponentAsInteger = storm::utility::convertNumber<uint_fast64_t>(secondOperandAsRationalNumber);
+                    return storm::utility::pow(firstOperandAsRationalNumber, exponentAsInteger);
                     break;
-                default:
-                    STORM_LOG_ASSERT(false, "Illegal operator type.");
             }
             
             // Return a dummy. This point must, however, never be reached.
+            STORM_LOG_ASSERT(false, "Illegal operator type.");
             return boost::any();
         }
         
         template<typename RationalNumberType>
-        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryRelationExpression const& expression) {
+        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BinaryRelationExpression const& expression, boost::any const& data) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
         }
         
         template<typename RationalNumberType>
-        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(VariableExpression const& expression) {
+        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(VariableExpression const& expression, boost::any const& data) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot transform expressions containing variables to a rational number.");
         }
         
         template<typename RationalNumberType>
-        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(UnaryBooleanFunctionExpression const& expression) {
+        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
         }
         
         template<typename RationalNumberType>
-        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(UnaryNumericalFunctionExpression const& expression) {
+        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
         }
         
         template<typename RationalNumberType>
-        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BooleanLiteralExpression const& expression) {
+        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(BooleanLiteralExpression const& expression, boost::any const& data) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression cannot be translated into a rational number.");
         }
         
         template<typename RationalNumberType>
-        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(IntegerLiteralExpression const& expression) {
+        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(IntegerLiteralExpression const& expression, boost::any const& data) {
 #ifdef STORM_HAVE_CARL
             return RationalNumberType(carl::rationalize<storm::RationalNumber>(static_cast<size_t>(expression.getValue())));
 #else
@@ -86,9 +97,9 @@ namespace storm {
         }
         
         template<typename RationalNumberType>
-        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(DoubleLiteralExpression const& expression) {
+        boost::any ToRationalNumberVisitor<RationalNumberType>::visit(RationalLiteralExpression const& expression, boost::any const& data) {
 #ifdef STORM_HAVE_CARL
-            return RationalNumberType(carl::rationalize<storm::RationalNumber>(expression.getValue()));
+            return expression.getValue();
 #else
             STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Rational numbers are not supported in this build.");
 #endif
diff --git a/src/storage/expressions/ToRationalNumberVisitor.h b/src/storage/expressions/ToRationalNumberVisitor.h
index 2254931f6..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(DoubleLiteralExpression const& expression) override;
+            virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
+            virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
         };
     }
 }
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 fa7cad7e3..988b17a12 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));
                 }
             }
             
@@ -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..ddf65afe4 100644
--- a/src/storage/jani/Assignment.cpp
+++ b/src/storage/jani/Assignment.cpp
@@ -1,10 +1,18 @@
 #include "src/storage/jani/Assignment.h"
 
+#include "src/utility/macros.h"
+#include "src/exceptions/NotImplementedException.h"
+
 namespace storm  {
     namespace jani {
         
-        Assignment::Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression) : variable(variable), expression(expression) {
-            // Intentionally left empty.
+        Assignment::Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression, uint64_t level) : variable(variable), expression(expression), level(level) {
+            STORM_LOG_THROW(level == 0, storm::exceptions::NotImplementedException, "Assignment levels other than 0 are currently not supported.");
+        }
+        
+        bool Assignment::operator==(Assignment const& other) const {
+            // FIXME: the level is currently ignored as we do not support it 
+            return this->isTransient() == other.isTransient() && this->getExpressionVariable() == other.getExpressionVariable() && this->getAssignedExpression().isSyntacticallyEqual(other.getAssignedExpression());
         }
         
         storm::jani::Variable const& Assignment::getVariable() const {
@@ -23,8 +31,16 @@ namespace storm  {
             this->expression = expression;
         }
         
-        bool Assignment::isTransientAssignment() const {
-            return this->variable.get().isTransientVariable();
+        bool Assignment::isTransient() const {
+            return this->variable.get().isTransient();
+        }
+        
+        void Assignment::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) {
+            this->setAssignedExpression(this->getAssignedExpression().substitute(substitution));
+        }
+        
+        uint64_t Assignment::getLevel() const {
+            return level;
         }
         
         std::ostream& operator<<(std::ostream& stream, Assignment const& assignment) {
@@ -32,5 +48,20 @@ namespace storm  {
             return stream;
         }
         
+        bool AssignmentPartialOrderByVariable::operator()(Assignment const& left, Assignment const& right) const {
+            return left.getExpressionVariable() < right.getExpressionVariable();
+        }
+
+        bool AssignmentPartialOrderByVariable::operator()(Assignment const& left, std::shared_ptr<Assignment> const& right) const {
+            return left.getExpressionVariable() < right->getExpressionVariable();
+        }
+        
+        bool AssignmentPartialOrderByVariable::operator()(std::shared_ptr<Assignment> const& left, std::shared_ptr<Assignment> const& right) const {
+            return left->getExpressionVariable() < right->getExpressionVariable();
+        }
+        
+        bool AssignmentPartialOrderByVariable::operator()(std::shared_ptr<Assignment> const& left, Assignment const& right) const {
+            return left->getExpressionVariable() < right.getExpressionVariable();
+        }
     }
 }
\ No newline at end of file
diff --git a/src/storage/jani/Assignment.h b/src/storage/jani/Assignment.h
index e4b562863..030c1f68f 100644
--- a/src/storage/jani/Assignment.h
+++ b/src/storage/jani/Assignment.h
@@ -13,7 +13,9 @@ namespace storm {
             /*!
              * Creates an assignment of the given expression to the given variable.
              */
-            Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression);
+            Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression, uint64_t index = 0);
+            
+            bool operator==(Assignment const& other) const;
             
             /*!
              * Retrieves the expression variable that is written in this assignment.
@@ -35,10 +37,20 @@ namespace storm {
              */
             void setAssignedExpression(storm::expressions::Expression const& expression);
 
+            /*!
+             * Substitutes all variables in all expressions according to the given substitution.
+             */
+            void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution);
+            
             /**
              * Retrieves whether the assignment assigns to a transient variable.
              */
-            bool isTransientAssignment() const;
+            bool isTransient() const;
+            
+            /*!
+             * Retrieves the level of the assignment.
+             */
+            uint64_t getLevel() const;
             
             friend std::ostream& operator<<(std::ostream& stream, Assignment const& assignment);
             
@@ -48,7 +60,20 @@ namespace storm {
             
             // The expression that is being assigned to the variable.
             storm::expressions::Expression expression;
+            
+            // The level of the assignment.
+            uint64_t level;
         };
         
+        /*!
+         * This functor enables ordering the assignments by variable. Note that this is a partial order.
+         */
+        struct AssignmentPartialOrderByVariable {
+            bool operator()(Assignment const& left, Assignment const& right) const;
+            bool operator()(Assignment const& left, std::shared_ptr<Assignment> const& right) const;
+            bool operator()(std::shared_ptr<Assignment> const& left, std::shared_ptr<Assignment> const& right) const;
+            bool operator()(std::shared_ptr<Assignment> const& left, Assignment const& right) const;
+        };
+    
     }
 }
\ No newline at end of file
diff --git a/src/storage/jani/Automaton.cpp b/src/storage/jani/Automaton.cpp
index c6d8600e3..9c618a838 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() {
@@ -91,6 +97,10 @@ namespace storm {
             return variables;
         }
         
+        bool Automaton::hasTransientVariable() const {
+            return variables.hasTransientVariable();
+        }
+        
         bool Automaton::hasLocation(std::string const& name) const {
             return locationToIndex.find(name) != locationToIndex.end();
         }
@@ -98,11 +108,19 @@ namespace storm {
         std::vector<Location> const& Automaton::getLocations() const {
             return locations;
         }
-        
+
+        std::vector<Location>& Automaton::getLocations() {
+            return locations;
+        }
+
         Location const& Automaton::getLocation(uint64_t index) const {
             return locations[index];
         }
-        
+
+        Location& Automaton::getLocation(uint64_t index) {
+            return locations[index];
+        }
+
         uint64_t Automaton::addLocation(Location const& location) {
             STORM_LOG_THROW(!this->hasLocation(location.getName()), storm::exceptions::WrongFormatException, "Cannot add location with name '" << location.getName() << "', because a location with this name already exists.");
             locationToIndex.emplace(location.getName(), locations.size());
@@ -352,6 +370,22 @@ namespace storm {
             return result;
         }
         
+        void Automaton::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) {
+            for (auto& variable : this->getVariables().getBoundedIntegerVariables()) {
+                variable.substitute(substitution);
+            }
+            
+            for (auto& location : this->getLocations()) {
+                location.substitute(substitution);
+            }
+            
+            this->setInitialStatesRestriction(this->getInitialStatesRestriction().substitute(substitution));
+            
+            for (auto& edge : this->getEdges()) {
+                edge.substitute(substitution);
+            }
+        }
+        
         void Automaton::finalize(Model const& containingModel) {
             for (auto& edge : edges) {
                 edge.finalize(containingModel);
diff --git a/src/storage/jani/Automaton.h b/src/storage/jani/Automaton.h
index 1a2ad61dc..c6219aa1e 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.
@@ -130,6 +135,11 @@ namespace storm {
              */
             VariableSet const& getVariables() const;
             
+            /*!
+             * Retrieves whether this automaton has a transient variable.
+             */
+            bool hasTransientVariable() const;
+            
             /*!
              * Retrieves whether the automaton has a location with the given name.
              */
@@ -147,12 +157,22 @@ namespace storm {
              * Retrieves the locations of the automaton.
              */
             std::vector<Location> const& getLocations() const;
-            
+
+            /*!
+             * Retrieves the locations of the automaton.
+             */
+            std::vector<Location>& getLocations();
+
             /*!
              * Retrieves the location with the given index.
              */
             Location const& getLocation(uint64_t index) const;
             
+            /*!
+             * Retrieves the location with the given index.
+             */
+            Location& getLocation(uint64_t index);
+            
             /*!
              * Adds the given location to the automaton.
              */
@@ -263,6 +283,11 @@ namespace storm {
              */
             std::vector<storm::expressions::Expression> getAllRangeExpressions() const;
             
+            /*!
+             * Substitutes all variables in all expressions according to the given substitution.
+             */
+            void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution);
+            
             /*!
              * Finalizes the building of this automaton. Subsequent changes to the automaton require another call to this
              * method. Note that this method is invoked by a call to <code>finalize</code> to the containing model.
diff --git a/src/storage/jani/BooleanVariable.cpp b/src/storage/jani/BooleanVariable.cpp
index b7a4c4e19..3eb63780b 100644
--- a/src/storage/jani/BooleanVariable.cpp
+++ b/src/storage/jani/BooleanVariable.cpp
@@ -11,10 +11,17 @@ namespace storm {
             // Intentionally left empty.
         }
         
-        
         bool BooleanVariable::isBooleanVariable() const {
             return true;
         }
         
+        std::shared_ptr<BooleanVariable> makeBooleanVariable(std::string const& name, storm::expressions::Variable const& variable, boost::optional<storm::expressions::Expression> initValue, bool transient) {
+            if (initValue) {
+                return std::make_shared<BooleanVariable>(name, variable, initValue.get(), transient);
+            } else {
+                return std::make_shared<BooleanVariable>(name, variable, transient);
+            }
+        }
+        
     }
 }
\ No newline at end of file
diff --git a/src/storage/jani/BooleanVariable.h b/src/storage/jani/BooleanVariable.h
index 7a8fe8b21..7fe9603e0 100644
--- a/src/storage/jani/BooleanVariable.h
+++ b/src/storage/jani/BooleanVariable.h
@@ -21,5 +21,10 @@ namespace storm {
             virtual bool isBooleanVariable() const override;
         };
         
+        /**
+         * Convenience function to call the appropriate constructor and return a shared pointer to the variable.
+         */
+        std::shared_ptr<BooleanVariable> makeBooleanVariable(std::string const& name, storm::expressions::Variable const& variable, boost::optional<storm::expressions::Expression> initValue, bool transient);
+        
     }
 }
\ No newline at end of file
diff --git a/src/storage/jani/BoundedIntegerVariable.cpp b/src/storage/jani/BoundedIntegerVariable.cpp
index f0872a500..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,11 +45,15 @@ namespace storm {
             return true;
         }
         
+        void BoundedIntegerVariable::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) {
+            Variable::substitute(substitution);
+            this->setLowerBound(this->getLowerBound().substitute(substitution));
+            this->setUpperBound(this->getUpperBound().substitute(substitution));
+        }
+        
         std::shared_ptr<BoundedIntegerVariable> makeBoundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, boost::optional<storm::expressions::Expression> initValue, bool transient, boost::optional<storm::expressions::Expression> lowerBound, boost::optional<storm::expressions::Expression> upperBound) {
-            if(!lowerBound || !upperBound) {
-                STORM_LOG_THROW(lowerBound && upperBound, storm::exceptions::NotImplementedException, "Jani Bounded Integer variables (for now) have to be bounded from both sides");
-            }
-            if(initValue) {
+            STORM_LOG_THROW(lowerBound && upperBound, storm::exceptions::NotImplementedException, "Jani Bounded Integer variables (for now) have to be bounded from both sides");
+            if (initValue) {
                 return std::make_shared<BoundedIntegerVariable>(name, variable, initValue.get(), transient, lowerBound.get(), upperBound.get());
             } else {
                 return std::make_shared<BoundedIntegerVariable>(name, variable, transient, lowerBound.get(), upperBound.get());
diff --git a/src/storage/jani/BoundedIntegerVariable.h b/src/storage/jani/BoundedIntegerVariable.h
index c9a42b177..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;
@@ -61,7 +66,7 @@ namespace storm {
         };
         
         /**
-         * Convenience function to call the appropriate constructor and retur a shared pointer to the variable.
+         * Convenience function to call the appropriate constructor and return a shared pointer to the variable.
          */
         std::shared_ptr<BoundedIntegerVariable> makeBoundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, boost::optional<storm::expressions::Expression> initValue, bool transient, boost::optional<storm::expressions::Expression> lowerBound, boost::optional<storm::expressions::Expression> upperBound);
     }
diff --git a/src/storage/jani/Edge.cpp b/src/storage/jani/Edge.cpp
index 347140b1b..0a06f50a8 100644
--- a/src/storage/jani/Edge.cpp
+++ b/src/storage/jani/Edge.cpp
@@ -2,10 +2,13 @@
 
 #include "src/storage/jani/Model.h"
 
+#include "src/utility/macros.h"
+#include "src/exceptions/InvalidArgumentException.h"
+
 namespace storm {
     namespace jani {
         
-        Edge::Edge(uint64_t sourceLocationIndex, uint64_t actionIndex, boost::optional<storm::expressions::Expression> const& rate, storm::expressions::Expression const& guard, std::vector<EdgeDestination> destinations) : sourceLocationIndex(sourceLocationIndex), actionIndex(actionIndex), rate(rate), guard(guard), destinations(destinations) {
+        Edge::Edge(uint64_t sourceLocationIndex, uint64_t actionIndex, boost::optional<storm::expressions::Expression> const& rate, storm::expressions::Expression const& guard, std::vector<EdgeDestination> destinations) : sourceLocationIndex(sourceLocationIndex), actionIndex(actionIndex), rate(rate), guard(guard), destinations(destinations), assignments(), writtenGlobalVariables() {
             // Intentionally left empty.
         }
         
@@ -49,6 +52,23 @@ namespace storm {
             destinations.push_back(destination);
         }
         
+        OrderedAssignments const& Edge::getAssignments() const {
+            return assignments;
+        }
+        
+        void Edge::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) {
+            this->setGuard(this->getGuard().substitute(substitution));
+            if (this->hasRate()) {
+                this->setRate(this->getRate().substitute(substitution));
+            }
+            for (auto& assignment : this->getAssignments()) {
+                assignment.substitute(substitution);
+            }
+            for (auto& destination : this->getDestinations()) {
+                destination.substitute(substitution);
+            }
+        }
+        
         void Edge::finalize(Model const& containingModel) {
             for (auto const& destination : getDestinations()) {
                 for (auto const& assignment : destination.getAssignments()) {
@@ -59,6 +79,36 @@ namespace storm {
             }
         }
         
+        bool Edge::addTransientAssignment(Assignment const& assignment) {
+            STORM_LOG_THROW(assignment.isTransient(), storm::exceptions::InvalidArgumentException, "Must not add non-transient assignment to location.");
+            return assignments.add(assignment);
+        }
+        
+        void Edge::liftTransientDestinationAssignments() {
+            if (!destinations.empty()) {
+                auto const& destination = *destinations.begin();
+                
+                for (auto const& assignment : destination.getTransientAssignments()) {
+                    // Check if we can lift the assignment to the edge.
+                    bool canBeLifted = true;
+                    for (auto const& destination : destinations) {
+                        if (!destination.hasAssignment(assignment)) {
+                            canBeLifted = false;
+                            break;
+                        }
+                    }
+                    
+                    // If so, remove the assignment from all destinations.
+                    if (canBeLifted) {
+                        this->addTransientAssignment(assignment);
+                        for (auto& destination : destinations) {
+                            destination.removeAssignment(assignment);
+                        }
+                    }
+                }
+            }
+        }
+        
         boost::container::flat_set<storm::expressions::Variable> const& Edge::getWrittenGlobalVariables() const {
             return writtenGlobalVariables;
         }
diff --git a/src/storage/jani/Edge.h b/src/storage/jani/Edge.h
index cb872ebbe..6ce6ef127 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,6 +65,11 @@ namespace storm {
              */
             void addDestination(EdgeDestination const& destination);
             
+            /*!
+             * Substitutes all variables in all expressions according to the given substitution.
+             */
+            void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution);
+            
             /*!
              * Finalizes the building of this edge. Subsequent changes to the edge require another call to this
              * method. Note that this method is invoked by a call to <code>finalize</code> to the containing model.
@@ -75,6 +81,25 @@ namespace storm {
              * that prior to calling this, the edge has to be finalized.
              */
             boost::container::flat_set<storm::expressions::Variable> const& getWrittenGlobalVariables() const;
+
+            /*!
+             * Adds a transient assignment to this edge.
+             *
+             * @param assignment The transient assignment to add.
+             * @return True if the assignment was added.
+             */
+            bool addTransientAssignment(Assignment const& assignment);
+            
+            /*!
+             * Retrieves the assignments of this edge.
+             */
+            OrderedAssignments const& getAssignments() const;
+
+            /*!
+             * Finds the transient assignments common to all destinations and lifts them to the edge. Afterwards, these
+             * assignments are no longer contained in the destination.
+             */
+            void liftTransientDestinationAssignments();
             
         private:
             /// The index of the source location.
@@ -93,6 +118,9 @@ namespace storm {
             /// The destinations of this edge.
             std::vector<EdgeDestination> destinations;
             
+            /// The assignments made when taking this edge.
+            OrderedAssignments assignments;
+            
             /// A set of global variables that is written by at least one of the edge's destinations. This set is
             /// initialized by the call to <code>finalize</code>.
             boost::container::flat_set<storm::expressions::Variable> writtenGlobalVariables;
diff --git a/src/storage/jani/EdgeDestination.cpp b/src/storage/jani/EdgeDestination.cpp
index c58a157e9..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,38 +26,29 @@ namespace storm {
             this->probability = probability;
         }
         
-        std::vector<Assignment>& EdgeDestination::getAssignments() {
-            return assignments;
+        storm::jani::detail::ConstAssignments EdgeDestination::getAssignments() const {
+            return assignments.getAllAssignments();
         }
-        
-        std::vector<Assignment> const& EdgeDestination::getAssignments() const {
-            return assignments;
-        }
-        
-        std::vector<Assignment>& EdgeDestination::getNonTransientAssignments() {
-            return nonTransientAssignments;
+
+        storm::jani::detail::ConstAssignments EdgeDestination::getTransientAssignments() const {
+            return assignments.getTransientAssignments();
         }
         
-        std::vector<Assignment> const& EdgeDestination::getNonTransientAssignments() const {
-            return nonTransientAssignments;
+        storm::jani::detail::ConstAssignments EdgeDestination::getNonTransientAssignments() const {
+            return assignments.getNonTransientAssignments();
         }
         
-        std::vector<Assignment>& EdgeDestination::getTransientAssignments() {
-            return transientAssignments;
+        void EdgeDestination::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) {
+            this->setProbability(this->getProbability().substitute(substitution));
+            assignments.substitute(substitution);
         }
         
-        std::vector<Assignment> const& EdgeDestination::getTransientAssignments() const {
-            return transientAssignments;
+        bool EdgeDestination::hasAssignment(Assignment const& assignment) const {
+            return assignments.contains(assignment);
         }
         
-        void EdgeDestination::sortAssignments(std::vector<Assignment>& assignments) {
-            std::sort(assignments.begin(), assignments.end(), [] (storm::jani::Assignment const& assignment1, storm::jani::Assignment const& assignment2) {
-                bool smaller = assignment1.getExpressionVariable().getType().isBooleanType() && !assignment2.getExpressionVariable().getType().isBooleanType();
-                if (!smaller) {
-                    smaller = assignment1.getExpressionVariable() < assignment2.getExpressionVariable();
-                }
-                return smaller;
-            });
+        bool EdgeDestination::removeAssignment(Assignment const& assignment) {
+            return assignments.remove(assignment);
         }
         
     }
diff --git a/src/storage/jani/EdgeDestination.h b/src/storage/jani/EdgeDestination.h
index d22e09ab3..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,55 +39,36 @@ namespace storm {
             /*!
              * Retrieves the assignments to make when choosing this destination.
              */
-            std::vector<Assignment>& getAssignments();
+            storm::jani::detail::ConstAssignments getAssignments() const;
             
             /*!
-             * Retrieves the assignments to make when choosing this destination.
-             */
-            std::vector<Assignment> const& getAssignments() const;
-            
-            /*!
-             * Retrieves the non-transient assignments to make when choosing this destination.
+             * Retrieves the transient assignments to make when choosing this destination.
              */
-            std::vector<Assignment>& getNonTransientAssignments();
+            storm::jani::detail::ConstAssignments getTransientAssignments() const;
 
             /*!
              * Retrieves the non-transient assignments to make when choosing this destination.
              */
-            std::vector<Assignment> const& getNonTransientAssignments() const;
+            storm::jani::detail::ConstAssignments getNonTransientAssignments() const;
 
             /*!
-             * Retrieves the non-transient assignments to make when choosing this destination.
+             * Substitutes all variables in all expressions according to the given substitution.
              */
-            std::vector<Assignment>& getTransientAssignments();
+            void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution);
             
-            /*!
-             * Retrieves the non-transient assignments to make when choosing this destination.
-             */
-            std::vector<Assignment> const& getTransientAssignments() const;
-
-        private:
-            /*!
-             * Sorts the assignments to make all assignments to boolean variables precede all others and order the
-             * assignments within one variable group by the expression variables.
-             */
-            static void sortAssignments(std::vector<Assignment>& assignments);
+            // Convenience methods to access the assignments.
+            bool hasAssignment(Assignment const& assignment) const;
+            bool removeAssignment(Assignment const& assignment);
             
+        private:
             // The index of the destination location.
             uint64_t locationIndex;
 
             // The probability to go to the destination.
             storm::expressions::Expression probability;
             
-            // The assignments to make when choosing this destination.
-            std::vector<Assignment> assignments;
-
-            // The assignments to make when choosing this destination.
-            std::vector<Assignment> nonTransientAssignments;
-
-            // The assignments to make when choosing this destination.
-            std::vector<Assignment> transientAssignments;
-
+            // The (ordered) assignments to make when choosing this destination.
+            OrderedAssignments assignments;
         };
         
     }
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 2f1f1f6b7..05a22d4e5 100644
--- a/src/storage/jani/Location.cpp
+++ b/src/storage/jani/Location.cpp
@@ -1,12 +1,13 @@
 #include "src/storage/jani/Location.h"
-#include "src/storage/jani/Assignment.h"
-#include "src/exceptions/InvalidJaniException.h"
+
 #include "src/utility/macros.h"
+#include "src/exceptions/InvalidJaniException.h"
+#include "src/exceptions/InvalidArgumentException.h"
 
 namespace storm {
     namespace jani {
         
-        Location::Location(std::string const& name, std::vector<Assignment> const& transientAssignments) : name(name), transientAssignments(transientAssignments) {
+        Location::Location(std::string const& name, std::vector<Assignment> const& transientAssignments) : name(name), assignments(transientAssignments) {
             // Intentionally left empty.
         }
         
@@ -14,15 +15,24 @@ namespace storm {
             return name;
         }
         
-        std::vector<Assignment> const& Location::getTransientAssignments() const {
-            return transientAssignments;
+        OrderedAssignments const& Location::getAssignments() const {
+            return assignments;
         }
         
-        void Location::checkValid() const {
-            for(auto const& assignment : transientAssignments) {
-                STORM_LOG_THROW(assignment.isTransientAssignment(), storm::exceptions::InvalidJaniException, "Only transient assignments are allowed in locations.");
+        void Location::addTransientAssignment(storm::jani::Assignment const& assignment) {
+            STORM_LOG_THROW(assignment.isTransient(), storm::exceptions::InvalidArgumentException, "Must not add non-transient assignment to location.");
+            assignments.add(assignment);
+        }
+        
+        void Location::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) {
+            for (auto& assignment : assignments) {
+                assignment.substitute(substitution);
             }
         }
         
+        void Location::checkValid() const {
+            // Intentionally left empty.
+        }
+        
     }
 }
\ No newline at end of file
diff --git a/src/storage/jani/Location.h b/src/storage/jani/Location.h
index 461b68e1f..a2328cb22 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 {
@@ -25,9 +25,19 @@ namespace storm {
             std::string const& getName() const;
             
             /*!
-             * Retrieves the transient assignments of this location.
+             * Retrieves the assignments of this location.
+             */
+            OrderedAssignments const& getAssignments() const;
+            
+            /*!
+             * Adds the given transient assignment to this location.
+             */
+            void addTransientAssignment(storm::jani::Assignment const& assignment);
+  
+            /*!
+             * Substitutes all variables in all expressions according to the given substitution.
              */
-            std::vector<Assignment> const& getTransientAssignments() const;
+            void substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution);
             
             /*!
              * Checks whether the location is valid, that is, whether the assignments are indeed all transient assignments.
@@ -39,7 +49,7 @@ namespace storm {
             std::string name;
             
             /// The transient assignments made in this location.
-            std::vector<Assignment> transientAssignments;
+            OrderedAssignments assignments;
         };
         
     }
diff --git a/src/storage/jani/Model.cpp b/src/storage/jani/Model.cpp
index a9fb3f25e..fc170ac58 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,29 +108,35 @@ namespace storm {
         std::vector<Constant>& Model::getConstants() {
             return constants;
         }
-
+        
         Variable const& Model::addVariable(Variable const& variable) {
             if (variable.isBooleanVariable()) {
-                return addBooleanVariable(variable.asBooleanVariable());
+                return addVariable(variable.asBooleanVariable());
             } else if (variable.isBoundedIntegerVariable()) {
-                return addBoundedIntegerVariable(variable.asBoundedIntegerVariable());
+                return addVariable(variable.asBoundedIntegerVariable());
             } else if (variable.isUnboundedIntegerVariable()) {
-                return addUnboundedIntegerVariable(variable.asUnboundedIntegerVariable());
+                return addVariable(variable.asUnboundedIntegerVariable());
+            } else if (variable.isRealVariable()) {
+                return addVariable(variable.asRealVariable());
             } else {
                 STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Variable has invalid type.");
             }
         }
 
-        BooleanVariable const& Model::addBooleanVariable(BooleanVariable const& variable) {
-            return globalVariables.addBooleanVariable(variable);
+        BooleanVariable const& Model::addVariable(BooleanVariable const& variable) {
+            return globalVariables.addVariable(variable);
         }
         
-        BoundedIntegerVariable const& Model::addBoundedIntegerVariable(BoundedIntegerVariable const& variable) {
-            return globalVariables.addBoundedIntegerVariable(variable);
+        BoundedIntegerVariable const& Model::addVariable(BoundedIntegerVariable const& variable) {
+            return globalVariables.addVariable(variable);
         }
         
-        UnboundedIntegerVariable const& Model::addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable) {
-            return globalVariables.addUnboundedIntegerVariable(variable);
+        UnboundedIntegerVariable const& Model::addVariable(UnboundedIntegerVariable const& variable) {
+            return globalVariables.addVariable(variable);
+        }
+
+        RealVariable const& Model::addVariable(RealVariable const& variable) {
+            return globalVariables.addVariable(variable);
         }
 
         VariableSet& Model::getGlobalVariables() {
@@ -137,6 +147,23 @@ namespace storm {
             return globalVariables;
         }
         
+        bool Model::hasGlobalVariable(std::string const& name) const {
+            return globalVariables.hasVariable(name);
+        }
+        
+        Variable const& Model::getGlobalVariable(std::string const& name) const {
+            return globalVariables.getVariable(name);
+        }
+        
+        bool Model::hasNonGlobalTransientVariable() const {
+            for (auto const& automaton : automata) {
+                if (automaton.hasTransientVariable()) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        
         storm::expressions::ExpressionManager& Model::getExpressionManager() {
             return *expressionManager;
         }
@@ -173,6 +200,12 @@ namespace storm {
             return automata[it->second];
         }
         
+        uint64_t Model::getAutomatonIndex(std::string const& name) const {
+            auto it = automatonToIndex.find(name);
+            STORM_LOG_THROW(it != automatonToIndex.end(), storm::exceptions::InvalidOperationException, "Unable to retrieve unknown automaton '" << name << "'.");
+            return it->second;
+        }
+        
         std::size_t Model::getNumberOfAutomata() const {
             return automata.size();
         }
@@ -304,9 +337,7 @@ namespace storm {
             
             // Substitute constants in all global variables.
             for (auto& variable : result.getGlobalVariables().getBoundedIntegerVariables()) {
-                variable.setInitExpression(variable.getInitExpression().substitute(constantSubstitution));
-                variable.setLowerBound(variable.getLowerBound().substitute(constantSubstitution));
-                variable.setUpperBound(variable.getUpperBound().substitute(constantSubstitution));
+                variable.substitute(constantSubstitution);
             }
             
             // Substitute constants in initial states expression.
@@ -314,26 +345,7 @@ namespace storm {
             
             // Substitute constants in variables of automata and their edges.
             for (auto& automaton : result.getAutomata()) {
-                for (auto& variable : automaton.getVariables().getBoundedIntegerVariables()) {
-                    variable.setInitExpression(variable.getInitExpression().substitute(constantSubstitution));
-                    variable.setLowerBound(variable.getLowerBound().substitute(constantSubstitution));
-                    variable.setUpperBound(variable.getUpperBound().substitute(constantSubstitution));
-                }
-                
-                automaton.setInitialStatesRestriction(automaton.getInitialStatesExpression().substitute(constantSubstitution));
-                
-                for (auto& edge : automaton.getEdges()) {
-                    edge.setGuard(edge.getGuard().substitute(constantSubstitution));
-                    if (edge.hasRate()) {
-                        edge.setRate(edge.getRate().substitute(constantSubstitution));
-                    }
-                    for (auto& destination : edge.getDestinations()) {
-                        destination.setProbability(destination.getProbability().substitute(constantSubstitution));
-                        for (auto& assignment : destination.getAssignments()) {
-                            assignment.setAssignedExpression(assignment.getAssignedExpression().substitute(constantSubstitution));
-                        }
-                    }
-                }
+                automaton.substitute(constantSubstitution);
             }
             
             return result;
diff --git a/src/storage/jani/Model.h b/src/storage/jani/Model.h
index 0379cd5dd..2fc06b18f 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.
              */
@@ -115,17 +120,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.
@@ -136,6 +146,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.
@@ -171,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.
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/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/UnboundedIntegerVariable.h b/src/storage/jani/UnboundedIntegerVariable.h
index d3d3daa01..17f81d334 100644
--- a/src/storage/jani/UnboundedIntegerVariable.h
+++ b/src/storage/jani/UnboundedIntegerVariable.h
@@ -15,7 +15,6 @@ namespace storm {
              * Creates an unbounded integer variable with initial value.
              */
             UnboundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, storm::expressions::Expression const&, bool transient=false);
-
             
             virtual bool isUnboundedIntegerVariable() const override;
         };
diff --git a/src/storage/jani/Variable.cpp b/src/storage/jani/Variable.cpp
index 57a9289a4..9280b7c8e 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 {
@@ -15,7 +16,6 @@ namespace storm {
             // Intentionally left empty.
         }
 
-
         storm::expressions::Variable const& Variable::getExpressionVariable() const {
             return variable;
         }
@@ -36,7 +36,11 @@ namespace storm {
             return false;
         }
 
-        bool Variable::isTransientVariable() const {
+        bool Variable::isRealVariable() const {
+            return false;
+        }
+        
+        bool Variable::isTransient() const {
             return transient;
         }
 
@@ -53,27 +57,41 @@ 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);
+        }
+        
+        void Variable::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) {
+            if (this->hasInitExpression()) {
+                this->setInitExpression(this->getInitExpression().substitute(substitution));
+            }
         }
         
     }
diff --git a/src/storage/jani/Variable.h b/src/storage/jani/Variable.h
index 820014b03..1add2768b 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,8 +59,9 @@ namespace storm {
             virtual bool isBooleanVariable() const;
             virtual bool isBoundedIntegerVariable() const;
             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();
@@ -68,6 +70,13 @@ namespace storm {
             BoundedIntegerVariable const& asBoundedIntegerVariable() const;
             UnboundedIntegerVariable& asUnboundedIntegerVariable();
             UnboundedIntegerVariable const& asUnboundedIntegerVariable() const;
+            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.
diff --git a/src/storage/jani/VariableSet.cpp b/src/storage/jani/VariableSet.cpp
index fe7ef300c..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.
         }
@@ -74,7 +35,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 +53,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 +63,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 +73,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();
         }
@@ -114,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 {
@@ -140,6 +119,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();
         }
@@ -152,24 +140,43 @@ namespace storm {
             return !unboundedIntegerVariables.empty();
         }
         
+        bool VariableSet::containsRealVariables() const {
+            return !realVariables.empty();
+        }
+        
+        bool VariableSet::containsNonTransientRealVariables() const {
+            for (auto const& variable : realVariables) {
+                if (!variable->isTransient()) {
+                    std::cout << "var " << variable->getName() << "is non-transient " << std::endl;
+                    return true;
+                }
+            }
+            return false;
+        }
+        
         bool VariableSet::empty() const {
             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 84e265ed1..78275de0b 100644
--- a/src/storage/jani/VariableSet.h
+++ b/src/storage/jani/VariableSet.h
@@ -3,65 +3,26 @@
 #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"
 #include "src/storage/jani/BoundedIntegerVariable.h"
+#include "src/storage/jani/RealVariable.h"
 
 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.
              */
@@ -97,20 +58,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.
@@ -132,25 +108,30 @@ 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.
              */
-            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.
@@ -167,11 +148,31 @@ namespace storm {
              */
             bool containsUnboundedIntegerVariables() const;
 
+            /*!
+             * 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.
              */
             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;
@@ -185,6 +186,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/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/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/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 d4168196d..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()) {
@@ -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());
@@ -216,12 +213,23 @@ namespace storm {
             }
             
             for (auto const& command : this->getCommands()) {
-                command.containsVariablesOnlyInUpdateProbabilities(undefinedConstantVariables);
+                if (!command.containsVariablesOnlyInUpdateProbabilities(undefinedConstantVariables)) {
+                    return false;
+                }
             }
             
             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 620432580..c3179b407 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.
@@ -226,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 3562747e7..126f53c4e 100644
--- a/src/storage/prism/Program.cpp
+++ b/src/storage/prism/Program.cpp
@@ -20,7 +20,7 @@
 
 #include "src/storage/prism/CompositionVisitor.h"
 #include "src/storage/prism/Compositions.h"
-#include "src/storage/prism/CompositionToJaniVisitor.h"
+#include "src/storage/prism/ToJaniConverter.h"
 
 namespace storm {
     namespace prism {
@@ -148,28 +148,15 @@ namespace storm {
             // Start by creating the necessary mappings from the given ones.
             this->createMappings();
             
-            // Set the initial construct.
+            // Set the initial construct if given.
             if (initialConstruct) {
                 this->initialConstruct = initialConstruct.get();
             } else {
-                // Create a new initial construct if none was given.
-                storm::expressions::Expression newInitialExpression = manager->boolean(true);
-                
-                for (auto const& booleanVariable : this->getGlobalBooleanVariables()) {
-                    newInitialExpression = newInitialExpression && storm::expressions::iff(booleanVariable.getExpression(), booleanVariable.getInitialValueExpression());
-                }
-                for (auto const& integerVariable : this->getGlobalIntegerVariables()) {
-                    newInitialExpression = newInitialExpression && integerVariable.getExpression() == integerVariable.getInitialValueExpression();
+                // Otherwise, we create the missing initial values.
+                this->createMissingInitialValues();
+                for (auto& modules : this->modules) {
+                    modules.createMissingInitialValues();
                 }
-                for (auto const& module : this->getModules()) {
-                    for (auto const& booleanVariable : module.getBooleanVariables()) {
-                        newInitialExpression = newInitialExpression && storm::expressions::iff(booleanVariable.getExpression(), booleanVariable.getInitialValueExpression());
-                    }
-                    for (auto const& integerVariable : module.getIntegerVariables()) {
-                        newInitialExpression = newInitialExpression && integerVariable.getExpression() == integerVariable.getInitialValueExpression();
-                    }
-                }
-                this->initialConstruct = storm::prism::InitialConstruct(newInitialExpression, this->getInitialConstruct().getFilename(), this->getInitialConstruct().getLineNumber());
             }
             
             if (finalModel) {
@@ -230,7 +217,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)) {
@@ -241,13 +228,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;
@@ -266,7 +257,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.
@@ -275,8 +268,10 @@ namespace storm {
             }
             
             // Initial construct.
-            if (this->getInitialConstruct().getInitialStatesExpression().containsVariable(undefinedConstantVariables)) {
-                return false;
+            if (this->hasInitialConstruct()) {
+                if (this->getInitialConstruct().getInitialStatesExpression().containsVariable(undefinedConstantVariables)) {
+                    return false;
+                }
             }
             
             // Labels.
@@ -337,7 +332,6 @@ namespace storm {
             return constantsSubstitution;
         }
         
-        
         std::size_t Program::getNumberOfConstants() const {
             return this->getConstants().size();
         }
@@ -446,10 +440,61 @@ namespace storm {
             return actionToIndexMap;
         }
         
+        bool Program::hasInitialConstruct() const {
+            return static_cast<bool>(initialConstruct);
+        }
+        
         storm::prism::InitialConstruct const& Program::getInitialConstruct() const {
+            return this->initialConstruct.get();
+        }
+        
+        boost::optional<InitialConstruct> const& Program::getOptionalInitialConstruct() const {
             return this->initialConstruct;
         }
         
+        storm::expressions::Expression Program::getInitialStatesExpression() const {
+            // If there is an initial construct, return its expression. If not, we construct the expression from the
+            // initial values of the variables (which have to exist).
+            if (this->hasInitialConstruct()) {
+                return this->getInitialConstruct().getInitialStatesExpression();
+            } else {
+                storm::expressions::Expression result;
+                
+                for (auto const& variable : this->getGlobalBooleanVariables()) {
+                    if (result.isInitialized()) {
+                        result = result && storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression());
+                    } else {
+                        result = storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression());
+                    }
+                }
+                for (auto const& variable : this->getGlobalIntegerVariables()) {
+                    if (result.isInitialized()) {
+                        result = result && variable.getExpressionVariable() == variable.getInitialValueExpression();
+                    } else {
+                        result = variable.getExpressionVariable() == variable.getInitialValueExpression();
+                    }
+                }
+                for (auto const& module : this->getModules()) {
+                    for (auto const& variable : module.getBooleanVariables()) {
+                        if (result.isInitialized()) {
+                            result = result && storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression());
+                        } else {
+                            result = storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression());
+                        }
+                    }
+                    for (auto const& variable : module.getIntegerVariables()) {
+                        if (result.isInitialized()) {
+                            result = result && variable.getExpressionVariable() == variable.getInitialValueExpression();
+                        } else {
+                            result = variable.getExpressionVariable() == variable.getInitialValueExpression();
+                        }
+                    }
+                }
+                
+                return result;
+            }
+        }
+        
         bool Program::specifiesSystemComposition() const {
             return static_cast<bool>(systemCompositionConstruct);
         }
@@ -611,7 +656,7 @@ namespace storm {
                 newModules.push_back(module.restrictCommands(indexSet));
             }
             
-            return Program(this->manager, this->getModelType(), this->getConstants(), this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(), this->getFormulas(), newModules, this->getActionNameToIndexMapping(), this->getRewardModels(), this->getLabels(), this->getInitialConstruct(), this->getOptionalSystemCompositionConstruct());
+            return Program(this->manager, this->getModelType(), this->getConstants(), this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(), this->getFormulas(), newModules, this->getActionNameToIndexMapping(), this->getRewardModels(), this->getLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct());
         }
         
         void Program::createMappings() {
@@ -711,11 +756,11 @@ namespace storm {
                 STORM_LOG_THROW(definedUndefinedConstants.find(constantExpressionPair.first) != definedUndefinedConstants.end(), storm::exceptions::InvalidArgumentException, "Unable to define non-existant constant.");
             }
             
-            return Program(this->manager, this->getModelType(), newConstants, this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(), this->getFormulas(), this->getModules(), this->getActionNameToIndexMapping(), this->getRewardModels(), this->getLabels(), this->getInitialConstruct(), this->getOptionalSystemCompositionConstruct());
+            return Program(this->manager, this->getModelType(), newConstants, this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(), this->getFormulas(), this->getModules(), this->getActionNameToIndexMapping(), this->getRewardModels(), this->getLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct());
         }
         
         Program Program::substituteConstants() const {
-            // 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) {
@@ -763,7 +808,10 @@ namespace storm {
                 newRewardModels.emplace_back(rewardModel.substitute(constantSubstitution));
             }
             
-            storm::prism::InitialConstruct newInitialConstruct = this->getInitialConstruct().substitute(constantSubstitution);
+            boost::optional<storm::prism::InitialConstruct> newInitialConstruct;
+            if (this->hasInitialConstruct()) {
+                newInitialConstruct = this->getInitialConstruct().substitute(constantSubstitution);
+            }
             
             std::vector<Label> newLabels;
             newLabels.reserve(this->getNumberOfLabels());
@@ -807,18 +855,22 @@ 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()) {
+                    STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": illegal to specify initial value if an initial construct is present.");
+                    
+                    // 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.
@@ -853,16 +905,20 @@ namespace storm {
                     STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": upper bound expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
                 }
                 
-                // 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()) {
+                    STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": illegal to specify initial value if an initial construct is present.");
+
+                    // 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.
@@ -875,17 +931,21 @@ 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()) {
+                        STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": illegal to specify initial value if an initial construct is present.");
+
+                        // 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.
@@ -918,17 +978,21 @@ namespace storm {
                         STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": upper bound expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
                     }
                     
-                    // 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()) {
+                        STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException, "Error in " << variable.getFilename() << ", line " << variable.getLineNumber() << ": illegal to specify initial value if an initial construct is present.");
+
+                        // 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.
@@ -1091,9 +1155,11 @@ namespace storm {
             }
             
             // Check the initial states expression.
-            std::set<storm::expressions::Variable> containedIdentifiers = this->getInitialConstruct().getInitialStatesExpression().getVariables();
-            bool isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedIdentifiers.begin(), containedIdentifiers.end());
-            STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << this->getInitialConstruct().getFilename() << ", line " << this->getInitialConstruct().getLineNumber() << ": initial expression refers to unknown identifiers.");
+            if (this->hasInitialConstruct()) {
+                std::set<storm::expressions::Variable> containedIdentifiers = this->getInitialConstruct().getInitialStatesExpression().getVariables();
+                bool isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedIdentifiers.begin(), containedIdentifiers.end());
+                STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Error in " << this->getInitialConstruct().getFilename() << ", line " << this->getInitialConstruct().getLineNumber() << ": initial construct refers to unknown identifiers.");
+            }
             
             // Check the system composition if given.
             if (systemCompositionConstruct) {
@@ -1151,17 +1217,28 @@ namespace storm {
         }
         
         Program Program::simplify() {
+            // Start by substituting the constants, because this will potentially erase some commands or even actions.
+            Program substitutedProgram = this->substituteConstants();
+            
+            // As we possibly delete some commands and some actions might be dropped from modules altogether, we need to
+            // maintain a list of actions that we need to remove in other modules. For example, if module A loses all [a]
+            // commands, we need to delete all [a] commands from all other modules as well. If we do not do that, we will
+            // remove the forced synchronization that was there before.
+            std::set<uint_fast64_t> actionIndicesToDelete;
+            
             std::vector<Module> newModules;
-            std::vector<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()) {
+                
+                // 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.
-                
+                // 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()) {
@@ -1171,54 +1248,84 @@ 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;
-                for(auto const& variable : module.getBooleanVariables()) {
-                    if(booleanVars.count(variable.getExpressionVariable()) == 0) {
-                        newBVars.push_back(variable);
+                std::vector<storm::prism::BooleanVariable> newBooleanVars;
+                for (auto const& variable : module.getBooleanVariables()) {
+                    if (booleanVars.find(variable.getExpressionVariable()) == booleanVars.end()) {
+                        newBooleanVars.push_back(variable);
                     }
                 }
-                std::vector<storm::prism::IntegerVariable> newIVars;
-                for(auto const& variable : module.getIntegerVariables()) {
-                    if(integerVars.count(variable.getExpressionVariable()) == 0) {
-                        newIVars.push_back(variable);
+                std::vector<storm::prism::IntegerVariable> newIntegerVars;
+                for (auto const& variable : module.getIntegerVariables()) {
+                    if (integerVars.find(variable.getExpressionVariable()) == integerVars.end()) {
+                        newIntegerVars.push_back(variable);
                     }
                 }
                 
-                newModules.emplace_back(module.getName(), newBVars, newIVars, newCommands);
+                newModules.emplace_back(module.getName(), newBooleanVars, newIntegerVars, newCommands);
+                
+                // Determine the set of action indices that have been deleted entirely.
+                std::set_difference(module.getSynchronizingActionIndices().begin(), module.getSynchronizingActionIndices().end(), newModules.back().getSynchronizingActionIndices().begin(), newModules.back().getSynchronizingActionIndices().end(), std::inserter(actionIndicesToDelete, actionIndicesToDelete.begin()));
                 
-                for(auto const& entry : booleanVars) {
+                for (auto const& entry : booleanVars) {
                     newConstants.emplace_back(entry.first, entry.second);
                 }
                 
-                for(auto const& entry : integerVars) {
+                for (auto const& entry : integerVars) {
                     newConstants.emplace_back(entry.first, entry.second);
                 }
             }
             
-            return replaceModulesAndConstantsInProgram(newModules, newConstants).substituteConstants();
+            // If we have to delete whole actions, do so now.
+            std::map<std::string, uint_fast64_t> newActionToIndexMap;
+            std::vector<RewardModel> newRewardModels;
+            if (!actionIndicesToDelete.empty()) {
+                boost::container::flat_set<uint_fast64_t> actionsToKeep;
+                std::set_difference(this->getSynchronizingActionIndices().begin(), this->getSynchronizingActionIndices().end(), actionIndicesToDelete.begin(), actionIndicesToDelete.end(), std::inserter(actionsToKeep, actionsToKeep.begin()));
+                
+                // Insert the silent action as this is not contained in the synchronizing action indices.
+                actionsToKeep.insert(0);
+                
+                std::vector<Module> cleanedModules;
+                cleanedModules.reserve(newModules.size());
+                for (auto const& module : newModules) {
+                    cleanedModules.emplace_back(module.restrictCommands(actionsToKeep));
+                }
+                newModules = std::move(cleanedModules);
+                
+                newRewardModels.reserve(substitutedProgram.getNumberOfRewardModels());
+                for (auto const& rewardModel : substitutedProgram.getRewardModels()) {
+                    newRewardModels.emplace_back(rewardModel.restrictActionRelatedRewards(actionsToKeep));
+                }
+                
+                for (auto const& entry : this->getActionNameToIndexMapping()) {
+                    if (actionsToKeep.find(entry.second) != actionsToKeep.end()) {
+                        newActionToIndexMap.emplace(entry.first, entry.second);
+                    }
+                }
+            }
             
-        }
-        
-        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());
+            return Program(this->manager, modelType, newConstants, getGlobalBooleanVariables(), getGlobalIntegerVariables(), getFormulas(), newModules, actionIndicesToDelete.empty() ? getActionNameToIndexMapping() : newActionToIndexMap, actionIndicesToDelete.empty() ? this->getRewardModels() : newRewardModels, getLabels(), getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct());
         }
         
         Program Program::flattenModules(std::unique_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory) const {
@@ -1404,7 +1511,7 @@ namespace storm {
             
             // Finally, we can create the module and the program and return it.
             storm::prism::Module singleModule(newModuleName.str(), allBooleanVariables, allIntegerVariables, newCommands, this->getFilename(), 0);
-            return Program(manager, this->getModelType(), this->getConstants(), std::vector<storm::prism::BooleanVariable>(), std::vector<storm::prism::IntegerVariable>(), this->getFormulas(), {singleModule}, actionToIndexMap, this->getRewardModels(), this->getLabels(), this->getInitialConstruct(), this->getOptionalSystemCompositionConstruct(), this->getFilename(), 0, true);
+            return Program(manager, this->getModelType(), this->getConstants(), std::vector<storm::prism::BooleanVariable>(), std::vector<storm::prism::IntegerVariable>(), this->getFormulas(), {singleModule}, actionToIndexMap, this->getRewardModels(), this->getLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), this->getFilename(), 0, true);
         }
         
         std::unordered_map<uint_fast64_t, std::string> Program::buildCommandIndexToActionNameMap() const {
@@ -1493,173 +1600,30 @@ 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::expressions::ExpressionManager const& Program::getManager() const {
-            return *this->manager;
+        storm::jani::Model Program::toJani(bool allVariablesGlobal) const {
+            ToJaniConverter converter;
+            return converter.convert(*this, allVariablesGlobal);
         }
         
-        storm::expressions::ExpressionManager& Program::getManager() {
+        storm::expressions::ExpressionManager& Program::getManager() const {
             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) {
-                storm::jani::BoundedIntegerVariable const& newVariable = janiModel.addBoundedIntegerVariable(storm::jani::BoundedIntegerVariable(variable.getName(), variable.getExpressionVariable(), variable.getInitialValueExpression(), variable.getLowerBoundExpression(), variable.getUpperBoundExpression()));
-                variableToVariableMap.emplace(variable.getExpressionVariable(), newVariable);
-            }
-            for (auto const& variable : globalBooleanVariables) {
-                storm::jani::BooleanVariable const& newVariable = janiModel.addBooleanVariable(storm::jani::BooleanVariable(variable.getName(), variable.getExpressionVariable(), variable.getInitialValueExpression()));
-                variableToVariableMap.emplace(variable.getExpressionVariable(), newVariable);
-            }
-            
-            // 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);
-                        }
-                    }
+        void Program::createMissingInitialValues() {
+            for (auto& variable : globalBooleanVariables) {
+                if (!variable.hasInitialValue()) {
+                    variable.setInitialValueExpression(manager->boolean(false));
                 }
             }
-            
-            // 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(variable.getName(), variable.getExpressionVariable(), variable.getInitialValueExpression(), 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& newVariable = automaton.addBoundedIntegerVariable(newIntegerVariable);
-                        variableToVariableMap.emplace(variable.getExpressionVariable(), newVariable);
-                    } else if (!accessingModuleIndices.empty()) {
-                        // Otherwise, we need to make it global.
-                        storm::jani::BoundedIntegerVariable const& newVariable = janiModel.addBoundedIntegerVariable(newIntegerVariable);
-                        variableToVariableMap.emplace(variable.getExpressionVariable(), newVariable);
-                    }
-                }
-                for (auto const& variable : module.getBooleanVariables()) {
-                    storm::jani::BooleanVariable newBooleanVariable(variable.getName(), variable.getExpressionVariable(), variable.getInitialValueExpression());
-                    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& newVariable = automaton.addBooleanVariable(newBooleanVariable);
-                        variableToVariableMap.emplace(variable.getExpressionVariable(), newVariable);
-                    } else if (!accessingModuleIndices.empty()) {
-                        // Otherwise, we need to make it global.
-                        storm::jani::BooleanVariable const& newVariable = janiModel.addBooleanVariable(newBooleanVariable);
-                        variableToVariableMap.emplace(variable.getExpressionVariable(), newVariable);
-                    }
+            for (auto& variable : globalIntegerVariables) {
+                if (!variable.hasInitialValue()) {
+                    variable.setInitialValueExpression(variable.getLowerBoundExpression());
                 }
-                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);
             }
-            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;
         }
         
         std::ostream& operator<<(std::ostream& out, Program::ModelType const& type) {
@@ -1706,7 +1670,9 @@ namespace storm {
                 stream << label << std::endl;
             }
             
-            stream << program.getInitialConstruct() << std::endl;
+            if (program.hasInitialConstruct()) {
+                stream << program.getInitialConstruct() << std::endl;
+            }
             
             if (program.specifiesSystemComposition()) {
                 stream << program.getSystemCompositionConstruct();
diff --git a/src/storage/prism/Program.h b/src/storage/prism/Program.h
index 71719c583..bc17072e1 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.
              *
@@ -285,12 +285,31 @@ namespace storm {
              */
             std::map<std::string, uint_fast64_t> const& getActionNameToIndexMapping() const;
             
+            /*!
+             * Retrieves whether the program specifies an initial construct.
+             */
+            bool hasInitialConstruct() const;
+            
             /*!
              * Retrieves the initial construct of the program.
              *
              * @return The initial construct of the program.
              */
             InitialConstruct const& getInitialConstruct() const;
+
+            /*!
+             * Retrieves an optional containing the initial construct of the program if there is any and nothing otherwise.
+             *
+             * @return The initial construct of the program.
+             */
+            boost::optional<InitialConstruct> const& getOptionalInitialConstruct() const;
+
+            /*!
+             * Retrieves an expression characterizing the initial states.
+             *
+             * @return an expression characterizing the initial states.
+             */
+            storm::expressions::Expression getInitialStatesExpression() const;
             
             /*!
              * Retrieves whether the program specifies a system composition in terms of process algebra operations over
@@ -547,27 +566,15 @@ namespace storm {
              *
              * @return The manager responsible for the expressions of this program.
              */
-            storm::expressions::ExpressionManager const& 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();
+            storm::expressions::ExpressionManager& getManager() const;
 
-            /*!
-             *
-             */
             std::unordered_map<uint_fast64_t, std::string> buildCommandIndexToActionNameMap() const;
 
             std::unordered_map<uint_fast64_t, uint_fast64_t> buildCommandIndexToActionIndex() const;
 
             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.
@@ -587,6 +594,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;
             
@@ -633,7 +645,7 @@ namespace storm {
             std::map<std::string, uint_fast64_t> rewardModelToIndexMap;
             
             // The initial construct of the program.
-            InitialConstruct initialConstruct;
+            boost::optional<InitialConstruct> initialConstruct;
             
             // If set, this specifies the way the modules are composed to obtain the full system.
             boost::optional<SystemCompositionConstruct> systemCompositionConstruct;
@@ -661,14 +673,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);
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/storage/prism/ToJaniConverter.cpp b/src/storage/prism/ToJaniConverter.cpp
new file mode 100644
index 000000000..33ad88fef
--- /dev/null
+++ b/src/storage/prism/ToJaniConverter.cpp
@@ -0,0 +1,269 @@
+#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"
+
+#include "src/utility/macros.h"
+#include "src/exceptions/NotImplementedException.h"
+
+namespace storm {
+    namespace prism {
+        
+        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.
+            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 : program.getActions()) {
+                // Ignore the empty action as every JANI program has predefined tau action.
+                if (!action.empty()) {
+                    janiModel.addAction(storm::jani::Action(action));
+                }
+            }
+            
+            // 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);
+                        }
+                    }
+                }
+            }
+            
+            // 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.");
+            }
+            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());
+                    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 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()) {
+                    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) {
+                        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(onlyLocationIndex, manager->integer(1) / rateExpression.get(), assignments));
+                        } else {
+                            destinations.push_back(storm::jani::EdgeDestination(onlyLocationIndex, update.getLikelihoodExpression(), assignments));
+                        }
+                    }
+                    
+                    // 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);
+                }
+                
+                // 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;
+            }
+            
+            // 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..bbabef568
--- /dev/null
+++ b/src/storage/prism/ToJaniConverter.h
@@ -0,0 +1,18 @@
+#pragma once
+
+namespace storm {
+    namespace jani {
+        class Model;
+    }
+    
+    namespace prism {
+        
+        class Program;
+        
+        class ToJaniConverter {
+        public:
+            storm::jani::Model convert(storm::prism::Program const& program, bool allVariablesGlobal = false) const;
+        };
+        
+    }
+}
\ No newline at end of file
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
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) {
diff --git a/src/utility/constants.cpp b/src/utility/constants.cpp
index 71d56cd63..6d954722a 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,16 @@ namespace storm {
         	// FIXME: this should be treated more properly.
         	return storm::RationalNumber(-1);
         }
+        
+        template<>
+        bool isInteger(storm::RationalNumber const& number) {
+            return carl::isInteger(number);
+        }
+
+        template<>
+        bool isInteger(storm::RationalFunction const& func) {
+            return storm::utility::isConstant(func) && storm::utility::isOne(func.denominator());
+        }
 #endif
         
         template<typename ValueType>
@@ -102,9 +128,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 +177,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 +198,31 @@ 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) {
+        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);
         }
+        
+        template<>
+        RationalNumber pow(RationalNumber const& value, uint_fast64_t exponent) {
+            return carl::pow(value, exponent);
+        }
+
 #endif
 
         template<typename IndexType, typename ValueType>
@@ -214,6 +261,7 @@ namespace storm {
         template storm::storage::MatrixEntry<storm::storage::sparse::state_type, double>&& simplify(storm::storage::MatrixEntry<storm::storage::sparse::state_type, double>&& matrixEntry);
 
         template 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 +272,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 +289,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 +328,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);
     }
 }
 
diff --git a/src/utility/storm.cpp b/src/utility/storm.cpp
index 8ea25af28..c567c05cb 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;
     }
@@ -43,8 +43,23 @@ 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>> 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());
+        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 a8aa4a828..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,12 +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.");
-            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>>();
+            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();
@@ -228,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);
         }
     }
 
@@ -382,10 +402,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());
         }
@@ -409,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;
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/parser/PrismParserTest.cpp b/test/functional/parser/PrismParserTest.cpp
index 260c4963a..5cfe7b07e 100644
--- a/test/functional/parser/PrismParserTest.cpp
+++ b/test/functional/parser/PrismParserTest.cpp
@@ -79,10 +79,6 @@ TEST(PrismParser, ComplexTest) {
     module mod3 = mod1 [ i = i1, j = j1, k = k1 ] endmodule
                                                                
     label "mal" = max(a, 10) > 0;
-                                                               
-    init
-        true
-    endinit
     
     rewards "testrewards"
         [a] true : a + 7;
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());
diff --git a/util/osx-package/package.sh b/util/osx-package/package.sh
new file mode 100644
index 000000000..0db5b2b5d
--- /dev/null
+++ b/util/osx-package/package.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+DYLIBBUNDLER_DIR=/Users/chris/work/macdylibbundler/
+
+mkdir -p $1
+mkdir -p $1/bin
+mkdir -p $1/lib
+cp $2 $1/bin
+$DYLIBBUNDLER_DIR/dylibbundler -cd -od -b -p @executable_path/../lib -x $1/bin/storm -d $1/lib
+python packager.py --bin storm --dir $1
diff --git a/util/osx-package/packager.py b/util/osx-package/packager.py
new file mode 100644
index 000000000..60b26a8b8
--- /dev/null
+++ b/util/osx-package/packager.py
@@ -0,0 +1,103 @@
+import argparse
+import subprocess
+import os
+from shutil import copyfile
+
+def get_dependencies(file):
+    # Call otool -L file to obtain the dependencies.
+    proc = subprocess.Popen(["otool", "-L", args.binary], stdout=subprocess.PIPE)
+    result = {}
+    for line_bytes in proc.stdout:
+        line = line_bytes.decode("utf-8").strip()
+        lib = line.split()[0]
+        if (lib.startswith("@")):
+            lib = lib.split("/", 1)[1]
+        (base, file) = os.path.split(lib)
+        print(base + " // " + file)
+    
+    return result
+
+def create_package(args):
+    create_package_dirs(args.dir)
+    copy_binary_to_package_dir(args.bin, args.binary_basename, args.dir)
+    run_dylibbundler(args.bundler_binary, args.dir, args.binary_basename)
+    pass
+
+def parse_arguments():
+    parser = argparse.ArgumentParser(description='Package the storm binary on Mac OS.')
+    parser.add_argument('--bin', dest='bin', help='the binary to package', default='storm')
+    parser.add_argument('--dir', dest='dir', help='the root directory of the package (will be created if it does not exist)', default='.')
+    parser.add_argument('--dylibbundler', dest='bundler_binary', help='the binary of the dylibbundler', default='dylibbundler')
+    args = parser.parse_args()
+    args.binary_dir = os.path.split(args.bin)[0]
+    args.binary_basename = os.path.split(args.bin)[1]
+    return args
+
+def create_package_dirs(root_dir):
+    if not os.path.exists(root_dir):
+        os.makedirs(root_dir)
+    if not os.path.exists(root_dir + "/bin"):
+        os.makedirs(root_dir + "/bin")
+    if not os.path.exists(root_dir + "/lib"):
+        os.makedirs(root_dir + "/bin")
+    pass
+
+def copy_binary_to_package_dir(binary, binary_basename, root_dir):
+    copyfile(binary, root_dir + "/bin/storm")
+    pass
+
+def run_dylibbundler(bundler_binary, root_dir, binary_basename):
+    command = [bundler_binary, "-cd", "-od", "-b", "-p", "@executable_path/../lib", "-x", root_dir + "/bin/" + binary_basename, "-d", root_dir + "/lib"]
+    print("executing " + str(command))
+    #proc = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+    pass
+
+def fix_paths(root_dir, binary_basename):
+    fix_paths_file(root_dir + "/bin/" + binary_basename)
+    for file in os.listdir(root_dir + "/lib"):
+        fix_paths_file(root_dir + "/lib/" + file)
+        pass
+    pass
+
+def fix_paths_file(file):
+    print("fixing paths for " + file)
+    fixable_deps = get_fixable_deps(file)
+    for (path, lib) in fixable_deps:
+        change_fixable_dep(file, path, lib)
+
+native_libs = ["libc++.1.dylib", "libSystem.B.dylib"]
+
+def get_fixable_deps(file):
+    # Call otool -L file to obtain the dependencies.
+    proc = subprocess.Popen(["otool", "-L", file], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+    result = []
+    for line_bytes in proc.stdout:
+        line = line_bytes.decode("utf-8").strip()
+        lib = line.split()[0]
+        if lib.startswith("@rpath/"):
+            result.append(("@rpath", lib.split("/", 1)[1]))
+        elif lib.startswith("/"):
+            path_file = os.path.split(lib)
+            if path_file[1] not in native_libs:
+                result.append((path_file[0], path_file[1]))
+    return result
+
+def change_fixable_dep(file, path, lib):
+    # Call install_name_tool to change the fixable dependencies
+    command = ["install_name_tool", "-change", path + "/" + lib, "@executable_path/../lib/" + lib, file]
+    print("executing " + str(command))
+    proc = subprocess.Popen(command, stdout=subprocess.PIPE)
+    #print ("after call to install_name_tool")
+    #proc = subprocess.Popen(["otool", "-L", file], stdout=subprocess.PIPE)
+    #for line_bytes in proc.stdout:
+    #    line = line_bytes.decode("utf-8").strip()
+    #    print(line)
+    pass
+
+if __name__ == "__main__":
+    args = parse_arguments()
+
+    #create_package(args)
+    fix_paths(args.dir, args.binary_basename)
+
+