diff --git a/src/adapters/DdExpressionAdapter.cpp b/src/adapters/DdExpressionAdapter.cpp
new file mode 100644
index 000000000..955a94970
--- /dev/null
+++ b/src/adapters/DdExpressionAdapter.cpp
@@ -0,0 +1,172 @@
+#include "src/adapters/DdExpressionAdapter.h"
+
+#include "src/utility/macros.h"
+#include "src/exceptions/ExpressionEvaluationException.h"
+
+#include "src/storage/dd/CuddDdManager.h"
+
+namespace storm {
+    namespace adapters {
+        
+        template<storm::dd::DdType Type>
+        SymbolicExpressionAdapter<Type>::SymbolicExpressionAdapter(storm::dd::DdManager<Type> const& ddManager, std::map<storm::expressions::Variable, storm::expressions::Variable> const& variableMapping) : ddManager(ddManager), variableMapping(variableMapping) {
+            // Intentionally left empty.
+        }
+        
+        template<storm::dd::DdType Type>
+        storm::dd::Dd<Type> SymbolicExpressionAdapter<Type>::translateExpression(storm::expressions::Expression const& expression) {
+            return boost::any_cast<storm::dd::Dd<Type>>(expression.accept(*this));
+        }
+        
+        template<storm::dd::DdType Type>
+        boost::any SymbolicExpressionAdapter<Type>::visit(storm::expressions::IfThenElseExpression const& expression) {
+            storm::dd::Dd<Type> elseDd = boost::any_cast<storm::dd::Dd<Type>>(expression.getElseExpression()->accept(*this));
+            storm::dd::Dd<Type> thenDd = boost::any_cast<storm::dd::Dd<Type>>(expression.getThenExpression()->accept(*this));
+            storm::dd::Dd<Type> conditionDd = boost::any_cast<storm::dd::Dd<Type>>(expression.getCondition()->accept(*this));
+            return conditionDd.ite(thenDd, elseDd);
+        }
+        
+        template<storm::dd::DdType Type>
+        boost::any SymbolicExpressionAdapter<Type>::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression) {
+            storm::dd::Dd<Type> leftResult = boost::any_cast<storm::dd::Dd<Type>>(expression.getFirstOperand()->accept(*this));
+            storm::dd::Dd<Type> rightResult = boost::any_cast<storm::dd::Dd<Type>>(expression.getSecondOperand()->accept(*this));
+            
+            storm::dd::Dd<Type> result;
+            switch (expression.getOperatorType()) {
+                case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::And:
+                    result = leftResult && rightResult;
+                    break;
+                case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::Or:
+                    result = leftResult || rightResult;
+                    break;
+                case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::Iff:
+                    result = leftResult.equals(rightResult);
+                    break;
+                case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::Implies:
+                    result = !leftResult || rightResult;
+                    break;
+                case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::Xor:
+                    result = (leftResult && !rightResult) || (!leftResult && rightResult);
+                    break;
+            }
+            
+            return result;
+        }
+        
+        template<storm::dd::DdType Type>
+        boost::any SymbolicExpressionAdapter<Type>::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression) {
+            storm::dd::Dd<Type> leftResult = boost::any_cast<storm::dd::Dd<Type>>(expression.getFirstOperand()->accept(*this));
+            storm::dd::Dd<Type> rightResult = boost::any_cast<storm::dd::Dd<Type>>(expression.getSecondOperand()->accept(*this));
+            
+            storm::dd::Dd<Type> result;
+            switch (expression.getOperatorType()) {
+                case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Plus:
+                    result = leftResult + rightResult;
+                    break;
+                case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Minus:
+                    result = leftResult - rightResult;
+                    break;
+                case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Times:
+                    result = leftResult * rightResult;
+                    break;
+                case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Divide:
+                    result = leftResult / rightResult;
+                    break;
+                case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Max:
+                    result = leftResult.maximum(rightResult);
+                    break;
+                case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Min:
+                    result = leftResult.minimum(rightResult);
+                    break;
+                default:
+                    STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot translate expression containing power operator.");
+            }
+            
+            return result;
+        }
+        
+        template<storm::dd::DdType Type>
+        boost::any SymbolicExpressionAdapter<Type>::visit(storm::expressions::BinaryRelationExpression const& expression) {
+            storm::dd::Dd<Type> leftResult = boost::any_cast<storm::dd::Dd<Type>>(expression.getFirstOperand()->accept(*this));
+            storm::dd::Dd<Type> rightResult = boost::any_cast<storm::dd::Dd<Type>>(expression.getSecondOperand()->accept(*this));
+            
+            storm::dd::Dd<Type> result;
+            switch (expression.getRelationType()) {
+                case storm::expressions::BinaryRelationExpression::RelationType::Equal:
+                    result = leftResult.equals(rightResult);
+                    break;
+                case storm::expressions::BinaryRelationExpression::RelationType::NotEqual:
+                    result = leftResult.notEquals(rightResult);
+                    break;
+                case storm::expressions::BinaryRelationExpression::RelationType::Less:
+                    result = leftResult.less(rightResult);
+                    break;
+                case storm::expressions::BinaryRelationExpression::RelationType::LessOrEqual:
+                    result = leftResult.lessOrEqual(rightResult);
+                    break;
+                case storm::expressions::BinaryRelationExpression::RelationType::Greater:
+                    result = leftResult.greater(rightResult);
+                    break;
+                case storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual:
+                    result = leftResult.greaterOrEqual(rightResult);
+                    break;
+            }
+            
+            return result;
+        }
+        
+        template<storm::dd::DdType Type>
+        boost::any SymbolicExpressionAdapter<Type>::visit(storm::expressions::VariableExpression const& expression) {
+            auto const& variablePair = variableMapping.find(expression.getVariable());
+            STORM_LOG_THROW(variablePair != variableMapping.end(), storm::exceptions::InvalidArgumentException, "Cannot translate the given expression, because it contains th variable '" << expression.getVariableName() << "' for which no DD counterpart is known.");
+            return ddManager.getIdentity(variablePair->second);
+        }
+        
+        template<storm::dd::DdType Type>
+        boost::any SymbolicExpressionAdapter<Type>::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression) {
+            storm::dd::Dd<Type> result = boost::any_cast<storm::dd::Dd<Type>>(expression.getOperand()->accept(*this));
+            
+            switch (expression.getOperatorType()) {
+                case storm::expressions::UnaryBooleanFunctionExpression::OperatorType::Not:
+                    result = !result;
+                    break;
+            }
+            
+            return result;
+        }
+        
+        template<storm::dd::DdType Type>
+        boost::any SymbolicExpressionAdapter<Type>::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression) {
+            storm::dd::Dd<Type> result = boost::any_cast<storm::dd::Dd<Type>>(expression.getOperand()->accept(*this));
+            
+            switch (expression.getOperatorType()) {
+                case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Minus:
+                    result = -result;
+                    break;
+                default:
+                    STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot translate expression containing floor/ceil operator.");
+            }
+            
+            return result;
+        }
+        
+        template<storm::dd::DdType Type>
+        boost::any SymbolicExpressionAdapter<Type>::visit(storm::expressions::BooleanLiteralExpression const& expression) {
+            return ddManager.getConstant(expression.getValue());
+        }
+        
+        template<storm::dd::DdType Type>
+        boost::any SymbolicExpressionAdapter<Type>::visit(storm::expressions::IntegerLiteralExpression const& expression) {
+            return ddManager.getConstant(expression.getValue());
+        }
+        
+        template<storm::dd::DdType Type>
+        boost::any SymbolicExpressionAdapter<Type>::visit(storm::expressions::DoubleLiteralExpression const& expression) {
+            return ddManager.getConstant(expression.getValue());
+        }
+        
+        // Explicitly instantiate the symbolic expression adapter
+        template class SymbolicExpressionAdapter<storm::dd::DdType::CUDD>;
+        
+    } // namespace adapters
+} // namespace storm
diff --git a/src/adapters/DdExpressionAdapter.h b/src/adapters/DdExpressionAdapter.h
new file mode 100644
index 000000000..a41d0993c
--- /dev/null
+++ b/src/adapters/DdExpressionAdapter.h
@@ -0,0 +1,43 @@
+#ifndef STORM_ADAPTERS_DDEXPRESSIONADAPTER_H_
+#define STORM_ADAPTERS_DDEXPRESSIONADAPTER_H_
+
+#include "src/storage/expressions/Variable.h"
+#include "src/storage/expressions/Expressions.h"
+#include "storage/expressions/ExpressionVisitor.h"
+
+#include "src/storage/dd/Dd.h"
+#include "src/storage/dd/DdManager.h"
+
+namespace storm {
+    namespace adapters {
+        
+        template<storm::dd::DdType Type>
+        class SymbolicExpressionAdapter : public storm::expressions::ExpressionVisitor {
+        public:
+            SymbolicExpressionAdapter(storm::dd::DdManager<Type> const& ddManager, std::map<storm::expressions::Variable, storm::expressions::Variable> const& variableMapping);
+            
+            storm::dd::Dd<Type> translateExpression(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;
+
+        private:
+            // The manager responsible for the DDs built by this adapter.
+            storm::dd::DdManager<Type> const& ddManager;
+            
+            // This member maps the variables used in the expressions to the variables used by the DD manager.
+            std::map<storm::expressions::Variable, storm::expressions::Variable> const& variableMapping;
+        };
+        
+    } // namespace adapters
+} // namespace storm
+
+#endif /* STORM_ADAPTERS_DDEXPRESSIONADAPTER_H_ */
diff --git a/src/adapters/StormAdapter.h b/src/adapters/StormAdapter.h
deleted file mode 100644
index 9fe348c00..000000000
--- a/src/adapters/StormAdapter.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * StormAdapter.h
- *
- *  Created on: 02.03.2013
- *      Author: Philipp Berger
- */
-
-#ifndef STORM_ADAPTERS_STORMADAPTER_H_
-#define STORM_ADAPTERS_STORMADAPTER_H_
-
-#include "gmm/gmm_matrix.h"
-#include "Eigen/Sparse"
-#include "src/storage/SparseMatrix.h"
-
-#include "log4cplus/logger.h"
-#include "log4cplus/loggingmacros.h"
-
-extern log4cplus::Logger logger;
-
-namespace storm {
-
-namespace adapters {
-
-class StormAdapter {
-public:
-	/*!
-	 * Converts a sparse matrix into a sparse matrix in the storm format.
-	 * @return A pointer to a row-major sparse matrix in storm format.
-	 */
-	template<class T>
-	static storm::storage::SparseMatrix<T>* toStormSparseMatrix(gmm::csr_matrix<T> const& matrix) {
-		uint_fast64_t realNonZeros = gmm::nnz(matrix);
-		LOG4CPLUS_DEBUG(logger, "Converting matrix with " << realNonZeros << " non-zeros from gmm++ format into Storm.");
-
-		// Prepare the resulting matrix.
-		storm::storage::SparseMatrix<T>* result = new storm::storage::SparseMatrix<T>(matrix.ncols(), matrix.jc, matrix.ir, matrix.pr);
-
-		LOG4CPLUS_DEBUG(logger, "Done converting matrix to storm format.");
-
-		return result;
-	}
-
-	/*!
-	 * Helper function to determine whether the given Eigen matrix is in RowMajor
-	 * format. Always returns true, but is overloaded, so the compiler will
-	 * only call it in case the Eigen matrix is in RowMajor format.
-	 * @return True.
-	 */
-	template<typename _Scalar, typename _Index>
-	static bool isEigenRowMajor(Eigen::SparseMatrix<_Scalar, Eigen::RowMajor, _Index>) {
-		return true;
-	}
-
-	/*!
-	 * Helper function to determine whether the given Eigen matrix is in RowMajor
-	 * format. Always returns false, but is overloaded, so the compiler will
-	 * only call it in case the Eigen matrix is in ColMajor format.
-	 * @return False.
-	 */
-	template<typename _Scalar, typename _Index>
-	static bool isEigenRowMajor(
-			Eigen::SparseMatrix<_Scalar, Eigen::ColMajor, _Index>) {
-		return false;
-	}
-
-	/*!
-	 * Converts a sparse matrix in the eigen format to Storm Sparse Matrix format.
-	 * @return A pointer to a row-major sparse matrix in our format.
-	 */
-	template<class T, int _Options, typename _Index>
-	static storm::storage::SparseMatrix<T>* toStormSparseMatrix(Eigen::SparseMatrix<T, _Options, _Index> const& matrix) {
-		uint_fast64_t realNonZeros = matrix.nonZeros();
-		LOG4CPLUS_DEBUG(logger, "Converting matrix with " << realNonZeros << " non-zeros from Eigen3 format into Storm.");
-
-		// Throw an error in case the matrix is not in compressed format.
-		if (!matrix.isCompressed()) {
-			LOG4CPLUS_ERROR(logger, "Trying to convert from an Eigen matrix that is not in compressed form.");
-			return nullptr;
-		}
-
-		/*
-		 * Try to prepare the internal storage and throw an error in case of
-		 * failure.
-		 */
-
-		// Get necessary pointers to the contents of the Eigen matrix.
-		const T* valuePtr = matrix.valuePtr();
-		const _Index* indexPtr = matrix.innerIndexPtr();
-		const _Index* outerPtr = matrix.outerIndexPtr();
-
-		const uint_fast64_t outerSize = matrix.outerSize();
-
-		storm::storage::SparseMatrix<T>* result = nullptr;
-
-		// If the given matrix is in RowMajor format, copying can simply
-		// be done by adding all values in order.
-		// Direct copying is, however, prevented because we have to
-		// separate the diagonal entries from others.
-		if (isEigenRowMajor(matrix)) {
-			/* Because of the RowMajor format outerSize evaluates to the
-			 * number of rows.
-			 * Prepare the resulting matrix.
-			 */
-			result = new storm::storage::SparseMatrix<T>(matrix.outerSize(), matrix.innerSize());
-		
-			// Set internal NonZero Counter
-			result->nonZeroEntryCount = realNonZeros;
-			result->setState(result->Initialized);
-
-			if (!result->prepareInternalStorage(false)) {
-				LOG4CPLUS_ERROR(logger, "Unable to allocate internal storage while converting Eigen3 RM Matrix to Storm.");
-				delete result;
-				return nullptr;
-			} else {
-			
-				// Copy Row Indications
-				std::copy(outerPtr, outerPtr + outerSize, std::back_inserter(result->rowIndications));
-				// Copy Columns Indications
-				std::copy(indexPtr, indexPtr + realNonZeros, std::back_inserter(result->columnIndications));
-				// And do the same thing with the actual values.
-				std::copy(valuePtr, valuePtr + realNonZeros, std::back_inserter(result->valueStorage));
-
-				// This is our Sentinel Element.
-				result->rowIndications.push_back(realNonZeros);
-
-				result->currentSize = realNonZeros;
-				result->lastRow = outerSize - 1;
-			}
-		} else {
-			/* Because of the RowMajor format outerSize evaluates to the
-			 * number of columns.
-			 * Prepare the resulting matrix.
-			 */
-			const uint_fast64_t colCount = matrix.outerSize();
-			result = new storm::storage::SparseMatrix<T>(matrix.innerSize(), colCount);
-		
-			// Set internal NonZero Counter
-			result->nonZeroEntryCount = realNonZeros;
-			result->setState(result->Initialized);
-			if (!result->prepareInternalStorage()) {
-				LOG4CPLUS_ERROR(logger, "Unable to allocate internal storage while converting Eigen3 CM Matrix to Storm.");
-				delete result;
-				return nullptr;
-			} else {
-				// Set internal NonZero Counter
-				result->nonZeroEntryCount = realNonZeros;
-				result->setState(result->Initialized);
-
-				// Create an array to remember which elements have to still
-				// be searched in each column and initialize it with the starting
-				// index for every column.
-				_Index* positions = new _Index[colCount]();
-				for (_Index i = 0; i < colCount; ++i) {
-					positions[i] = outerPtr[i];
-				}
-
-				// Now copy the elements. As the matrix is in ColMajor format,
-				// we need to iterate over the columns to find the next non-zero
-				// entry.
-				uint_fast64_t i = 0;
-				int currentRow = 0;
-				int currentColumn = 0;
-				while (i < realNonZeros) {
-					// If the current element belongs the the current column,
-					// add it in case it is also in the current row.
-					if ((positions[currentColumn] < outerPtr[currentColumn + 1])
-							&& (indexPtr[positions[currentColumn]] == currentRow)) {
-						result->addNextValue(currentRow, currentColumn,	valuePtr[positions[currentColumn]]);
-						// Remember that we found one more non-zero element.
-						++i;
-						// Mark this position as "used".
-						++positions[currentColumn];
-					}
-
-					// Now we can advance to the next column and also row,
-					// in case we just iterated through the last column.
-					++currentColumn;
-					if (currentColumn == colCount) {
-						currentColumn = 0;
-						++currentRow;
-					}
-				}
-				delete[] positions;
-			}
-		}
-		result->setState(result->Initialized);
-		result->finalize();
-
-		LOG4CPLUS_DEBUG(logger, "Done converting matrix to storm format.");
-
-		return result;
-	}
-};
-
-} //namespace adapters
-
-} //namespace storm
-
-#endif /* STORM_ADAPTERS_STORMADAPTER_H_ */
diff --git a/src/adapters/SymbolicModelAdapter.h b/src/adapters/SymbolicModelAdapter.h
deleted file mode 100644
index 29ab6c613..000000000
--- a/src/adapters/SymbolicModelAdapter.h
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * SymbolicModelAdapter.h
- *
- *  Created on: 25.01.2013
- *      Author: Christian Dehnert
- */
-
-#ifndef STORM_ADAPTERS_SYMBOLICMODELADAPTER_H_
-#define STORM_ADAPTERS_SYMBOLICMODELADAPTER_H_
-
-#include "src/exceptions/WrongFormatException.h"
-
-#include "src/utility/CuddUtility.h"
-#include "SymbolicExpressionAdapter.h"
-
-#include "cuddObj.hh"
-#include <iostream>
-#include <unordered_map>
-#include <cmath>
-
-namespace storm {
-
-namespace adapters {
-
-class SymbolicModelAdapter {
-public:
-
-	SymbolicModelAdapter(storm::ir::Program const& program) : program(program), cuddUtility(storm::utility::cuddUtilityInstance()), allDecisionDiagramVariables(),
-		allRowDecisionDiagramVariables(), allColumnDecisionDiagramVariables(), booleanRowDecisionDiagramVariables(),
-		integerRowDecisionDiagramVariables(), booleanColumnDecisionDiagramVariables(), integerColumnDecisionDiagramVariables(),
-		variableToRowDecisionDiagramVariableMap(), variableToColumnDecisionDiagramVariableMap(),
-		variableToIdentityDecisionDiagramMap(),
-		rowExpressionAdapter(program, variableToRowDecisionDiagramVariableMap), columnExpressionAdapter(program, variableToColumnDecisionDiagramVariableMap) {
-
-	}
-
-	void toMTBDD() {
-		LOG4CPLUS_INFO(logger, "Creating MTBDD representation for probabilistic program.");
-		createDecisionDiagramVariables(program);
-		createIdentityDecisionDiagrams(program);
-
-		ADD* systemAdd = cuddUtility->getZero();
-		for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
-			storm::ir::Module const& module = program.getModule(i);
-
-			ADD* moduleAdd = cuddUtility->getZero();
-			for (uint_fast64_t j = 0; j < module.getNumberOfCommands(); ++j) {
-				storm::ir::Command const& command = module.getCommand(j);
-
-				ADD* commandAdd = cuddUtility->getZero();
-
-				ADD* guard = rowExpressionAdapter.translateExpression(command.getGuard());
-				if (*guard != *cuddUtility->getZero()) {
-					for (uint_fast64_t i = 0; i < command.getNumberOfUpdates(); ++i) {
-						ADD* updateAdd = cuddUtility->getOne();
-
-						storm::ir::Update const& update = command.getUpdate(i);
-
-						std::map<std::string, storm::ir::Assignment> booleanAssignments = update.getBooleanAssignments();
-						for (auto assignmentPair : booleanAssignments) {
-							ADD* updateExpr = rowExpressionAdapter.translateExpression(assignmentPair.second.getExpression());
-
-							ADD* temporary = cuddUtility->getZero();
-							cuddUtility->setValueAtIndex(temporary, 0, variableToColumnDecisionDiagramVariableMap[assignmentPair.first], 0);
-							cuddUtility->setValueAtIndex(temporary, 1, variableToColumnDecisionDiagramVariableMap[assignmentPair.first], 1);
-
-							ADD* result = new ADD(*updateExpr * *guard);
-							result = new ADD(result->Equals(*temporary));
-
-							*updateAdd = *updateAdd * *result;
-						}
-
-						std::map<std::string, storm::ir::Assignment> integerAssignments = update.getIntegerAssignments();
-						for (auto assignmentPair : integerAssignments) {
-							ADD* updateExpr = rowExpressionAdapter.translateExpression(assignmentPair.second.getExpression());
-
-							ADD* temporary = cuddUtility->getZero();
-
-							uint_fast64_t variableIndex = module.getIntegerVariableIndex(assignmentPair.first);
-							storm::ir::IntegerVariable integerVariable = module.getIntegerVariable(variableIndex);
-							int_fast64_t low = integerVariable.getLowerBound()->getValueAsInt(nullptr);
-							int_fast64_t high = integerVariable.getUpperBound()->getValueAsInt(nullptr);
-
-							for (int_fast64_t i = low; i <= high; ++i) {
-								cuddUtility->setValueAtIndex(temporary, i - low, variableToColumnDecisionDiagramVariableMap[assignmentPair.first], static_cast<double>(i));
-							}
-
-							ADD* result = new ADD(*updateExpr * *guard);
-							result = new ADD(result->Equals(*temporary));
-							*result *= *guard;
-
-							*updateAdd = *updateAdd * *result;
-						}
-						for (uint_fast64_t i = 0; i < module.getNumberOfBooleanVariables(); ++i) {
-							storm::ir::BooleanVariable const& booleanVariable = module.getBooleanVariable(i);
-
-							if (update.getBooleanAssignments().find(booleanVariable.getName()) == update.getBooleanAssignments().end()) {
-								*updateAdd = *updateAdd * *variableToIdentityDecisionDiagramMap[booleanVariable.getName()];
-							}
-						}
-						for (uint_fast64_t i = 0; i < module.getNumberOfIntegerVariables(); ++i) {
-							storm::ir::IntegerVariable const& integerVariable = module.getIntegerVariable(i);
-
-							if (update.getIntegerAssignments().find(integerVariable.getName()) == update.getIntegerAssignments().end()) {
-								*updateAdd = *updateAdd * *variableToIdentityDecisionDiagramMap[integerVariable.getName()];
-							}
-						}
-
-						*commandAdd += *updateAdd * *cuddUtility->getConstant(update.getLikelihoodExpression()->getValueAsDouble(nullptr));
-					}
-					*moduleAdd += *commandAdd;
-				} else {
-					LOG4CPLUS_WARN(logger, "Guard " << command.getGuard()->toString() << " is unsatisfiable.");
-				}
-			}
-			*systemAdd += *moduleAdd;
-		}
-
-		performReachability(program, systemAdd);
-
-		LOG4CPLUS_INFO(logger, "Done creating MTBDD representation for probabilistic program.");
-	}
-
-private:
-    storm::ir::Program const& program;
-	storm::utility::CuddUtility* cuddUtility;
-
-	std::vector<ADD*> allDecisionDiagramVariables;
-	std::vector<ADD*> allRowDecisionDiagramVariables;
-	std::vector<ADD*> allColumnDecisionDiagramVariables;
-	std::vector<ADD*> booleanRowDecisionDiagramVariables;
-	std::vector<ADD*> integerRowDecisionDiagramVariables;
-	std::vector<ADD*> booleanColumnDecisionDiagramVariables;
-	std::vector<ADD*> integerColumnDecisionDiagramVariables;
-	std::unordered_map<std::string, std::vector<ADD*>> variableToRowDecisionDiagramVariableMap;
-	std::unordered_map<std::string, std::vector<ADD*>> variableToColumnDecisionDiagramVariableMap;
-
-	std::unordered_map<std::string, ADD*> variableToIdentityDecisionDiagramMap;
-
-	SymbolicExpressionAdapter rowExpressionAdapter;
-	SymbolicExpressionAdapter columnExpressionAdapter;
-
-	// As log2 is not part of C90, only of C99 which no Compiler fully supports, this feature is unavailable on MSVC
-	inline double log2(uint_fast64_t number) {
-#		include "src/utility/OsDetection.h"
-#		ifndef WINDOWS
-			return std::log2(number);
-#		else
-			return std::log(number) / std::log(2);
-#		endif
-	}
-
-	ADD* getInitialStateDecisionDiagram(storm::ir::Program const& program) {
-		ADD* initialStates = cuddUtility->getOne();
-		for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
-			storm::ir::Module const& module = program.getModule(i);
-
-			for (uint_fast64_t j = 0; j < module.getNumberOfBooleanVariables(); ++j) {
-				storm::ir::BooleanVariable const& booleanVariable = module.getBooleanVariable(j);
-				*initialStates *= *cuddUtility->getConstantEncoding(1, variableToRowDecisionDiagramVariableMap[booleanVariable.getName()]);
-			}
-			for (uint_fast64_t j = 0; j < module.getNumberOfIntegerVariables(); ++j) {
-				storm::ir::IntegerVariable const& integerVariable = module.getIntegerVariable(j);
-				int_fast64_t initialValue = integerVariable.getInitialValue()->getValueAsInt(nullptr);
-				int_fast64_t low = integerVariable.getLowerBound()->getValueAsInt(nullptr);
-				*initialStates *= *cuddUtility->getConstantEncoding(initialValue - low, variableToRowDecisionDiagramVariableMap[integerVariable.getName()]);
-			}
-		}
-
-		cuddUtility->dumpDotToFile(initialStates, "initstates.add");
-		return initialStates;
-	}
-
-	void performReachability(storm::ir::Program const& program, ADD* systemAdd) {
-		ADD* systemAdd01 = new ADD(systemAdd->GreaterThan(*cuddUtility->getZero()));
-		cuddUtility->dumpDotToFile(systemAdd01, "system01.add");
-
-		cuddUtility->dumpDotToFile(systemAdd, "reachtransold.add");
-		ADD* reachableStates = getInitialStateDecisionDiagram(program);
-		cuddUtility->dumpDotToFile(reachableStates, "init.add");
-		ADD* newReachableStates = new ADD(*reachableStates);
-
-		ADD* rowCube = cuddUtility->getOne();
-		for (auto variablePtr : allRowDecisionDiagramVariables) {
-			*rowCube *= *variablePtr;
-		}
-
-		bool changed;
-		do {
-			changed = false;
-			*newReachableStates = *reachableStates * *systemAdd01;
-			newReachableStates = new ADD(newReachableStates->ExistAbstract(*rowCube));
-
-			cuddUtility->dumpDotToFile(newReachableStates, "reach1.add");
-
-			newReachableStates = cuddUtility->permuteVariables(newReachableStates, allColumnDecisionDiagramVariables, allRowDecisionDiagramVariables, static_cast<int>(allDecisionDiagramVariables.size()));
-
-			*newReachableStates += *reachableStates;
-			newReachableStates = new ADD(newReachableStates->GreaterThan(*cuddUtility->getZero()));
-
-			if (*newReachableStates != *reachableStates) changed = true;
-			*reachableStates = *newReachableStates;
-		} while (changed);
-
-		*systemAdd *= *reachableStates;
-		std::cout << "got " << systemAdd->nodeCount() << " nodes" << std::endl;
-		std::cout << "and " << systemAdd->CountMinterm(static_cast<int>(allRowDecisionDiagramVariables.size() + allColumnDecisionDiagramVariables.size())) << std::endl;
-	}
-
-	void createIdentityDecisionDiagrams(storm::ir::Program const& program) {
-		for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
-			storm::ir::Module const& module = program.getModule(i);
-
-			for (uint_fast64_t j = 0; j < module.getNumberOfBooleanVariables(); ++j) {
-				storm::ir::BooleanVariable const& booleanVariable = module.getBooleanVariable(j);
-				ADD* identity = cuddUtility->getZero();
-				cuddUtility->setValueAtIndices(identity, 0, 0,
-						variableToRowDecisionDiagramVariableMap[booleanVariable.getName()],
-						variableToColumnDecisionDiagramVariableMap[booleanVariable.getName()], 1);
-				cuddUtility->setValueAtIndices(identity, 1, 1,
-						variableToRowDecisionDiagramVariableMap[booleanVariable.getName()],
-						variableToColumnDecisionDiagramVariableMap[booleanVariable.getName()], 1);
-				variableToIdentityDecisionDiagramMap[booleanVariable.getName()] = identity;
-			}
-
-			for (uint_fast64_t j = 0; j < module.getNumberOfIntegerVariables(); ++j) {
-				storm::ir::IntegerVariable const& integerVariable = module.getIntegerVariable(j);
-
-				ADD* identity = cuddUtility->getZero();
-
-				int_fast64_t low = integerVariable.getLowerBound()->getValueAsInt(nullptr);
-				int_fast64_t high = integerVariable.getUpperBound()->getValueAsInt(nullptr);
-
-				for (int_fast64_t i = low; i <= high; ++i) {
-					cuddUtility->setValueAtIndices(identity, i - low, i - low,
-							variableToRowDecisionDiagramVariableMap[integerVariable.getName()],
-							variableToColumnDecisionDiagramVariableMap[integerVariable.getName()], 1);
-				}
-				variableToIdentityDecisionDiagramMap[integerVariable.getName()] = identity;
-			}
-		}
-	}
-
-	void createDecisionDiagramVariables(storm::ir::Program const& program) {
-		for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
-			storm::ir::Module const& module = program.getModule(i);
-
-			for (uint_fast64_t j = 0; j < module.getNumberOfBooleanVariables(); ++j) {
-				storm::ir::BooleanVariable const& booleanVariable = module.getBooleanVariable(j);
-
-				ADD* newRowDecisionDiagramVariable = cuddUtility->getNewAddVariable();
-				variableToRowDecisionDiagramVariableMap[booleanVariable.getName()].push_back(newRowDecisionDiagramVariable);
-				booleanRowDecisionDiagramVariables.push_back(newRowDecisionDiagramVariable);
-				allRowDecisionDiagramVariables.push_back(newRowDecisionDiagramVariable);
-				allDecisionDiagramVariables.push_back(newRowDecisionDiagramVariable);
-
-				ADD* newColumnDecisionDiagramVariable = cuddUtility->getNewAddVariable();
-				variableToColumnDecisionDiagramVariableMap[booleanVariable.getName()].push_back(newColumnDecisionDiagramVariable);
-				booleanColumnDecisionDiagramVariables.push_back(newColumnDecisionDiagramVariable);
-				allColumnDecisionDiagramVariables.push_back(newColumnDecisionDiagramVariable);
-				allDecisionDiagramVariables.push_back(newColumnDecisionDiagramVariable);
-			}
-
-			for (uint_fast64_t j = 0; j < module.getNumberOfIntegerVariables(); ++j) {
-				storm::ir::IntegerVariable const& integerVariable = module.getIntegerVariable(j);
-				uint_fast64_t integerRange = integerVariable.getUpperBound()->getValueAsInt(nullptr) - integerVariable.getLowerBound()->getValueAsInt(nullptr);
-				if (integerRange <= 0) {
-					throw storm::exceptions::WrongFormatException() << "Range of variable "
-							<< integerVariable.getName() << " is empty or negativ.";
-				}
-				uint_fast64_t numberOfDecisionDiagramVariables = static_cast<uint_fast64_t>(std::ceil(log2(integerRange)));
-
-				std::vector<ADD*> allRowDecisionDiagramVariablesForVariable;
-				std::vector<ADD*> allColumnDecisionDiagramVariablesForVariable;
-				for (uint_fast64_t k = 0; k < numberOfDecisionDiagramVariables; ++k) {
-					ADD* newRowDecisionDiagramVariable = cuddUtility->getNewAddVariable();
-					allRowDecisionDiagramVariablesForVariable.push_back(newRowDecisionDiagramVariable);
-					integerRowDecisionDiagramVariables.push_back(newRowDecisionDiagramVariable);
-					allRowDecisionDiagramVariables.push_back(newRowDecisionDiagramVariable);
-					allDecisionDiagramVariables.push_back(newRowDecisionDiagramVariable);
-
-					ADD* newColumnDecisionDiagramVariable = cuddUtility->getNewAddVariable();
-					allColumnDecisionDiagramVariablesForVariable.push_back(newColumnDecisionDiagramVariable);
-					integerColumnDecisionDiagramVariables.push_back(newColumnDecisionDiagramVariable);
-					allColumnDecisionDiagramVariables.push_back(newColumnDecisionDiagramVariable);
-					allDecisionDiagramVariables.push_back(newColumnDecisionDiagramVariable);
-				}
-				variableToRowDecisionDiagramVariableMap[integerVariable.getName()] = allRowDecisionDiagramVariablesForVariable;
-				variableToColumnDecisionDiagramVariableMap[integerVariable.getName()] = allColumnDecisionDiagramVariablesForVariable;
-			}
-		}
-	}
-};
-
-} // namespace adapters
-
-} // namespace storm
-
-#endif /* STORM_ADAPTERS_SYMBOLICMODELADAPTER_H_ */
diff --git a/src/builder/DdPrismModelBuilder.cpp b/src/builder/DdPrismModelBuilder.cpp
new file mode 100644
index 000000000..3214a1e42
--- /dev/null
+++ b/src/builder/DdPrismModelBuilder.cpp
@@ -0,0 +1,1442 @@
+#include "src/builder/DdPrismModelBuilder.h"
+#include "src/adapters/DdExpressionAdapter.h"
+
+#include "src/storage/dd/CuddDd.h"
+#include "src/storage/dd/CuddDdManager.h"
+#include "src/settings/SettingsManager.h"
+
+#include "src/utility/prism.h"
+#include "src/utility/math.h"
+#include "src/utility/macros.h"
+
+namespace storm {
+    namespace adapters {
+        
+        template <storm::dd::DdType Type>
+        DdPrismModelBuilder<Type>::Options::Options() : buildRewards(false), rewardModelName(), constantDefinitions() {
+            // Intentionally left empty.
+        }
+        
+        template <storm::dd::DdType Type>
+        DdPrismModelBuilder<Type>::Options::Options(storm::logic::Formula const& formula) : buildRewards(formula.containsRewardOperator()), rewardModelName(), constantDefinitions(), labelsToBuild(std::set<std::string>()), expressionLabels(std::vector<storm::expressions::Expression>()) {
+            // Extract all the labels used in the formula.
+            std::vector<std::shared_ptr<storm::logic::AtomicLabelFormula const>> atomicLabelFormulas = formula.getAtomicLabelFormulas();
+            for (auto const& formula : atomicLabelFormulas) {
+                labelsToBuild.get().insert(formula.get()->getLabel());
+            }
+            
+            // Extract all the expressions used in the formula.
+            std::vector<std::shared_ptr<storm::logic::AtomicExpressionFormula const>> atomicExpressionFormulas = formula.getAtomicExpressionFormulas();
+            for (auto const& formula : atomicExpressionFormulas) {
+                expressionLabels.get().push_back(formula.get()->getExpression());
+            }
+        }
+        
+        template <storm::dd::DdType Type>
+        void DdPrismModelBuilder<Type>::Options::addConstantDefinitionsFromString(storm::prism::Program const& program, std::string const& constantDefinitionString) {
+            std::map<storm::expressions::Variable, storm::expressions::Expression> newConstantDefinitions = storm::utility::prism::parseConstantDefinitionString(program, constantDefinitionString);
+            
+            // If there is at least one constant that is defined, and the constant definition map does not yet exist,
+            // we need to create it.
+            if (!constantDefinitions && !newConstantDefinitions.empty()) {
+                constantDefinitions = std::map<storm::expressions::Variable, storm::expressions::Expression>();
+            }
+            
+            // Now insert all the entries that need to be defined.
+            for (auto const& entry : newConstantDefinitions) {
+                constantDefinitions.get().insert(entry);
+            }
+        }
+        
+        template <storm::dd::DdType Type>
+        void DdPrismModelBuilder<Type>::translateProgram(storm::prism::Program const& program, Options const& options) {
+            // There might be nondeterministic variables. In that case the program must be prepared before translating.
+            storm::prism::Program preparedProgram;
+            if (options.constantDefinitions) {
+                preparedProgram = program.defineUndefinedConstants(options.constantDefinitions.get());
+            } else {
+                preparedProgram = program;
+            }
+            
+            preparedProgram = preparedProgram.substituteConstants();
+            
+            // 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);
+
+            
+//            LOG4CPLUS_INFO(logger, "Creating MTBDD representation for probabilistic program.");
+//            
+//            // There might be nondeterministic variables. In that case the program must be prepared before translating.
+//            storm::prism::Program preparedProgram = program.defineUndefinedConstants(std::map<std::string, storm::expressions::Expression>());
+//            preparedProgram = preparedProgram.substituteConstants();
+//
+//            // Initialize the structure used for storing all information needed during the model generation.
+//            GenerationInformation generationInfo(preparedProgram);
+//
+//            // Initial state DD
+//            storm::dd::Dd<Type> initialStateDd = generationInfo.manager->getZero();
+//            initialStateDd = getInitialStateDecisionDiagram(generationInfo);
+//            
+//            // System DD
+//            storm::dd::Dd<Type> systemDd = generationInfo.manager->getZero();
+//            
+//            // Reachable states DD
+//            storm::dd::Dd<Type> reachableStatesDd = generationInfo.manager->getOne();
+//            
+//            // Initialize the clock.
+//            auto clock = std::chrono::high_resolution_clock::now();
+//            
+//            // Create system DD
+//            systemDd = createSystemDecisionDiagramm(generationInfo);
+//            std::cout << "Built transition matrix in " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - clock).count() << "ms." << std::endl;
+//            
+//            //manager->triggerReordering();
+//            
+//            // Get all reachable states
+//            if (!storm::settings::adapterSettings().isNoReachSet()){
+//                reachableStatesDd = performReachability(generationInfo, systemDd, initialStateDd);
+//                // Reduce transition matrix
+//                systemDd = systemDd * reachableStatesDd;
+//            }
+//            
+//            // Fix deadlocks
+//            if (!storm::settings::adapterSettings().isNoDeadlockSet()){
+//                systemDd = findDeadlocks(generationInfo, systemDd, reachableStatesDd);
+//            }
+//            
+//            // System DD with only 0/1 leaves
+//            storm::dd::Dd<Type> systemBdd = systemDd.notZero();
+//            
+//            // Get all abstract variables (MDP)
+//            std::set<std::string> abstractVariables = std::set<std::string>();
+//            
+//            if (program.getModelType() == storm::prism::Program::ModelType::MDP) {
+//                for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i) {
+//                    // Synchronizing variables
+//                    if (systemDd.containsMetaVariable("sync" + std::to_string(i))) {
+//                        abstractVariables.insert("sync" + std::to_string(i));
+//                    }
+//                }
+//                for (uint_fast64_t i = 1; i <= generationInfo.numberOfNondetVariables; ++i) {
+//                    // Nondet. variables
+//                    if (systemDd.containsMetaVariable("nondet" + std::to_string(i))) {
+//                        abstractVariables.insert("nondet" + std::to_string(i));
+//                    }
+//                }
+//            }
+//            
+//            // Create state labeling
+//            std::unordered_map<std::string, storm::dd::Dd<Type>> labelToStateDdMap;
+//            storm::dd::Dd<Type> temporary;
+//            for (auto const& label : program.getLabels()) {
+//                // Translate Labeling into Expression and further into DD
+//                temporary = storm::adapters::SymbolicExpressionAdapter<Type>::translateExpression(label.getStatePredicateExpression().getBaseExpressionPointer(), generationInfo.program, generationInfo.manager, false);
+//                temporary = temporary * reachableStatesDd;
+//                labelToStateDdMap.insert(std::make_pair(label.getName(), temporary));
+//            }
+//            
+//            // Create model
+//            std::shared_ptr<storm::models::AbstractSymbolicModel<Type>> model;
+//            switch (program.getModelType()){
+//                case storm::prism::Program::ModelType::DTMC:
+//                    model = std::shared_ptr<storm::models::AbstractSymbolicModel<Type>>(std::make_shared<storm::models::SymbolicDtmc<Type>>(std::move(systemDd),
+//                                                                                                                                            std::move(systemBdd), std::move(initialStateDd), std::move(reachableStatesDd),
+//                                                                                                                                            std::move(generationInfo.rewardDds.first), std::move(generationInfo.rewardDds.second), std::move(generationInfo.manager->getZero()),
+//                                                                                                                                            std::move(generationInfo.rowMetaVariableNames), std::move(generationInfo.columnMetaVariableNames), std::move(generationInfo.metaVariablePairs),
+//                                                                                                                                            std::move(generationInfo.allSynchronizingActions), std::move(abstractVariables), std::move(generationInfo.manager), std::move(labelToStateDdMap)));
+//                    break;
+//                case storm::prism::Program::ModelType::MDP:
+//                    model = std::shared_ptr<storm::models::AbstractSymbolicModel<Type>>(std::make_shared<storm::models::SymbolicMdp<Type>>(std::move(systemDd),
+//                                                                                                                                           std::move(systemBdd), std::move(initialStateDd), std::move(reachableStatesDd),
+//                                                                                                                                           std::move(generationInfo.rewardDds.first), std::move(generationInfo.rewardDds.second), std::move(generationInfo.transitionActionDd),
+//                                                                                                                                           std::move(generationInfo.rowMetaVariableNames), std::move(generationInfo.columnMetaVariableNames), std::move(generationInfo.metaVariablePairs),
+//                                                                                                                                           std::move(generationInfo.allSynchronizingActions), std::move(abstractVariables), std::move(generationInfo.manager), std::move(labelToStateDdMap)));
+//                    break;
+//                default:
+//                    STORM_LOG_ASSERT(false, "Illegal model type.");
+//            }
+//            
+//            LOG4CPLUS_INFO(logger, "Done creating MTBDD representation for probabilistic preparedProgram.");
+//            LOG4CPLUS_INFO(logger, "MTBDD: " << systemDd.getNodeCount() << " nodes, " << systemDd.getLeafCount() << " leaves, " << generationInfo.manager->getNumberOfMetaVariables() << " variables.");
+//            return model;
+        }
+        
+//        template <storm::dd::DdType Type>
+//        void SymbolicModelAdapter<Type>::GenerationInformation::addDecisionDiagramVariables() {
+//            
+//            uint_fast64_t numberOfSynchronizingActions = allSynchronizingActions.size();
+//            
+//            // Add synchronizing variables
+//            for (uint_fast64_t i = 0; i < numberOfSynchronizingActions; ++i) {
+//                manager->addMetaVariable("sync" + std::to_string(i), 0, 1);
+//            }
+//            
+//            // Add nondet. variables ( number of modules + number of commands)
+//            numberOfNondetVariables = program.getModules().size();
+//            for (uint_fast64_t i = 0; i < program.getModules().size(); ++i) {
+//                numberOfNondetVariables += program.getModule(i).getCommands().size();
+//            }
+//            
+//            for (uint_fast64_t i = numberOfNondetVariables; i > 0; --i) {
+//                manager->addMetaVariable("nondet" + std::to_string(i), 0, 1);
+//            }
+//            
+//            std::vector<std::string> newVariables;
+//            
+//            // Global Boolean Variables
+//            for (uint_fast64_t j = 0; j < program.getGlobalBooleanVariables().size(); ++j) {
+//                storm::prism::BooleanVariable const& booleanVariable = program.getGlobalBooleanVariables().at(j);
+//                
+//                // Add row and column meta variable
+//                manager->addMetaVariable(booleanVariable.getName(), 0, 1);
+//                
+//                rowMetaVariableNames.insert(booleanVariable.getName());
+//                columnMetaVariableNames.insert(booleanVariable.getName() + "'");
+//                
+//                // Create pair (column,row)
+//                std::pair<std::string, std::string> variablePair(booleanVariable.getName() + "'", booleanVariable.getName());
+//                metaVariablePairs.push_back(variablePair);
+//            }
+//            
+//            // Global Integer Variables
+//            for (uint_fast64_t j = 0; j < program.getGlobalIntegerVariables().size(); ++j) {
+//                storm::prism::IntegerVariable const& integerVariable = program.getGlobalIntegerVariables().at(j);
+//                
+//                int_fast64_t low = integerVariable.getLowerBoundExpression().evaluateAsInt();
+//                int_fast64_t high = integerVariable.getUpperBoundExpression().evaluateAsInt();
+//                
+//                // Add row and column meta variable
+//                manager->addMetaVariable(integerVariable.getName(), low, high);
+//                
+//                rowMetaVariableNames.insert(integerVariable.getName());
+//                columnMetaVariableNames.insert(integerVariable.getName() + "'");
+//                
+//                // Create pair (column,row)
+//                std::pair<std::string, std::string> variablePair(integerVariable.getName() + "'", integerVariable.getName());
+//                metaVariablePairs.push_back(variablePair);
+//            }
+//            
+//            // Add boolean and integer variables
+//            for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
+//                storm::prism::Module const& module = program.getModule(i);
+//                
+//                // Boolean Variables
+//                for (uint_fast64_t j = 0; j < module.getNumberOfBooleanVariables(); ++j) {
+//                    storm::prism::BooleanVariable const& booleanVariable = module.getBooleanVariables().at(j);
+//                    
+//                    // Add row and column meta variable
+//                    manager->addMetaVariable(booleanVariable.getName(), 0, 1);
+//                    
+//                    rowMetaVariableNames.insert(booleanVariable.getName());
+//                    columnMetaVariableNames.insert(booleanVariable.getName() + "'");
+//                    
+//                    // Create pair (column,row)
+//                    std::pair<std::string, std::string> variablePair(booleanVariable.getName() + "'", booleanVariable.getName());
+//                    metaVariablePairs.push_back(variablePair);
+//                }
+//                
+//                // Integer Variables
+//                for (uint_fast64_t j = 0; j < module.getNumberOfIntegerVariables(); ++j) {
+//                    storm::prism::IntegerVariable const& integerVariable = module.getIntegerVariables().at(j);
+//                    
+//                    int_fast64_t low = integerVariable.getLowerBoundExpression().evaluateAsInt();
+//                    int_fast64_t high = integerVariable.getUpperBoundExpression().evaluateAsInt();
+//                    
+//                    // Add row and column meta variable
+//                    manager->addMetaVariable(integerVariable.getName(), low, high);
+//                    
+//                    rowMetaVariableNames.insert(integerVariable.getName());
+//                    columnMetaVariableNames.insert(integerVariable.getName() + "'");
+//                    
+//                    // Create pair (column,row)
+//                    std::pair<std::string, std::string> variablePair(integerVariable.getName() + "'", integerVariable.getName());
+//                    metaVariablePairs.push_back(variablePair);
+//                }
+//            }
+//            
+//            std::cout << "Variable Ordering: ";
+//            for(auto x: manager->getDdVariableNames()){
+//                std::cout << x << ",";
+//            }
+//            std::cout << std::endl;
+//            std::cout << std::endl;
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        void SymbolicModelAdapter<Type>::GenerationInformation::createIdentityDecisionDiagrams() {
+//            
+//            // Global Boolean variables
+//            for (uint_fast64_t j = 0; j < program.getGlobalBooleanVariables().size(); ++j) {
+//                storm::prism::BooleanVariable const & booleanVariable = program.getGlobalBooleanVariables().at(j);
+//                
+//                storm::dd::Dd<Type> identity = manager->getZero();
+//                
+//                // f(0)=0 leads to 1
+//                identity.setValue(booleanVariable.getName(), 0, booleanVariable.getName() + "'", 0, 1);
+//                // f(1)=1 leads to 1
+//                identity.setValue(booleanVariable.getName(), 1, booleanVariable.getName() + "'", 1, 1);
+//                
+//                variableToIdentityDecisionDiagramMap.insert(std::make_pair(booleanVariable.getName(), identity));
+//            }
+//            
+//            // Global Integer variables
+//            for (uint_fast64_t j = 0; j < program.getGlobalIntegerVariables().size(); ++j) {
+//                storm::prism::IntegerVariable const& integerVariable = program.getGlobalIntegerVariables().at(j);
+//                storm::dd::Dd<Type> identity = manager->getZero();
+//                
+//                int_fast64_t low = integerVariable.getLowerBoundExpression().evaluateAsInt();
+//                int_fast64_t high = integerVariable.getUpperBoundExpression().evaluateAsInt();
+//                
+//                for (int_fast64_t i = low; i <= high; ++i) {
+//                    // f(i)=i leads to 1
+//                    identity.setValue(integerVariable.getName(), i, integerVariable.getName() + "'", i, 1);
+//                }
+//                
+//                variableToIdentityDecisionDiagramMap.insert(std::make_pair(integerVariable.getName(), identity));
+//            }
+//            
+//            
+//            for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
+//                storm::prism::Module const& module = program.getModule(i);
+//                
+//                // Module identity matrix
+//                storm::dd::Dd<Type> moduleIdentity = manager->getOne();
+//                
+//                // Boolean variables
+//                for (uint_fast64_t j = 0; j < module.getNumberOfBooleanVariables(); ++j) {
+//                    storm::prism::BooleanVariable const& booleanVariable = module.getBooleanVariables().at(j);
+//                    
+//                    storm::dd::Dd<Type> identity = manager->getZero();
+//                    
+//                    // f(0)=0 leads to 1
+//                    identity.setValue(booleanVariable.getName(), 0, booleanVariable.getName() + "'", 0, 1);
+//                    // f(1)=1 leads to 1
+//                    identity.setValue(booleanVariable.getName(), 1, booleanVariable.getName() + "'", 1, 1);
+//                    
+//                    variableToIdentityDecisionDiagramMap.insert(std::make_pair(booleanVariable.getName(), identity));
+//                    moduleIdentity = moduleIdentity * identity;
+//                }
+//                
+//                // Integer variables
+//                for (uint_fast64_t j = 0; j < module.getNumberOfIntegerVariables(); ++j) {
+//                    storm::prism::IntegerVariable const& integerVariable = module.getIntegerVariables().at(j);
+//                    storm::dd::Dd<Type> identity = manager->getZero();
+//                    
+//                    int_fast64_t low = integerVariable.getLowerBoundExpression().evaluateAsInt();
+//                    int_fast64_t high = integerVariable.getUpperBoundExpression().evaluateAsInt();
+//                    
+//                    for (int_fast64_t i = low; i <= high; ++i) {
+//                        // f(i)=i leads to 1
+//                        identity.setValue(integerVariable.getName(), i, integerVariable.getName() + "'", i, 1);
+//                    }
+//                    
+//                    variableToIdentityDecisionDiagramMap.insert(std::make_pair(integerVariable.getName(), identity));
+//                    moduleIdentity = moduleIdentity * identity;
+//                }
+//                
+//                // Create module identity matrix
+//                moduleToIdentityDecisionDiagramMap.insert(std::make_pair(module.getName(), moduleIdentity));
+//            }
+//            
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        storm::dd::Dd<Type> SymbolicModelAdapter<Type>::createSystemDecisionDiagramm(GenerationInformation & generationInfo){
+//            
+//            uint_fast64_t numberOfSynchronizingActions = generationInfo.allSynchronizingActions.size();
+//            
+//            // System DDs
+//            SystemComponentDecisionDiagram<Type> systemDds(0);
+//            SystemComponentDecisionDiagram<Type> systemDds1(0);
+//            SystemComponentDecisionDiagram<Type> systemDds2(0);
+//            
+//            storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
+//            
+//            // Initialize usedNondetVariablesVector
+//            // TODO: Formulate simpler.
+//            std::vector<uint_fast64_t> usedNondetVariablesVector(numberOfSynchronizingActions);
+//            for (uint_fast64_t j = 0; j < numberOfSynchronizingActions; ++j) {
+//                usedNondetVariablesVector[j] = 0;
+//            }
+//            
+//            // Create DD for first module
+//            systemDds = createSystemComponentDecisionDiagramm(generationInfo, generationInfo.program.getModule(0), usedNondetVariablesVector);
+//            
+//            for (uint_fast64_t i = 1; i < generationInfo.program.getNumberOfModules(); ++i) {
+//                
+//                // Create new usedNondetVariablesVector
+//                std::vector<uint_fast64_t> newUsedNondetVariablesVector(numberOfSynchronizingActions);
+//                for (uint_fast64_t j = 0; j < numberOfSynchronizingActions; ++j) {
+//                    // Check if systemDds contains action
+//                    if (std::find(systemDds.allSynchronizingActions.begin(), systemDds.allSynchronizingActions.end(), generationInfo.allSynchronizingActions[j]) != systemDds.allSynchronizingActions.end()) {
+//                        newUsedNondetVariablesVector[j] = systemDds.synchronizingActionDds[j].usedNondetVariables;
+//                    }
+//                    else{
+//                        newUsedNondetVariablesVector[j] = usedNondetVariablesVector[j];
+//                    }
+//                }
+//                
+//                // Create DD for next module
+//                systemDds2 = createSystemComponentDecisionDiagramm(generationInfo, generationInfo.program.getModule(i), newUsedNondetVariablesVector);
+//                
+//                // SystemDds1 stores the previous modules (already combined)
+//                systemDds1 = SystemComponentDecisionDiagram<Type>(systemDds);
+//                
+//                // SystemDds is used to store combination of SystemDds1 and SystemDds2
+//                systemDds = SystemComponentDecisionDiagram<Type>(numberOfSynchronizingActions);
+//                
+//                // Combine non-synchronizing/independent actions
+//                systemDds.independentActionDd = combineModules(generationInfo, false, systemDds1.independentActionDd, systemDds2.independentActionDd, systemDds1.identityMatrix, systemDds2.identityMatrix);
+//                
+//                // Combine synchronizing actions
+//                for (uint_fast64_t j = 0; j < numberOfSynchronizingActions; ++j){
+//                    // Check if both modules contain the current action
+//                    if (std::find(systemDds1.allSynchronizingActions.begin(), systemDds1.allSynchronizingActions.end(), generationInfo.allSynchronizingActions[j]) != systemDds1.allSynchronizingActions.end() &&
+//                        std::find(systemDds2.allSynchronizingActions.begin(), systemDds2.allSynchronizingActions.end(), generationInfo.allSynchronizingActions[j]) != systemDds2.allSynchronizingActions.end()) {
+//                        // Both modules contain action
+//                        systemDds.synchronizingActionDds[j] = combineModules(generationInfo, true, systemDds1.synchronizingActionDds[j], systemDds2.synchronizingActionDds[j], systemDds1.identityMatrix, systemDds2.identityMatrix);
+//                    }
+//                    else {
+//                        // Only one or no module contains current action
+//                        systemDds.synchronizingActionDds[j] = combineModules(generationInfo, false, systemDds1.synchronizingActionDds[j], systemDds2.synchronizingActionDds[j], systemDds1.identityMatrix, systemDds2.identityMatrix);
+//                    }
+//                }
+//                
+//                // Combine identity matrix
+//                systemDds.identityMatrix = systemDds1.identityMatrix * systemDds2.identityMatrix;
+//                
+//                // Combine list of synchronizing actions
+//                systemDds.allSynchronizingActions.insert(systemDds1.allSynchronizingActions.begin(), systemDds1.allSynchronizingActions.end());
+//                systemDds.allSynchronizingActions.insert(systemDds2.allSynchronizingActions.begin(), systemDds2.allSynchronizingActions.end());
+//            }
+//            
+//            // Combine all DDs
+//            systemDds = combineSystem(generationInfo, systemDds);
+//            generationInfo.globalSystemDds = SystemComponentDecisionDiagram<Type>(systemDds);
+//            
+//            
+//            // Build state and transition rewards
+//            generationInfo.rewardDds = computeRewards(generationInfo, systemDds);
+//            
+//            // Create transition to action mapping for MDPs
+//            if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
+//                generationInfo.transitionActionDd = computeTransitionAction(generationInfo, systemDds);
+//            }
+//            
+//            // Normalize each row for DTMCs
+//            if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) {
+//                temporary = storm::dd::Dd<Type>(systemDds.independentActionDd.commandsDd);
+//                temporary = temporary.sumAbstract(generationInfo.columnMetaVariableNames);
+//                systemDds.independentActionDd.commandsDd = systemDds.independentActionDd.commandsDd / temporary;
+//            }
+//            
+//            // Get system transition matrix
+//            storm::dd::Dd<Type> systemTransitionMatrix = systemDds.independentActionDd.commandsDd;
+//            
+//            return systemTransitionMatrix;
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        SystemComponentDecisionDiagram<Type> SymbolicModelAdapter<Type>::combineSystem(GenerationInformation const & generationInfo, SystemComponentDecisionDiagram<Type> systemDds){
+//            
+//            uint_fast64_t numberOfSynchronizingActions = generationInfo.allSynchronizingActions.size();
+//            uint_fast64_t max = 0;
+//            storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
+//            storm::dd::Dd<Type> variableDd = generationInfo.manager->getZero();
+//            
+//            // Add non-determinism variables for MDPs
+//            if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
+//                // Check DD variables
+//                
+//                // Look for maximal variable index
+//                max = systemDds.independentActionDd.usedNondetVariables;
+//                for (uint_fast64_t i = 0; i < numberOfSynchronizingActions; ++i){
+//                    if (systemDds.synchronizingActionDds[i].usedNondetVariables > max) {
+//                        max = systemDds.synchronizingActionDds[i].usedNondetVariables;
+//                    }
+//                }
+//                
+//                // Add variables to independent action DD (if required)
+//                if (max > systemDds.independentActionDd.usedNondetVariables) {
+//                    temporary = generationInfo.manager->getOne();
+//                    for (uint_fast64_t i = systemDds.independentActionDd.usedNondetVariables+1; i <= max; ++i){
+//                        
+//                        // Get variable and set to 0
+//                        variableDd = generationInfo.manager->getEncoding("nondet" + std::to_string(i), 0);
+//                        temporary = temporary * variableDd;
+//                        
+//                    }
+//                    systemDds.independentActionDd.commandsDd = systemDds.independentActionDd.commandsDd * temporary;
+//                    systemDds.independentActionDd.usedNondetVariables = max;
+//                }
+//                
+//                // Add variables to synchronized action DDs
+//                for (uint_fast64_t j = 0; j < numberOfSynchronizingActions; ++j){
+//                    if (max > systemDds.synchronizingActionDds[j].usedNondetVariables) {
+//                        temporary = generationInfo.manager->getOne();
+//                        for (uint_fast64_t i = systemDds.synchronizingActionDds[j].usedNondetVariables+1; i <= max; ++i){
+//                            
+//                            // Get variable and set to 0
+//                            variableDd = generationInfo.manager->getEncoding("nondet" + std::to_string(i), 0);
+//                            temporary = temporary * variableDd;
+//                            
+//                        }
+//                        systemDds.synchronizingActionDds[j].commandsDd = systemDds.synchronizingActionDds[j].commandsDd * temporary;
+//                        systemDds.synchronizingActionDds[j].usedNondetVariables = max;
+//                    }
+//                }
+//                
+//                // Set variables for synchronization
+//                temporary = generationInfo.manager->getOne();
+//                for (uint_fast64_t i = 0; i < numberOfSynchronizingActions; ++i){
+//                    // Get sync variable
+//                    variableDd = generationInfo.manager->getEncoding("sync" + std::to_string(i), 0);
+//                    temporary = temporary * variableDd;
+//                }
+//                
+//                systemDds.independentActionDd.commandsDd = temporary * systemDds.independentActionDd.commandsDd;
+//                
+//                // Set variables for synchronized action DDs
+//                for (uint_fast64_t i = 0; i < numberOfSynchronizingActions; ++i){
+//                    temporary = generationInfo.manager->getOne();
+//                    for (uint_fast64_t j = 0; j < numberOfSynchronizingActions; ++j){
+//                        // Enable synchronizing variable j iff current action i==j
+//                        if (i == j) {
+//                            variableDd = generationInfo.manager->getEncoding("sync" + std::to_string(j), 1);
+//                            temporary = temporary * variableDd;
+//                        }
+//                        else {
+//                            variableDd = generationInfo.manager->getEncoding("sync" + std::to_string(j), 0);
+//                            temporary = temporary * variableDd;
+//                        }
+//                    }
+//                    
+//                    systemDds.synchronizingActionDds[i].commandsDd = temporary * systemDds.synchronizingActionDds[i].commandsDd;
+//                }
+//                
+//            }
+//            
+//            // Create transition matrix
+//            temporary = systemDds.independentActionDd.commandsDd;
+//            for (uint_fast64_t i = 0; i < numberOfSynchronizingActions; ++i){
+//                temporary = temporary + systemDds.synchronizingActionDds[i].commandsDd;
+//            }
+//            
+//            // Store transition matrix in systemDDs structure
+//            systemDds.independentActionDd.commandsDd = temporary;
+//            
+//            return systemDds;
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        ModuleDecisionDiagram<Type> SymbolicModelAdapter<Type>::combineModules(GenerationInformation const & generationInfo, bool synchronizing, ModuleDecisionDiagram<Type> moduleDd1, ModuleDecisionDiagram<Type> moduleDd2, storm::dd::Dd<Type> const& identityDd1, storm::dd::Dd<Type> const& identityDd2){
+//            
+//            // Module DD
+//            ModuleDecisionDiagram<Type> moduleDd = ModuleDecisionDiagram<Type>();
+//            
+//            if (synchronizing) {
+//                // Synchronizing actions
+//                
+//                // Combine guards (intersection)
+//                moduleDd.guardDd = moduleDd1.guardDd * moduleDd2.guardDd;
+//                
+//                // Combine transitions
+//                moduleDd.commandsDd = moduleDd1.commandsDd * moduleDd2.commandsDd;
+//                
+//                // Update min/max index
+//                moduleDd.usedNondetVariables = (moduleDd1.usedNondetVariables > moduleDd2.usedNondetVariables) ? moduleDd1.usedNondetVariables : moduleDd2.usedNondetVariables;
+//                
+//            } else {
+//                // Non-synchronizing actions
+//                
+//                // Multiply commands with identity matrix (because of non-synchronization)
+//                moduleDd1.commandsDd = moduleDd1.commandsDd * identityDd2;
+//                moduleDd2.commandsDd = moduleDd2.commandsDd * identityDd1;
+//                
+//                // Combine modules
+//                switch (generationInfo.program.getModelType()) {
+//                    case storm::prism::Program::ModelType::DTMC:
+//                        
+//                        // No non-determinism, just sum up
+//                        moduleDd.guardDd = moduleDd1.guardDd + moduleDd2.guardDd;
+//                        moduleDd.commandsDd = moduleDd1.commandsDd + moduleDd2.commandsDd;
+//                        moduleDd.usedNondetVariables = 0;
+//                        break;
+//                    case storm::prism::Program::ModelType::MDP:
+//                        
+//                        // Combine modules and solve non-determinism
+//                        moduleDd = combineModulesMDP(generationInfo, moduleDd1, moduleDd2);
+//                        break;
+//                    default:
+//                        STORM_LOG_ASSERT(false, "Illegal model type.");
+//                }
+//            }
+//            
+//            return moduleDd;
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        ModuleDecisionDiagram<Type> SymbolicModelAdapter<Type>::combineModulesMDP(GenerationInformation const & generationInfo, ModuleDecisionDiagram<Type> moduleDd1, ModuleDecisionDiagram<Type> moduleDd2){
+//            
+//            // Module DD
+//            ModuleDecisionDiagram<Type> moduleDd = ModuleDecisionDiagram<Type>();
+//            
+//            storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
+//            storm::dd::Dd<Type> variableDd = generationInfo.manager->getZero();
+//            
+//            // Check if one command DD equals 0
+//            if (moduleDd1.commandsDd.isZero()) {
+//                moduleDd.guardDd = moduleDd2.guardDd;
+//                moduleDd.commandsDd = moduleDd2.commandsDd;
+//                moduleDd.usedNondetVariables = moduleDd2.usedNondetVariables;
+//                return moduleDd;
+//            }
+//            if (moduleDd2.commandsDd.isZero()) {
+//                moduleDd.guardDd = moduleDd1.guardDd;
+//                moduleDd.commandsDd = moduleDd1.commandsDd;
+//                moduleDd.usedNondetVariables = moduleDd1.usedNondetVariables;
+//                return moduleDd;
+//            }
+//            
+//            // Solve non-determinism
+//            
+//            // Check index of DD variables
+//            if (moduleDd1.usedNondetVariables > moduleDd2.usedNondetVariables) {
+//                temporary = generationInfo.manager->getOne();
+//                
+//                for (uint_fast64_t i = moduleDd2.usedNondetVariables+1; i <= moduleDd1.usedNondetVariables; ++i){
+//                    // Get variable and set to 0
+//                    variableDd = generationInfo.manager->getEncoding("nondet" + std::to_string(i), 0);
+//                    temporary = temporary * variableDd;
+//                }
+//                moduleDd2.commandsDd = moduleDd2.commandsDd * temporary;
+//                moduleDd2.usedNondetVariables = moduleDd1.usedNondetVariables;
+//            }
+//            if (moduleDd2.usedNondetVariables > moduleDd1.usedNondetVariables) {
+//                temporary = generationInfo.manager->getOne();
+//                
+//                for (uint_fast64_t i = moduleDd1.usedNondetVariables+1; i <= moduleDd2.usedNondetVariables; ++i){
+//                    // Get variable and set to 0
+//                    variableDd = generationInfo.manager->getEncoding("nondet" + std::to_string(i), 0);
+//                    temporary = temporary * variableDd;
+//                }
+//                moduleDd1.commandsDd = moduleDd1.commandsDd * temporary;
+//                moduleDd1.usedNondetVariables = moduleDd2.usedNondetVariables;
+//            }
+//            
+//            // Get new nondet. variable
+//            variableDd = variableDd = generationInfo.manager->getEncoding("nondet" + std::to_string(moduleDd1.usedNondetVariables + 1), 1);
+//            
+//            // Set nondet. variable
+//            moduleDd2.commandsDd = moduleDd2.commandsDd * variableDd;
+//            moduleDd1.commandsDd = moduleDd1.commandsDd * (!variableDd);
+//            
+//            // Combine command DDs
+//            moduleDd.commandsDd = moduleDd1.commandsDd + moduleDd2.commandsDd;
+//            
+//            // Combine guard DDs
+//            moduleDd.guardDd = moduleDd1.guardDd || moduleDd2.guardDd;
+//            
+//            moduleDd.usedNondetVariables = moduleDd1.usedNondetVariables + 1;
+//            
+//            return moduleDd;
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        SystemComponentDecisionDiagram<Type> SymbolicModelAdapter<Type>::createSystemComponentDecisionDiagramm(GenerationInformation const & generationInfo, storm::prism::Module const& module, std::vector<uint_fast64_t> usedNondetVariablesVector){
+//            
+//            uint_fast64_t numberOfSynchronizingActions = generationInfo.allSynchronizingActions.size();
+//            
+//            // System Component DD
+//            SystemComponentDecisionDiagram<Type> systemComponentDd(numberOfSynchronizingActions);
+//            
+//            // Create module DD for independent actions
+//            systemComponentDd.independentActionDd = createModuleDecisionDiagramm(generationInfo, module, "", 0);
+//            
+//            // Create module DD for synchronizing actions
+//            for (uint_fast64_t i = 0; i < numberOfSynchronizingActions; ++i){
+//                
+//                if (module.hasAction(generationInfo.allSynchronizingActions[i])){
+//                    systemComponentDd.synchronizingActionDds[i] = createModuleDecisionDiagramm(generationInfo, module, generationInfo.allSynchronizingActions[i], usedNondetVariablesVector[i]);
+//                }else{
+//                    switch (generationInfo.program.getModelType()){
+//                        case storm::prism::Program::ModelType::DTMC:
+//                            systemComponentDd.synchronizingActionDds[i] = ModuleDecisionDiagram<Type>(generationInfo.manager->getZero(), generationInfo.manager->getZero(), 0);
+//                            break;
+//                        case storm::prism::Program::ModelType::MDP:
+//                            systemComponentDd.synchronizingActionDds[i] = ModuleDecisionDiagram<Type>(generationInfo.manager->getZero(), generationInfo.manager->getZero(), usedNondetVariablesVector[i]);
+//                            break;
+//                        default:
+//                            STORM_LOG_ASSERT(false, "Illegal model type.");
+//                    }
+//                }
+//                
+//            }
+//            
+//            // Get module identity matrix
+//            systemComponentDd.identityMatrix = generationInfo.moduleToIdentityDecisionDiagramMap.at(module.getName());
+//            
+//            // Store all synchronizing actions
+//            systemComponentDd.allSynchronizingActions.insert(module.getActions().begin(), module.getActions().end());
+//            
+//            return systemComponentDd;
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        ModuleDecisionDiagram<Type> SymbolicModelAdapter<Type>::combineCommandsDTMC(std::shared_ptr<storm::dd::DdManager<Type>> const & manager, uint_fast64_t numberOfCommands, std::vector<storm::dd::Dd<Type>> const& commandDds, std::vector<storm::dd::Dd<Type>> const & guardDds){
+//            
+//            // Module DD
+//            ModuleDecisionDiagram<Type> moduleDd;
+//            
+//            // Initialize DDs
+//            storm::dd::Dd<Type> guardRangeDd = manager->getZero();
+//            storm::dd::Dd<Type> commandsDd = manager->getZero();
+//            storm::dd::Dd<Type> temporary = manager->getZero();
+//            
+//            for (uint_fast64_t i = 0; i < numberOfCommands; ++i) {
+//                
+//                // Check guard
+//                if (guardDds[i].isZero()) continue;
+//                
+//                // Check for overlapping guards
+//                temporary = guardDds[i] * guardRangeDd;
+//                if (!(temporary.isZero())) {
+//                    LOG4CPLUS_WARN(logger, "Overlapping guard in command " << (i + 1) << ".");
+//                }
+//                
+//                // Sum up all guards
+//                guardRangeDd = guardRangeDd + guardDds[i];
+//                
+//                // Create command DD (multiply guard and updates)
+//                temporary = guardDds[i] * commandDds[i];
+//                
+//                // Sum up all command DDs
+//                commandsDd = commandsDd + temporary;
+//            }
+//            
+//            moduleDd.guardDd = guardRangeDd;
+//            moduleDd.commandsDd = commandsDd;
+//            moduleDd.usedNondetVariables = 0;
+//            
+//            return moduleDd;
+//        }
+//        
+//        // TODO
+//        std::map<std::string, int_fast64_t> getMetaVariableMapping(std::vector<std::string> metaVariables, uint_fast64_t value){
+//            
+//            std::map<std::string, int_fast64_t> metaVariableNameToValueMap = std::map<std::string, int_fast64_t>();
+//            
+//            for (uint_fast64_t i = 0; i < metaVariables.size(); ++i) {
+//                if (value & (1ull << (metaVariables.size() - i - 1))) {
+//                    metaVariableNameToValueMap.insert(std::make_pair(metaVariables[i], 1));
+//                }
+//                else {
+//                    metaVariableNameToValueMap.insert(std::make_pair(metaVariables[i], 0));
+//                }
+//            }
+//            
+//            return metaVariableNameToValueMap;
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        ModuleDecisionDiagram<Type> SymbolicModelAdapter<Type>::combineCommandsMDP(std::shared_ptr<storm::dd::DdManager<Type>> const & manager, uint_fast64_t numberOfCommands, std::vector<storm::dd::Dd<Type>> const& commandDds, std::vector<storm::dd::Dd<Type>> const & guardDds, uint_fast64_t usedNondetVariables){
+//            
+//            // Module DD
+//            ModuleDecisionDiagram<Type> moduleDd = ModuleDecisionDiagram<Type>();
+//            
+//            // Initialize DDs
+//            storm::dd::Dd<Type> guardRangeDd = manager->getZero();
+//            storm::dd::Dd<Type> commandsDd = manager->getZero();
+//            storm::dd::Dd<Type> temporaryDd = manager->getZero();
+//            
+//            // Check for overlapping guards
+//            storm::dd::Dd<Type> overlappingGuardDd = manager->getZero();
+//            
+//            for (uint_fast64_t i = 0; i < numberOfCommands; ++i) {
+//                overlappingGuardDd = overlappingGuardDd + guardDds[i];
+//                guardRangeDd = guardRangeDd || guardDds[i];
+//            }
+//            
+//            uint_fast64_t maxChoices = overlappingGuardDd.getMax();
+//            
+//            // Check for no choice or no non-determinism
+//            if (maxChoices == 0 || maxChoices == 1) {
+//                
+//                if (maxChoices == 1) {
+//                    // Sum up all command updates
+//                    for (uint_fast64_t i = 0; i < numberOfCommands; ++i) {
+//                        temporaryDd = guardDds[i] * commandDds[i];
+//                        commandsDd = commandsDd + temporaryDd;
+//                    }
+//                }
+//                
+//                moduleDd.guardDd = guardRangeDd;
+//                moduleDd.commandsDd = commandsDd;
+//                moduleDd.usedNondetVariables = usedNondetVariables;
+//                
+//                return moduleDd;
+//            }
+//            
+//            // Calculate number of required variables (log2(maxChoices))
+//            uint_fast64_t numberOfBinaryVariables = static_cast<uint_fast64_t>(std::ceil(log2(maxChoices)));
+//            
+//            // Allocate local nondet. choice variables
+//            std::vector<std::string> nondetVariables(numberOfBinaryVariables);
+//            for (uint_fast64_t i = 1; i <= numberOfBinaryVariables; ++i) {
+//                nondetVariables[i-1] = "nondet" + std::to_string(usedNondetVariables + i);
+//            }
+//            
+//            // Initialize more DDs
+//            storm::dd::Dd<Type> equalsNumberOfChoicesDd = manager->getZero();
+//            std::vector<storm::dd::Dd<Type>> choiceDds(maxChoices);
+//            std::vector<storm::dd::Dd<Type>> remainingDds(maxChoices);
+//            
+//            storm::dd::Dd<Type> temporaryDd1 = manager->getZero();
+//            storm::dd::Dd<Type> temporaryDd2 = manager->getZero();
+//            
+//            for (uint_fast64_t currentChoices = 1; currentChoices <= maxChoices; ++currentChoices) {
+//                
+//                // Check for paths with exactly i nondet. choices
+//                equalsNumberOfChoicesDd = overlappingGuardDd.equals(manager->getConstant(static_cast<double> (currentChoices)));
+//                
+//                if (equalsNumberOfChoicesDd.isZero()) continue;
+//                
+//                // Reset DDs
+//                for (uint_fast64_t j = 0; j < currentChoices; ++j) {
+//                    choiceDds[j] = manager->getZero();
+//                    remainingDds[j] = equalsNumberOfChoicesDd;
+//                }
+//                
+//                // Check all commands
+//                for (uint_fast64_t j = 0; j < numberOfCommands; ++j) {
+//                    
+//                    // Check if command guard overlaps with equalsNumberOfChoicesDd
+//                    temporaryDd1 = guardDds[j] && equalsNumberOfChoicesDd;
+//                    if (temporaryDd1.isZero()) continue;
+//                    
+//                    // Split nondet. choices
+//                    for (uint_fast64_t k = 0; k < currentChoices; ++k) {
+//                        
+//                        // Calculate maximal overlapping parts of command guard and remaining DD (for current index)
+//                        temporaryDd2 = temporaryDd1 && remainingDds[k];
+//                        
+//                        // Check if we can add some overlapping parts to the current index
+//                        if (temporaryDd2 != manager->getZero()) {
+//                            
+//                            // Remove overlapping parts from the remaining DD
+//                            remainingDds[k] = remainingDds[k] && (!temporaryDd2);
+//                            
+//                            // Combine guard (overlapping parts) with command updates
+//                            temporaryDd = temporaryDd2 * commandDds[j];
+//                            // Add command DD to the commands with current index
+//                            choiceDds[k] = choiceDds[k] + temporaryDd;
+//                        }
+//                        
+//                        // Remove overlapping parts from the command guard DD
+//                        temporaryDd1 = temporaryDd1 && (!temporaryDd2);
+//                        
+//                        // Check if the command guard DD is already 0
+//                        if (temporaryDd1.isZero()) break;
+//                    }
+//                }
+//                
+//                // Set nondet. choices for corresponding DDs
+//                for (uint_fast64_t j = 0; j < currentChoices; ++j) {
+//                    
+//                    temporaryDd1 = manager->getZero();
+//                    
+//                    // Set chosen variables to value j
+//                    temporaryDd1.setValue(getMetaVariableMapping(nondetVariables, j), 1);
+//                    
+//                    // Multiply setting of nondet. variables with corresponding commands
+//                    temporaryDd = temporaryDd1 * choiceDds[j];
+//                    // Sum up all DDs (no non-determinism any more)
+//                    commandsDd = commandsDd + temporaryDd;
+//                }
+//                
+//                // Delete currentChoices out of overlapping DD
+//                overlappingGuardDd = overlappingGuardDd * (!equalsNumberOfChoicesDd);
+//            }
+//            
+//            moduleDd.guardDd = guardRangeDd;
+//            moduleDd.commandsDd = commandsDd;
+//            moduleDd.usedNondetVariables = usedNondetVariables + numberOfBinaryVariables;
+//            
+//            return moduleDd;
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        ModuleDecisionDiagram<Type> SymbolicModelAdapter<Type>::createModuleDecisionDiagramm(GenerationInformation const & generationInfo, storm::prism::Module const& module, std::string const& synchronizingAction, uint_fast64_t usedNondetVariables){
+//            
+//            // Module DD
+//            ModuleDecisionDiagram<Type> moduleDd;
+//            
+//            // Set up vectors
+//            uint_fast64_t numberOfCommands = module.getNumberOfCommands();
+//            std::vector<storm::dd::Dd<Type>> guardDds(numberOfCommands);
+//            std::vector<storm::dd::Dd<Type>> commandDds(numberOfCommands);
+//            
+//            for (uint_fast64_t j = 0; j < numberOfCommands; ++j) {
+//                
+//                storm::prism::Command const& command = module.getCommand(j);
+//                
+//                // Check if command action matches requested synchronizing action
+//                if (synchronizingAction == command.getActionName()) {
+//                    
+//                    // Translate guard
+//                    guardDds[j] = storm::adapters::SymbolicExpressionAdapter<Type>::translateExpression(command.getGuardExpression().getBaseExpressionPointer(), generationInfo.program, generationInfo.manager);
+//                    
+//                    if (guardDds[j].isZero()){
+//                        LOG4CPLUS_WARN(logger, "A guard is unsatisfiable.");
+//                    }
+//                    
+//                    // Create command DD
+//                    commandDds[j] = createCommandDecisionDiagramm(generationInfo, module, guardDds[j], command);
+//                    
+//                    commandDds[j] = commandDds[j] * guardDds[j];
+//                    
+//                    // check negative probabilities/rates
+//                    if (commandDds[j].getMin() < 0){
+//                        LOG4CPLUS_WARN(logger, "Negative probabilites/rates in command " << (j + 1) << ".");
+//                    }
+//                }
+//                else {
+//                    // Otherwise use zero DDs
+//                    guardDds[j] = generationInfo.manager->getZero();
+//                    commandDds[j] = generationInfo.manager->getZero();
+//                }
+//            }
+//            
+//            // combine command DDs with guard DDs
+//            switch (generationInfo.program.getModelType()){
+//                case storm::prism::Program::ModelType::DTMC:
+//                    moduleDd = combineCommandsDTMC(generationInfo.manager, numberOfCommands, commandDds, guardDds);
+//                    break;
+//                case storm::prism::Program::ModelType::MDP:
+//                    moduleDd = combineCommandsMDP(generationInfo.manager, numberOfCommands, commandDds, guardDds, usedNondetVariables);
+//                    break;
+//                default:
+//                    STORM_LOG_ASSERT(false, "Illegal model type.");
+//            }
+//            
+//            return moduleDd;
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        storm::dd::Dd<Type> SymbolicModelAdapter<Type>::createCommandDecisionDiagramm(GenerationInformation const & generationInfo, storm::prism::Module const& module, storm::dd::Dd<Type> const& guard, storm::prism::Command const& command){
+//            
+//            // Command DD
+//            storm::dd::Dd<Type> commandDd = generationInfo.manager->getZero();
+//            
+//            for (uint_fast64_t i = 0; i < command.getNumberOfUpdates(); ++i) {
+//                
+//                // Create update DD
+//                storm::dd::Dd<Type> updateDd = createUpdateDecisionDiagramm(generationInfo, module, guard, command.getUpdate(i));
+//                
+//                if (updateDd.isZero()){
+//                    LOG4CPLUS_WARN(logger, "Update " << (i + 1) << " does not do anything.");
+//                }
+//                
+//                // Multiply likelihood expression (MDP: transition probability)
+//                double p = command.getUpdate(i).getLikelihoodExpression().evaluateAsDouble();
+//                
+//                updateDd = updateDd * generationInfo.manager->getConstant(p);
+//                
+//                commandDd = commandDd + updateDd;
+//            }
+//            
+//            return commandDd;
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        storm::dd::Dd<Type> SymbolicModelAdapter<Type>::createUpdateDecisionDiagramm(GenerationInformation const & generationInfo, storm::prism::Module const& module, storm::dd::Dd<Type> const& guard, storm::prism::Update const& update){
+//            
+//            // Update DD
+//            storm::dd::Dd<Type> updateDd = generationInfo.manager->getOne();
+//            
+//            // Assignments (integer and boolean)
+//            std::vector<storm::prism::Assignment> assignments = update.getAssignments();
+//            for (auto singleAssignment : assignments) {
+//                
+//                // Translate first part of assignment
+//                storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
+//                
+//                temporary = generationInfo.manager->getIdentity(singleAssignment.getVariableName() + "'");
+//                
+//                // Translate second part of assignment
+//                storm::dd::Dd<Type> updateExpr = storm::adapters::SymbolicExpressionAdapter<Type>::translateExpression(singleAssignment.getExpression().getBaseExpressionPointer(), generationInfo.program, generationInfo.manager);
+//                
+//                storm::dd::Dd<Type> result = updateExpr * guard;
+//                // Combine first and second part of the assignment
+//                result = result.equals(temporary);
+//                result = result * guard;
+//                
+//                // Filter range
+//                result = result * generationInfo.manager->getRange(singleAssignment.getVariableName() + "'");
+//                
+//                updateDd = updateDd * result;
+//            }
+//            
+//            // All unused global boolean variables do not change
+//            for (uint_fast64_t i = 0; i < generationInfo.program.getGlobalBooleanVariables().size(); ++i) {
+//                storm::prism::BooleanVariable const& booleanVariable = generationInfo.program.getGlobalBooleanVariables().at(i);
+//                if (update.getAssignmentMapping().find(booleanVariable.getName()) == update.getAssignmentMapping().end()) {
+//                    // Multiply identity matrix
+//                    updateDd = updateDd * generationInfo.variableToIdentityDecisionDiagramMap.at(booleanVariable.getName());
+//                }
+//            }
+//            
+//            // All unused global integer variables do not change
+//            for (uint_fast64_t i = 0; i < generationInfo.program.getGlobalIntegerVariables().size(); ++i) {
+//                storm::prism::IntegerVariable const& integerVariable = generationInfo.program.getGlobalIntegerVariables().at(i);
+//                if (update.getAssignmentMapping().find(integerVariable.getName()) == update.getAssignmentMapping().end()) {
+//                    // Multiply identity matrix
+//                    updateDd = updateDd * generationInfo.variableToIdentityDecisionDiagramMap.at(integerVariable.getName());
+//                }
+//            }
+//            
+//            // All unused boolean variables do not change
+//            for (uint_fast64_t i = 0; i < module.getNumberOfBooleanVariables(); ++i) {
+//                storm::prism::BooleanVariable const& booleanVariable = module.getBooleanVariables().at(i);
+//                if (update.getAssignmentMapping().find(booleanVariable.getName()) == update.getAssignmentMapping().end()) {
+//                    // Multiply identity matrix
+//                    updateDd = updateDd * generationInfo.variableToIdentityDecisionDiagramMap.at(booleanVariable.getName());
+//                }
+//            }
+//            
+//            // All unused integer variables do not change
+//            for (uint_fast64_t i = 0; i < module.getNumberOfIntegerVariables(); ++i) {
+//                storm::prism::IntegerVariable const& integerVariable = module.getIntegerVariables().at(i);
+//                if (update.getAssignmentMapping().find(integerVariable.getName()) == update.getAssignmentMapping().end()) {
+//                    // Multiply identity matrix
+//                    updateDd = updateDd * generationInfo.variableToIdentityDecisionDiagramMap.at(integerVariable.getName());
+//                }
+//            }
+//            
+//            return updateDd;
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        storm::dd::Dd<Type> SymbolicModelAdapter<Type>::getInitialStateDecisionDiagram(GenerationInformation const & generationInfo) {
+//            storm::dd::Dd<Type> initialStates = generationInfo.manager->getOne();
+//            storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
+//            
+//            // Global Boolean variables
+//            for (uint_fast64_t j = 0; j < generationInfo.program.getGlobalBooleanVariables().size(); ++j) {
+//                storm::prism::BooleanVariable const& booleanVariable = generationInfo.program.getGlobalBooleanVariables().at(j);
+//                temporary = generationInfo.manager->getEncoding(booleanVariable.getName(), booleanVariable.getInitialValueExpression().evaluateAsBool());
+//                initialStates = initialStates * temporary;
+//            }
+//            
+//            // Global Integer variables
+//            for (uint_fast64_t j = 0; j < generationInfo.program.getGlobalIntegerVariables().size(); ++j) {
+//                storm::prism::IntegerVariable const& integerVariable = generationInfo.program.getGlobalIntegerVariables().at(j);
+//                temporary = generationInfo.manager->getEncoding(integerVariable.getName(), integerVariable.getInitialValueExpression().evaluateAsInt());
+//                initialStates = initialStates * temporary;
+//            }
+//            
+//            for (uint_fast64_t i = 0; i < generationInfo.program.getNumberOfModules(); ++i) {
+//                storm::prism::Module const& module = generationInfo.program.getModule(i);
+//                
+//                // Boolean variables
+//                for (uint_fast64_t j = 0; j < module.getNumberOfBooleanVariables(); ++j) {
+//                    storm::prism::BooleanVariable const& booleanVariable = module.getBooleanVariables().at(j);
+//                    temporary = generationInfo.manager->getEncoding(booleanVariable.getName(), booleanVariable.getInitialValueExpression().evaluateAsBool());
+//                    initialStates = initialStates * temporary;
+//                }
+//                
+//                // Integer variables
+//                for (uint_fast64_t j = 0; j < module.getNumberOfIntegerVariables(); ++j) {
+//                    storm::prism::IntegerVariable const& integerVariable = module.getIntegerVariables().at(j);
+//                    temporary = generationInfo.manager->getEncoding(integerVariable.getName(), integerVariable.getInitialValueExpression().evaluateAsInt());
+//                    initialStates = initialStates * temporary;
+//                }
+//            }
+//            
+//            return initialStates;
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        storm::dd::Dd<Type> SymbolicModelAdapter<Type>::performReachability(GenerationInformation & generationInfo, storm::dd::Dd<Type> const& systemDd, storm::dd::Dd<Type> const& initialStateDd) {
+//            
+//            // Initialize the clock.
+//            auto clock = std::chrono::high_resolution_clock::now();
+//            
+//            
+//            storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
+//            storm::dd::Dd<Type> S;
+//            storm::dd::Dd<Type> U;
+//            
+//            // Get initial state
+//            storm::dd::Dd<Type> reachableStates = initialStateDd;
+//            
+//            // Copy current state
+//            storm::dd::Dd<Type> newReachableStates = reachableStates;
+//            
+//            std::set<std::string> abstractVariables = std::set<std::string>();
+//            
+//            if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
+//                for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i) {
+//                    // Synchronizing variables
+//                    if (systemDd.containsMetaVariable("sync" + std::to_string(i))) {
+//                        abstractVariables.insert("sync" + std::to_string(i));
+//                    }
+//                }
+//                for (uint_fast64_t i = 1; i <= generationInfo.numberOfNondetVariables; ++i) {
+//                    // Nondet. variables
+//                    if (systemDd.containsMetaVariable("nondet" + std::to_string(i))) {
+//                        abstractVariables.insert("nondet" + std::to_string(i));
+//                    }
+//                }
+//            }
+//            
+//            // Create system BDD
+//            storm::dd::Dd<Type> systemBdd = systemDd.notZero();
+//            
+//            // For MDPs, we need to abstract from the nondeterminism variables, but we can do so prior to the
+//            // reachability analysis.
+//            if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
+//                // Abstract from synchronizing and nondet. variables (MDPs)
+//                systemBdd = systemBdd.existsAbstract(abstractVariables);
+//            }
+//            
+//            // Initialize variables and choose option
+//            bool changed;
+//            int iter = 0;
+//            int option = storm::settings::adapterSettings().getReachabilityMethod();
+//            
+//            //TODO: Name reachability options.
+//            std::cout << "Reachability option: " << option << std::endl;
+//            
+//            if (option == 3 || option == 4){
+//                
+//                S = storm::dd::Dd<Type>(initialStateDd);
+//                U = storm::dd::Dd<Type>(initialStateDd);
+//                
+//                generationInfo.globalSystemDds.independentActionDd.commandsDd = generationInfo.globalSystemDds.independentActionDd.commandsDd.notZero();
+//                generationInfo.globalSystemDds.independentActionDd.commandsDd = generationInfo.globalSystemDds.independentActionDd.commandsDd.existsAbstract(abstractVariables);
+//                
+//                for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i) {
+//                    generationInfo.globalSystemDds.synchronizingActionDds[i].commandsDd = generationInfo.globalSystemDds.synchronizingActionDds[i].commandsDd.notZero();
+//                    generationInfo.globalSystemDds.synchronizingActionDds[i].commandsDd = generationInfo.globalSystemDds.synchronizingActionDds[i].commandsDd.existsAbstract(abstractVariables);
+//                }
+//            }
+//            
+//            // Perform updates until nothing changes
+//            do {
+//                if (option == 1){
+//                    iter++;
+//                    changed = true;
+//                    
+//                    newReachableStates = newReachableStates * systemBdd;
+//                    
+//                    // Abstract from row meta variables
+//                    newReachableStates = newReachableStates.existsAbstract(generationInfo.rowMetaVariableNames);
+//                    
+//                    // Swap column variables to row variables
+//                    newReachableStates.swapVariables(generationInfo.metaVariablePairs);
+//                    
+//                    newReachableStates = newReachableStates * (!reachableStates);
+//                    
+//                    // Check if something has changed
+//                    if (newReachableStates.isZero()) {
+//                        changed = false;
+//                    }
+//                    
+//                    // Update reachableStates DD
+//                    reachableStates = reachableStates + newReachableStates;
+//                    
+//                } else if (option == 2) {
+//                    iter++;
+//                    changed = false;
+//                    
+//                    newReachableStates = newReachableStates * systemBdd;
+//                    
+//                    // Abstract from row meta variables
+//                    newReachableStates = newReachableStates.existsAbstract(generationInfo.rowMetaVariableNames);
+//                    
+//                    // Swap column variables to row variables
+//                    newReachableStates.swapVariables(generationInfo.metaVariablePairs);
+//                    
+//                    newReachableStates = newReachableStates || reachableStates;
+//                    
+//                    // Check if something has changed
+//                    if (newReachableStates != reachableStates) {
+//                        changed = true;
+//                    }
+//                    
+//                    // Update reachableStates DD
+//                    reachableStates = newReachableStates;
+//                    
+//                } else if (option == 3) {
+//                    iter++;
+//                    changed = true;
+//                    
+//                    newReachableStates = generationInfo.manager->getZero();
+//                    
+//                    temporary = U * generationInfo.globalSystemDds.independentActionDd.commandsDd;
+//                    newReachableStates = newReachableStates.existsAbstract(generationInfo.rowMetaVariableNames);
+//                    newReachableStates.swapVariables(generationInfo.metaVariablePairs);
+//                    newReachableStates = temporary;
+//                    
+//                    for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i) {
+//                        temporary = U * generationInfo.globalSystemDds.synchronizingActionDds[i].commandsDd;
+//                        temporary = temporary.existsAbstract(generationInfo.rowMetaVariableNames);
+//                        temporary.swapVariables(generationInfo.metaVariablePairs);
+//                        newReachableStates = newReachableStates || temporary;
+//                    }
+//                    
+//                    newReachableStates = newReachableStates.existsAbstract(generationInfo.rowMetaVariableNames);
+//                    newReachableStates.swapVariables(generationInfo.metaVariablePairs);
+//                    U = U || newReachableStates;
+//                    
+//                    if (U == S){
+//                        changed = false;
+//                        reachableStates = S;
+//                        break;
+//                    }
+//                    
+//                    S = S || U;
+//                    
+//                }
+//                else if (option == 4) {
+//                    iter++;
+//                    changed = true;
+//                    
+//                    temporary = U * generationInfo.globalSystemDds.independentActionDd.commandsDd;
+//                    temporary = temporary.existsAbstract(generationInfo.rowMetaVariableNames);
+//                    temporary.swapVariables(generationInfo.metaVariablePairs);
+//                    U = U || temporary;
+//                    
+//                    for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i) {
+//                        temporary = U * generationInfo.globalSystemDds.synchronizingActionDds[i].commandsDd;
+//                        temporary = temporary.existsAbstract(generationInfo.rowMetaVariableNames);
+//                        temporary.swapVariables(generationInfo.metaVariablePairs);
+//                        U = U || temporary;
+//                    }
+//                    
+//                    U = U * (!S);
+//                    
+//                    S = S + U;
+//                    
+//                    if (U.isZero()){
+//                        changed = false;
+//                        reachableStates = S;
+//                    }
+//                    
+//                }
+//            } while (changed);
+//            
+//            std::cout << "Performed reachability (" << iter << " iterations) in " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - clock).count() << "ms." << std::endl;
+//            
+//            return reachableStates;
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        storm::dd::Dd<Type> SymbolicModelAdapter<Type>::findDeadlocks(GenerationInformation const & generationInfo, storm::dd::Dd<Type> systemDd, storm::dd::Dd<Type> const& reachableStatesDd) {
+//            
+//            // Initialize the clock.
+//            auto clock = std::chrono::high_resolution_clock::now();
+//            
+//            storm::dd::Dd<Type> systemBdd = systemDd.notZero();
+//            
+//            std::set<std::string> abstractVariables = std::set<std::string>();
+//            
+//            if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
+//                for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i) {
+//                    // Synchronizing variables
+//                    if (systemDd.containsMetaVariable("sync" + std::to_string(i))) {
+//                        abstractVariables.insert("sync" + std::to_string(i));
+//                    }
+//                }
+//                for (uint_fast64_t i = 1; i <= generationInfo.numberOfNondetVariables; ++i) {
+//                    // Nondet. variables
+//                    if (systemDd.containsMetaVariable("nondet" + std::to_string(i))) {
+//                        abstractVariables.insert("nondet" + std::to_string(i));
+//                    }
+//                }
+//            }
+//            
+//            // Find states with at least one transition
+//            systemBdd = systemBdd.existsAbstract(generationInfo.columnMetaVariableNames);
+//            
+//            // For MDPs, we need to abstract from the nondeterminism variables
+//            if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
+//                // Abstract from synchronizing and nondet. variables (MDPs)
+//                systemBdd = systemBdd.existsAbstract(abstractVariables);
+//            }
+//            
+//            systemBdd = reachableStatesDd * (!systemBdd);
+//            
+//            std::cout << "Deadlocks: " << systemBdd.getNonZeroCount() << " fixed." << std::endl;
+//            
+//            // Check if there are deadlocks
+//            if (!systemBdd.isZero()){
+//                
+//                storm::dd::Dd<Type> temporary = generationInfo.manager->getOne();
+//                
+//                // Get all variable identities
+//                for (auto variable : generationInfo.rowMetaVariableNames) {
+//                    temporary = temporary * generationInfo.variableToIdentityDecisionDiagramMap.at(variable);
+//                }
+//                
+//                // Add synchronizing and nondet. variables to identity for MDPs (all set to 0)
+//                if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
+//                    for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i) {
+//                        // Synchronizing variables
+//                        if (systemDd.containsMetaVariable("sync" + std::to_string(i))) {
+//                            temporary = temporary * generationInfo.manager->getEncoding("sync" + std::to_string(i),0);
+//                        }
+//                    }
+//                    for (uint_fast64_t i = 1; i <= generationInfo.numberOfNondetVariables; ++i) {
+//                        // Nondet. variables
+//                        if (systemDd.containsMetaVariable("nondet" + std::to_string(i))) {
+//                            temporary = temporary * generationInfo.manager->getEncoding("nondet" + std::to_string(i), 0);
+//                        }
+//                    }
+//                }
+//                
+//                temporary = temporary * systemBdd;
+//                
+//                // Add self-loops to transition matrix
+//                systemDd = systemDd + temporary;
+//            }
+//            
+//            std::cout << "Fixed deadlocks in " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - clock).count() << "ms." << std::endl;
+//            
+//            return systemDd;
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        std::pair<std::vector<storm::dd::Dd<Type>>, std::vector<storm::dd::Dd<Type>>> SymbolicModelAdapter<Type>::computeRewards(GenerationInformation const & generationInfo, SystemComponentDecisionDiagram<Type> const& systemDds) {
+//            
+//            // Get number of reward modules and synchronizing actions
+//            uint_fast64_t numberOfRewardModules = generationInfo.program.getRewardModels().size();
+//            uint_fast64_t numberOfSynchronizingActions = generationInfo.allSynchronizingActions.size();
+//            
+//            // State reward DD
+//            std::vector<storm::dd::Dd<Type>> stateRewardsDds = std::vector<storm::dd::Dd<Type>>(numberOfRewardModules);
+//            // Transition reward DD
+//            std::vector<storm::dd::Dd<Type>> transitionRewardsDds = std::vector<storm::dd::Dd<Type>>(numberOfRewardModules);
+//            
+//            // Initialize DDs
+//            for (uint_fast64_t i = 0; i < numberOfRewardModules; ++i) {
+//                stateRewardsDds[i] = generationInfo.manager->getConstant(0);
+//                transitionRewardsDds[i] = generationInfo.manager->getConstant(0);
+//            }
+//            
+//            storm::dd::Dd<Type> statesDd = generationInfo.manager->getZero();
+//            storm::dd::Dd<Type> rewardsDd = generationInfo.manager->getZero();
+//            storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
+//            
+//            // Loop through all reward models
+//            for (uint_fast64_t i = 0; i < numberOfRewardModules; ++i) {
+//                storm::prism::RewardModel const& currentRewardModule = generationInfo.program.getRewardModels().at(i);
+//                
+//                // State rewards 
+//                for (auto stateReward : currentRewardModule.getStateRewards()) {
+//                    
+//                    // Translate state and reward expression
+//                    statesDd = storm::adapters::SymbolicExpressionAdapter<Type>::translateExpression(stateReward.getStatePredicateExpression().getBaseExpressionPointer(), generationInfo.program, generationInfo.manager);
+//                    rewardsDd = storm::adapters::SymbolicExpressionAdapter<Type>::translateExpression(stateReward.getRewardValueExpression().getBaseExpressionPointer(), generationInfo.program, generationInfo.manager);
+//                    
+//                    // Restrict rewards to states
+//                    temporary = statesDd * rewardsDd;
+//                    
+//                    // Check for negative rewards
+//                    if (temporary.getMin() < 0){
+//                        LOG4CPLUS_WARN(logger, "Negative state reward in reward model " << (i + 1) << ".");
+//                    }
+//                    
+//                    if(temporary.isZero()) {
+//                        LOG4CPLUS_WARN(logger, "Only zero rewards in reward model " << (i + 1) << ".");
+//                    }
+//                    
+//                    // Combine all rewards
+//                    stateRewardsDds[i] = stateRewardsDds[i] + temporary;
+//                }
+//                
+//                // Transition rewards 
+//                for (auto transitionReward : currentRewardModule.getTransitionRewards()) {
+//                    
+//                    // Translate state and reward expression
+//                    statesDd = storm::adapters::SymbolicExpressionAdapter<Type>::translateExpression(transitionReward.getStatePredicateExpression().getBaseExpressionPointer(), generationInfo.program, generationInfo.manager);
+//                    rewardsDd = storm::adapters::SymbolicExpressionAdapter<Type>::translateExpression(transitionReward.getRewardValueExpression().getBaseExpressionPointer(), generationInfo.program, generationInfo.manager);
+//                    
+//                    // Get action name of the transition
+//                    std::string const& rewardAction = transitionReward.getActionName();
+//                    
+//                    if (rewardAction == "") {
+//                        // Take independent action module
+//                        temporary = systemDds.independentActionDd.commandsDd;
+//                    }else {
+//                        // Get module corresponding to the reward action
+//                        for (uint_fast64_t j = 0; j < numberOfSynchronizingActions; ++j) {
+//                            if (generationInfo.allSynchronizingActions[j] == rewardAction) {
+//                                temporary = systemDds.synchronizingActionDds[j].commandsDd;
+//                                break;
+//                            }
+//                        }
+//                    }
+//                    
+//                    // Convert to BDD for MDPs (DTMC need exact values for scaling)
+//                    if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
+//                        temporary = temporary.notZero();
+//                    }
+//                    
+//                    // Restrict to states and multiply reward values
+//                    temporary = temporary * statesDd;
+//                    temporary = temporary * rewardsDd;
+//                    
+//                    // Check for negative rewards
+//                    if (temporary.getMin() < 0){
+//                        LOG4CPLUS_WARN(logger, "Negative transition reward in reward model " << (i + 1) << ".");
+//                    }
+//                    
+//                    // Combine all rewards
+//                    transitionRewardsDds[i] = transitionRewardsDds[i] + temporary;
+//                }
+//            }
+//            
+//            // Scale transition rewards for DTMCs
+//            if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) {
+//                for (uint_fast64_t i = 0; i < generationInfo.program.getRewardModels().size(); ++i){
+//                    // Divide transition rewards through transition matrix
+//                    transitionRewardsDds[i] = transitionRewardsDds[i] / systemDds.independentActionDd.commandsDd;
+//                }
+//            }
+//            
+//            // Pair to store state and transition rewards
+//            return std::make_pair(stateRewardsDds, transitionRewardsDds);
+//        }
+//        
+//        template <storm::dd::DdType Type>
+//        storm::dd::Dd<Type> SymbolicModelAdapter<Type>::computeTransitionAction(GenerationInformation const & generationInfo, SystemComponentDecisionDiagram<Type> const& systemDds){
+//            
+//            // Transition actions DD
+//            storm::dd::Dd<Type> transitionActionDd = generationInfo.manager->getZero();
+//            storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
+//            
+//            // Store action labels for each transition (0 iff no action/tau/epsilon)
+//            storm::dd::Dd<Type> commandsBdd = generationInfo.manager->getZero();
+//            for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i){
+//                // Get action transition matrix as BDD
+//                commandsBdd = systemDds.synchronizingActionDds[i].commandsDd.notZero();
+//                commandsBdd = commandsBdd.existsAbstract(generationInfo.columnMetaVariableNames);
+//                
+//                // Add action index
+//                temporary = commandsBdd * generationInfo.manager->getConstant(i + 1);
+//                transitionActionDd = transitionActionDd + temporary;
+//            }
+//            
+//            return transitionActionDd;
+//        }
+        
+        // Explicitly instantiate the symbolic expression adapter
+        template class DdPrismModelBuilder<storm::dd::DdType::CUDD>;
+        
+    } // namespace adapters
+} // namespace storm
+
+
diff --git a/src/builder/DdPrismModelBuilder.h b/src/builder/DdPrismModelBuilder.h
new file mode 100644
index 000000000..03283d55d
--- /dev/null
+++ b/src/builder/DdPrismModelBuilder.h
@@ -0,0 +1,282 @@
+#ifndef STORM_BUILDER_DDPRISMMODELBUILDER_H_
+#define STORM_BUILDER_DDPRISMMODELBUILDER_H_
+
+#include <map>
+#include <boost/optional.hpp>
+
+#include "src/logic/Formulas.h"
+#include "src/storage/prism/Program.h"
+#include "src/adapters/DdExpressionAdapter.h"
+
+namespace storm {
+    namespace adapters {
+        
+        template <storm::dd::DdType Type>
+        class DdPrismModelBuilder {
+        public:
+            struct Options {
+                /*!
+                 * Creates an object representing the default building options.
+                 */
+                Options();
+                
+                /*! Creates an object representing the suggested building options assuming that the given formula is the
+                 * only one to check.
+                 *
+                 * @param formula The formula based on which to choose the building options.
+                 */
+                Options(storm::logic::Formula const& formula);
+                
+                /*!
+                 * Sets the constants definitions from the given string. The string must be of the form 'X=a,Y=b,Z=c',
+                 * etc. where X,Y,Z are the variable names and a,b,c are the values of the constants.
+                 *
+                 * @param program The program managing the constants that shall be defined. Note that the program itself
+                 * is not modified whatsoever.
+                 * @param constantDefinitionString The string from which to parse the constants' values.
+                 */
+                void addConstantDefinitionsFromString(storm::prism::Program const& program, std::string const& constantDefinitionString);
+                
+                // A flag that indicates whether or not a reward model is to be built.
+                bool buildRewards;
+                
+                // An optional string, that, if given, indicates which of the reward models is to be built.
+                boost::optional<std::string> rewardModelName;
+                
+                // An optional mapping that, if given, contains defining expressions for undefined constants.
+                boost::optional<std::map<storm::expressions::Variable, storm::expressions::Expression>> constantDefinitions;
+                
+                // An optional set of labels that, if given, restricts the labels that are built.
+                boost::optional<std::set<std::string>> labelsToBuild;
+                
+                // An optional set of expressions for which labels need to be built.
+                boost::optional<std::vector<storm::expressions::Expression>> expressionLabels;
+            };
+            
+            /*!
+             * Translates the given program into a model that stores the transition relation as a decision diagram.
+             *
+             * @param program The program to translate.
+             */
+            static void translateProgram(storm::prism::Program const& program, Options const& options = Options());
+            
+        private:
+            // This structure can store the decision diagrams representing a particular action.
+            struct ActionDecisionDiagram {
+                ActionDecisionDiagram(storm::dd::DdManager<Type> const& manager) : guardDd(manager.getZero()), transitionsDd(manager.getZero()), numberOfUsedNondeterminismVariables(0) {
+                    // Intentionally left empty.
+                }
+                
+                // The guard of the action.
+                storm::dd::Dd<Type> guardDd;
+                
+                // The actual transitions (source and target states).
+                storm::dd::Dd<Type> transitionsDd;
+                
+                // The number of variables that are used to encode the nondeterminism.
+                uint_fast64_t numberOfUsedNondeterminismVariables;
+            };
+            
+            // This structure holds all decision diagrams related to a module.
+            struct ModuleDecisionDiagram {
+                ModuleDecisionDiagram(storm::dd::DdManager<Type> const& manager) : independantAction(manager), synchronizingActionToDecisionDiagramMap(), identity(manager.getZero()) {
+                    // Intentionally left empty.
+                }
+                
+                // The decision diagram for the independant action.
+                ActionDecisionDiagram independantAction;
+                
+                // A mapping from synchronizing action indices to the decision diagram.
+                std::map<uint_fast64_t, ActionDecisionDiagram> synchronizingActionToDecisionDiagramMap;
+                
+                // A decision diagram that represents the identity of this module.
+                storm::dd::Dd<Type> identity;
+            };
+            
+            /*!
+             * Structure to store all information required to generate the model from the program.
+             */
+            class GenerationInformation {
+                GenerationInformation(storm::prism::Program const& program) : program(program), manager(std::make_shared<storm::dd::DdManager<Type>>()), rowMetaVariables(), columnMetaVariables(), metaVariablePairs(), numberOfNondetVariables(0), variableToIdentityMap(), moduleToIdentityMap(), allSynchronizingActionIndices(), labelToStateDdMap() {
+                    // Initializes variables and identity DDs.
+                    createMetaVariables();
+                    createIdentities();
+                }
+                
+            private:
+                /*!
+                 * Creates the required meta variables.
+                 */
+                void createMetaVariables();
+                
+                /*!
+                 * Creates identity DDs for all variables and all modules.
+                 */
+                void createIdentities();
+                
+                // The program that is currently translated.
+                storm::prism::Program const& program;
+                
+                // The manager used to build the decision diagrams.
+                std::shared_ptr<storm::dd::DdManager<Type>> manager;
+
+                // The meta variables for the row encoding.
+                std::vector<storm::expressions::Variable> rowMetaVariables;
+                
+                // The meta variables for the column encoding.
+                std::vector<storm::expressions::Variable> columnMetaVariables;
+
+                // Pairs of meta variables (row, column).
+                std::vector<std::pair<storm::expressions::Variable, storm::expressions::Variable>> metaVariablePairs;
+
+                // Number of variables used to encode the nondeterminism.
+                uint_fast64_t numberOfNondetVariables;
+                
+                // DDs representing the identity for each variable.
+                std::map<storm::expressions::Variable, storm::dd::Dd<Type>> variableToIdentityMap;
+                
+                // DDs representing the identity for each module (index).
+                std::map<uint_fast64_t, storm::dd::Dd<Type>> moduleToIdentityMap;
+                
+                // All synchronizing actions
+                std::set<uint_fast64_t> allSynchronizingActionIndices;
+                
+                // DDs representing the identity matrix for each module
+                std::unordered_map<std::string, storm::dd::Dd<Type>> labelToStateDdMap;
+            };
+            
+        private:
+            
+//            /*!
+//             * Creates system DD (full parallel)
+//             *
+//             * @return A DD representing the whole system
+//             */
+//            static storm::dd::Dd<Type> createSystemDecisionDiagramm(GenerationInformation & generationInfo);
+//            
+//            /*!
+//             * Combines all DDs to one DD (including independent/synchronized actions)
+//             *
+//             * @param systemDds DDs representing the whole system
+//             * @return System DDs with combined independent/synchronized actions
+//             */
+//            static SystemComponentDecisionDiagram<Type> combineSystem(GenerationInformation const & generationInfo, SystemComponentDecisionDiagram<Type> systemDds);
+//            
+//            /*!
+//             * Combines 2 modules with/without synchronizing actions
+//             *
+//             * @param synchronizing Synchronizing actions or not
+//             * @param module1 First module
+//             * @param module1 Second module
+//             * @param identity1 Identity matrix of first module
+//             * @param identity2 Identity matrix of second module
+//             * @return A module DD representing the combination of both modules
+//             */
+//            static ModuleDecisionDiagram<Type> combineModules(GenerationInformation const & generationInfo, bool synchronizing, ModuleDecisionDiagram<Type> moduleDd1, ModuleDecisionDiagram<Type> moduleDd2, storm::dd::Dd<Type> const& identityDd1, storm::dd::Dd<Type> const& identityDd2);
+//            
+//            /*!
+//             * Combines 2 modules and solves non-determinism (MDP)
+//             *
+//             * @param module1 First module
+//             * @param module1 Second module
+//             * @return A module DD representing the combination of both modules
+//             */
+//            static ModuleDecisionDiagram<Type> combineModulesMDP(GenerationInformation const & generationInfo, ModuleDecisionDiagram<Type> moduleDd1, ModuleDecisionDiagram<Type> moduleDd2);
+//            
+//            /*!
+//             * Creates a system component DD (module)
+//             *
+//             * @param module Module
+//             * @param usedNondetVariablesVector Number of used nondet. variables
+//             * @return A system component DD storing all required module information
+//             */
+//            static SystemComponentDecisionDiagram<Type> createSystemComponentDecisionDiagramm(GenerationInformation const & generationInfo, storm::prism::Module const & module, std::vector<uint_fast64_t> usedNondetVariablesVector);
+//            
+//            /*!
+//             * Combines commands (with guards) to a module DD (DTMC)
+//             *
+//             * @param numberOfCommands Number of commands in the current module
+//             * @param commandDds DDs containing all updates for each command
+//             * @param guardDds Guard DDs for each command
+//             * @return A DD representing the module.
+//             */
+//            static ModuleDecisionDiagram<Type> combineCommandsDTMC(std::shared_ptr<storm::dd::DdManager<Type>> const & manager, uint_fast64_t numberOfCommands, std::vector<storm::dd::Dd<Type>> const& commandDds, std::vector<storm::dd::Dd<Type>> const& guardDds);
+//            
+//            /*!
+//             * Combines commands (with guards) to a module DD (MDP)
+//             *
+//             * @param numberOfCommands Number of commands in the current module
+//             * @param commandDds DDs containing all updates for each command
+//             * @param guardDds Guard DDs for each command
+//             * @param usedNondetVariables Number of used nondet. variables
+//             * @return A DD representing the module.
+//             */
+//            static ModuleDecisionDiagram<Type> combineCommandsMDP(std::shared_ptr<storm::dd::DdManager<Type>> const & manager, uint_fast64_t numberOfCommands, std::vector<storm::dd::Dd<Type>> const& commandDds, std::vector<storm::dd::Dd<Type>> const& guardDds, uint_fast64_t usedNondetVariables);
+//            
+//            /*!
+//             * Creates a module DD
+//             *
+//             * @param module Module
+//             * @param synchronizingAction Name of the synchronizing action ("" = no synchronization)
+//             * @param usedNondetVariables Number of used nondet. variables
+//             * @return A DD representing the module (with/without synchronized actions).
+//             */
+//            static ModuleDecisionDiagram<Type> createModuleDecisionDiagramm(GenerationInformation const & generationInfo, storm::prism::Module const& module, std::string const& synchronizingAction, uint_fast64_t usedNondetVariables);
+//            
+//            /*!
+//             * Creates a command DD
+//             *
+//             * @param module Current module
+//             * @param guard Command guard
+//             * @param update Command expression
+//             * @return A DD representing the command.
+//             */
+//            static storm::dd::Dd<Type> createCommandDecisionDiagramm(GenerationInformation const & generationInfo, storm::prism::Module const& module, storm::dd::Dd<Type> const& guard, storm::prism::Command const& command);
+//            
+//            /*!
+//             * Creates an update DD
+//             *
+//             * @param module Current module
+//             * @param guard Command guard
+//             * @param update Update expression
+//             * @return A DD representing the update.
+//             */
+//            static storm::dd::Dd<Type> createUpdateDecisionDiagramm(GenerationInformation const & generationInfo, storm::prism::Module const& module, storm::dd::Dd<Type> const& guard, storm::prism::Update const& update);
+//            
+//            /*!
+//             * Creates initial state DD
+//             *
+//             * @return A DD representing the initial state.
+//             */
+//            static storm::dd::Dd<Type> getInitialStateDecisionDiagram(GenerationInformation const & generationInfo);
+//            
+//            /*!
+//             * Calculates the reachable states of the given transition matrix
+//             *
+//             * @param systemDd The transition matrix DD
+//             * @param initialStateDd All initial states
+//             * @return A DD representing all reachable states
+//             */
+//            static storm::dd::Dd<Type> performReachability(GenerationInformation & generationInfo, storm::dd::Dd<Type> const& systemDd, storm::dd::Dd<Type> const& initialStateDd);
+//            
+//            /*!
+//             * Adds a self-loop to deadlock states
+//             *
+//             * @param systemDd The given DD
+//             * @param reachableStatesDd DD representing all reachable states
+//             * @return A DD with fixed deadlocks.
+//             */
+//            static storm::dd::Dd<Type> findDeadlocks(GenerationInformation const & generationInfo, storm::dd::Dd<Type> systemDd, storm::dd::Dd<Type> const& reachableStatesDd);
+//            
+//            /*!
+//             * Computes state and transition rewards
+//             *
+//             * @param systemDds System DDs
+//             */
+//            static std::pair<std::vector<storm::dd::Dd<Type>>, std::vector<storm::dd::Dd<Type>>> computeRewards(GenerationInformation const & generationInfo, SystemComponentDecisionDiagram<Type> const& systemDds);
+        };
+        
+    } // namespace adapters
+} // namespace storm
+
+#endif /* STORM_BUILDER_DDPRISMMODELBUILDER_H_ */
diff --git a/src/builder/ExplicitPrismModelBuilder.cpp b/src/builder/ExplicitPrismModelBuilder.cpp
index 5ac83af33..974d9d306 100644
--- a/src/builder/ExplicitPrismModelBuilder.cpp
+++ b/src/builder/ExplicitPrismModelBuilder.cpp
@@ -7,6 +7,7 @@
 #include "src/models/Mdp.h"
 #include "src/models/Ctmdp.h"
 
+#include "src/utility/prism.h"
 #include "src/utility/macros.h"
 #include "src/exceptions/WrongFormatException.h"
 
@@ -54,13 +55,11 @@ namespace storm {
             // Intentionally left empty.
         }
 
-
         template <typename ValueType, typename IndexType>
         ExplicitPrismModelBuilder<ValueType, IndexType>::Options::Options() : buildCommandLabels(false), buildRewards(false), rewardModelName(), constantDefinitions() {
             // Intentionally left empty.
         }
-            
-
+        
         template <typename ValueType, typename IndexType>
         ExplicitPrismModelBuilder<ValueType, IndexType>::Options::Options(storm::logic::Formula const& formula) : buildCommandLabels(false), buildRewards(formula.containsRewardOperator()), rewardModelName(), constantDefinitions(), labelsToBuild(std::set<std::string>()), expressionLabels(std::vector<storm::expressions::Expression>()) {
             // Extract all the labels used in the formula.
diff --git a/src/storage/dd/CuddDd.cpp b/src/storage/dd/CuddDd.cpp
index 6e474bebf..25c99ced1 100644
--- a/src/storage/dd/CuddDd.cpp
+++ b/src/storage/dd/CuddDd.cpp
@@ -12,7 +12,7 @@
 
 namespace storm {
     namespace dd {
-        Dd<DdType::CUDD>::Dd(std::shared_ptr<DdManager<DdType::CUDD>> ddManager, ADD cuddAdd, std::set<storm::expressions::Variable> const& containedMetaVariables) : ddManager(ddManager), cuddAdd(cuddAdd), containedMetaVariables(containedMetaVariables) {
+        Dd<DdType::CUDD>::Dd(std::shared_ptr<DdManager<DdType::CUDD> const> ddManager, ADD cuddAdd, std::set<storm::expressions::Variable> const& containedMetaVariables) : ddManager(ddManager), cuddAdd(cuddAdd), containedMetaVariables(containedMetaVariables) {
             // Intentionally left empty.
         }
         
@@ -808,7 +808,7 @@ namespace storm {
             this->getContainedMetaVariables().erase(metaVariable);
         }
         
-        std::shared_ptr<DdManager<DdType::CUDD>> Dd<DdType::CUDD>::getDdManager() const {
+        std::shared_ptr<DdManager<DdType::CUDD> const> Dd<DdType::CUDD>::getDdManager() const {
             return this->ddManager;
         }
         
diff --git a/src/storage/dd/CuddDd.h b/src/storage/dd/CuddDd.h
index 2a56b96a5..0fa04f574 100644
--- a/src/storage/dd/CuddDd.h
+++ b/src/storage/dd/CuddDd.h
@@ -563,7 +563,7 @@ namespace storm {
              *
              * A pointer to the manager that is responsible for this DD.
              */
-            std::shared_ptr<DdManager<DdType::CUDD>> getDdManager() const;
+            std::shared_ptr<DdManager<DdType::CUDD> const> getDdManager() const;
             
             /*!
              * Retrieves an iterator that points to the first meta variable assignment with a non-zero function value.
@@ -604,6 +604,7 @@ namespace storm {
             storm::expressions::Expression getMintermExpression() const;
             
             friend std::ostream & operator<<(std::ostream& out, const Dd<DdType::CUDD>& dd);
+            
         private:
             /*!
              * Retrieves a reference to the CUDD ADD object associated with this DD.
@@ -659,7 +660,7 @@ namespace storm {
              * @param cuddAdd The CUDD ADD to store.
              * @param containedMetaVariables The meta variables that appear in the DD.
              */
-            Dd(std::shared_ptr<DdManager<DdType::CUDD>> ddManager, ADD cuddAdd, std::set<storm::expressions::Variable> const& containedMetaVariables = std::set<storm::expressions::Variable>());
+            Dd(std::shared_ptr<DdManager<DdType::CUDD> const> ddManager, ADD cuddAdd, std::set<storm::expressions::Variable> const& containedMetaVariables = std::set<storm::expressions::Variable>());
             
             /*!
              * Helper function to convert the DD into a (sparse) matrix.
@@ -723,7 +724,7 @@ namespace storm {
             std::vector<uint_fast64_t> getSortedVariableIndices() const;
             
             // A pointer to the manager responsible for this DD.
-            std::shared_ptr<DdManager<DdType::CUDD>> ddManager;
+            std::shared_ptr<DdManager<DdType::CUDD> const> ddManager;
             
             // The ADD created by CUDD.
             ADD cuddAdd;
diff --git a/src/storage/dd/CuddDdForwardIterator.cpp b/src/storage/dd/CuddDdForwardIterator.cpp
index b37ba1a11..74f29d174 100644
--- a/src/storage/dd/CuddDdForwardIterator.cpp
+++ b/src/storage/dd/CuddDdForwardIterator.cpp
@@ -9,7 +9,7 @@ namespace storm {
             // Intentionally left empty.
         }
         
-        DdForwardIterator<DdType::CUDD>::DdForwardIterator(std::shared_ptr<DdManager<DdType::CUDD>> ddManager, DdGen* generator, int* cube, double value, bool isAtEnd, std::set<storm::expressions::Variable> const* metaVariables, bool enumerateDontCareMetaVariables) : ddManager(ddManager), generator(generator), cube(cube), value(value), isAtEnd(isAtEnd), metaVariables(metaVariables), enumerateDontCareMetaVariables(enumerateDontCareMetaVariables), cubeCounter(), relevantDontCareDdVariables(), currentValuation(ddManager->getExpressionManager().getSharedPointer()) {
+        DdForwardIterator<DdType::CUDD>::DdForwardIterator(std::shared_ptr<DdManager<DdType::CUDD> const> ddManager, DdGen* generator, int* cube, double value, bool isAtEnd, std::set<storm::expressions::Variable> const* metaVariables, bool enumerateDontCareMetaVariables) : ddManager(ddManager), generator(generator), cube(cube), value(value), isAtEnd(isAtEnd), metaVariables(metaVariables), enumerateDontCareMetaVariables(enumerateDontCareMetaVariables), cubeCounter(), relevantDontCareDdVariables(), currentValuation(ddManager->getExpressionManager().getSharedPointer()) {
             // If the given generator is not yet at its end, we need to create the current valuation from the cube from
             // scratch.
             if (!this->isAtEnd) {
diff --git a/src/storage/dd/CuddDdForwardIterator.h b/src/storage/dd/CuddDdForwardIterator.h
index aad7db67c..4c7e97364 100644
--- a/src/storage/dd/CuddDdForwardIterator.h
+++ b/src/storage/dd/CuddDdForwardIterator.h
@@ -85,7 +85,7 @@ namespace storm {
              * @param enumerateDontCareMetaVariables If set to true, all meta variable assignments are enumerated, even
              * if a meta variable does not at all influence the the function value.
              */
-            DdForwardIterator(std::shared_ptr<DdManager<DdType::CUDD>> ddManager, DdGen* generator, int* cube, double value, bool isAtEnd, std::set<storm::expressions::Variable> const* metaVariables = nullptr, bool enumerateDontCareMetaVariables = true);
+            DdForwardIterator(std::shared_ptr<DdManager<DdType::CUDD> const> ddManager, DdGen* generator, int* cube, double value, bool isAtEnd, std::set<storm::expressions::Variable> const* metaVariables = nullptr, bool enumerateDontCareMetaVariables = true);
             
             /*!
              * Recreates the internal information when a new cube needs to be treated.
@@ -98,7 +98,7 @@ namespace storm {
             void treatNextInCube();
             
             // The manager responsible for the meta variables (and therefore the underlying DD).
-            std::shared_ptr<DdManager<DdType::CUDD>> ddManager;
+            std::shared_ptr<DdManager<DdType::CUDD> const> ddManager;
             
             // The CUDD generator used to enumerate the cubes of the DD.
             DdGen* generator;
diff --git a/src/storage/dd/CuddDdManager.cpp b/src/storage/dd/CuddDdManager.cpp
index 32a25ae3e..933b95af6 100644
--- a/src/storage/dd/CuddDdManager.cpp
+++ b/src/storage/dd/CuddDdManager.cpp
@@ -37,19 +37,19 @@ namespace storm {
             }
         }
         
-        Dd<DdType::CUDD> DdManager<DdType::CUDD>::getOne() {
+        Dd<DdType::CUDD> DdManager<DdType::CUDD>::getOne() const {
             return Dd<DdType::CUDD>(this->shared_from_this(), cuddManager.addOne());
         }
         
-        Dd<DdType::CUDD> DdManager<DdType::CUDD>::getZero() {
+        Dd<DdType::CUDD> DdManager<DdType::CUDD>::getZero() const {
             return Dd<DdType::CUDD>(this->shared_from_this(), cuddManager.addZero());
         }
         
-        Dd<DdType::CUDD> DdManager<DdType::CUDD>::getConstant(double value) {
+        Dd<DdType::CUDD> DdManager<DdType::CUDD>::getConstant(double value) const {
             return Dd<DdType::CUDD>(this->shared_from_this(), cuddManager.constant(value));
         }
         
-        Dd<DdType::CUDD> DdManager<DdType::CUDD>::getEncoding(storm::expressions::Variable const& variable, int_fast64_t value) {
+        Dd<DdType::CUDD> DdManager<DdType::CUDD>::getEncoding(storm::expressions::Variable const& variable, int_fast64_t value) const {
             DdMetaVariable<DdType::CUDD> const& metaVariable = this->getMetaVariable(variable);
             
             STORM_LOG_THROW(value >= metaVariable.getLow() && value <= metaVariable.getHigh(), storm::exceptions::InvalidArgumentException, "Illegal value " << value << " for meta variable '" << variable.getName() << "'.");
@@ -77,7 +77,7 @@ namespace storm {
             return result;
         }
         
-        Dd<DdType::CUDD> DdManager<DdType::CUDD>::getRange(storm::expressions::Variable const& variable) {
+        Dd<DdType::CUDD> DdManager<DdType::CUDD>::getRange(storm::expressions::Variable const& variable) const {
             storm::dd::DdMetaVariable<DdType::CUDD> const& metaVariable = this->getMetaVariable(variable);
             
             Dd<DdType::CUDD> result = this->getZero();
@@ -88,7 +88,7 @@ namespace storm {
             return result;
         }
         
-        Dd<DdType::CUDD> DdManager<DdType::CUDD>::getIdentity(storm::expressions::Variable const& variable) {
+        Dd<DdType::CUDD> DdManager<DdType::CUDD>::getIdentity(storm::expressions::Variable const& variable) const {
             storm::dd::DdMetaVariable<DdType::CUDD> const& metaVariable = this->getMetaVariable(variable);
             
             Dd<DdType::CUDD> result = this->getZero();
diff --git a/src/storage/dd/CuddDdManager.h b/src/storage/dd/CuddDdManager.h
index 8ff263ed2..5aff80682 100644
--- a/src/storage/dd/CuddDdManager.h
+++ b/src/storage/dd/CuddDdManager.h
@@ -40,21 +40,21 @@ namespace storm {
              *
              * @return A DD representing the constant one function.
              */
-            Dd<DdType::CUDD> getOne();
+            Dd<DdType::CUDD> getOne() const;
             
             /*!
              * Retrieves a DD representing the constant zero function.
              *
              * @return A DD representing the constant zero function.
              */
-            Dd<DdType::CUDD> getZero();
+            Dd<DdType::CUDD> getZero() const;
             
             /*!
              * Retrieves a DD representing the constant function with the given value.
              *
              * @return A DD representing the constant function with the given value.
              */
-            Dd<DdType::CUDD> getConstant(double value);
+            Dd<DdType::CUDD> getConstant(double value) const;
             
             /*!
              * Retrieves the DD representing the function that maps all inputs which have the given meta variable equal
@@ -65,7 +65,7 @@ namespace storm {
              * @return The DD representing the function that maps all inputs which have the given meta variable equal
              * to the given value one.
              */
-            Dd<DdType::CUDD> getEncoding(storm::expressions::Variable const& variable, int_fast64_t value);
+            Dd<DdType::CUDD> getEncoding(storm::expressions::Variable const& variable, int_fast64_t value) const;
             
             /*!
              * Retrieves the DD representing the range of the meta variable, i.e., a function that maps all legal values
@@ -74,7 +74,7 @@ namespace storm {
              * @param variable The expression variable associated with the meta variable.
              * @return The range of the meta variable.
              */
-            Dd<DdType::CUDD> getRange(storm::expressions::Variable const& variable);
+            Dd<DdType::CUDD> getRange(storm::expressions::Variable const& variable) const;
 
             /*!
              * Retrieves the DD representing the identity of the meta variable, i.e., a function that maps all legal
@@ -83,7 +83,7 @@ namespace storm {
              * @param variable The expression variable associated with the meta variable.
              * @return The identity of the meta variable.
              */
-            Dd<DdType::CUDD> getIdentity(storm::expressions::Variable const& variable);
+            Dd<DdType::CUDD> getIdentity(storm::expressions::Variable const& variable) const;
             
             /*!
              * Adds an integer meta variable with the given range.
diff --git a/src/storage/dd/CuddOdd.cpp b/src/storage/dd/CuddOdd.cpp
index dc84d9fd7..bd06a8648 100644
--- a/src/storage/dd/CuddOdd.cpp
+++ b/src/storage/dd/CuddOdd.cpp
@@ -8,7 +8,7 @@
 namespace storm {
     namespace dd {
         Odd<DdType::CUDD>::Odd(Dd<DdType::CUDD> const& dd) {
-            std::shared_ptr<DdManager<DdType::CUDD>> manager = dd.getDdManager();
+            std::shared_ptr<DdManager<DdType::CUDD> const> manager = dd.getDdManager();
             
             // First, we need to determine the involved DD variables indices.
             std::vector<uint_fast64_t> ddVariableIndices = dd.getSortedVariableIndices();
diff --git a/src/utility/math.h b/src/utility/math.h
new file mode 100644
index 000000000..9ee653c4e
--- /dev/null
+++ b/src/utility/math.h
@@ -0,0 +1,22 @@
+#ifndef STORM_UTILITY_MATH_H_
+#define STORM_UTILITY_MATH_H_
+
+#include <cmath>
+
+#include "src/utility/OsDetection.h"
+
+namespace storm {
+    namespace math {
+        // We provide this method explicitly, because MSVC does not offer it (non-C99 compliant).
+        template<typename ValueType>
+        static inline double log2(ValueType number) {
+#		ifndef WINDOWS
+            return std::log2(number);
+#		else
+            return std::log(number) / std::log(2);
+#		endif
+        }
+    }
+}
+
+#endif /* STORM_UTILITY_MATH_H_ */
\ No newline at end of file
diff --git a/src/utility/PrismUtility.h b/src/utility/prism.h
similarity index 99%
rename from src/utility/PrismUtility.h
rename to src/utility/prism.h
index 7d76dd5f4..f88188fb5 100644
--- a/src/utility/PrismUtility.h
+++ b/src/utility/prism.h
@@ -1,5 +1,5 @@
-#ifndef STORM_UTILITY_PRISMUTILITY
-#define STORM_UTILITY_PRISMUTILITY
+#ifndef STORM_UTILITY_PRISM_H_
+#define STORM_UTILITY_PRISM_H_
 
 #include <memory>
 #include <boost/algorithm/string.hpp>
@@ -236,4 +236,4 @@ namespace storm {
     } // namespace utility
 } // namespace storm
 
-#endif /* STORM_UTILITY_PRISMUTILITY_H_ */
+#endif /* STORM_UTILITY_PRISM_H_ */