diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 60fbadab9..bde12ab44 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -12,6 +12,7 @@ file(GLOB_RECURSE STORM_MAIN_FILE ${PROJECT_SOURCE_DIR}/src/storm.cpp)
 file(GLOB_RECURSE STORM_DFT_MAIN_FILE ${PROJECT_SOURCE_DIR}/src/storm-dyftee.cpp)
 file(GLOB_RECURSE STORM_ADAPTERS_FILES ${PROJECT_SOURCE_DIR}/src/adapters/*.h ${PROJECT_SOURCE_DIR}/src/adapters/*.cpp)
 file(GLOB_RECURSE STORM_BUILDER_FILES ${PROJECT_SOURCE_DIR}/src/builder/*.h ${PROJECT_SOURCE_DIR}/src/builder/*.cpp)
+file(GLOB_RECURSE STORM_GENERATOR_FILES ${PROJECT_SOURCE_DIR}/src/generator/*.h ${PROJECT_SOURCE_DIR}/src/generator/*.cpp)
 file(GLOB_RECURSE STORM_CLI_FILES ${PROJECT_SOURCE_DIR}/src/cli/*.h ${PROJECT_SOURCE_DIR}/src/cli/*.cpp)
 file(GLOB_RECURSE STORM_EXCEPTIONS_FILES ${PROJECT_SOURCE_DIR}/src/exceptions/*.h ${PROJECT_SOURCE_DIR}/src/exceptions/*.cpp)
 file(GLOB_RECURSE STORM_LOGIC_FILES ${PROJECT_SOURCE_DIR}/src/logic/*.h ${PROJECT_SOURCE_DIR}/src/logic/*.cpp)
@@ -63,6 +64,7 @@ source_group(main FILES ${STORM_MAIN_FILE})
 source_group(dft FILES ${STORM_DYFTTEE_FILE})
 source_group(adapters FILES ${STORM_ADAPTERS_FILES})
 source_group(builder FILES ${STORM_BUILDER_FILES})
+source_group(generator FILES ${STORM_GENERATOR_FILES})
 source_group(cli FILES ${STORM_CLI_FILES})
 source_group(exceptions FILES ${STORM_EXCEPTIONS_FILES})
 source_group(logic FILES ${STORM_LOGIC_FILES})
diff --git a/src/builder/ExplicitPrismModelBuilder.cpp b/src/builder/ExplicitPrismModelBuilder.cpp
index d7c2f6293..ef53b9e43 100644
--- a/src/builder/ExplicitPrismModelBuilder.cpp
+++ b/src/builder/ExplicitPrismModelBuilder.cpp
@@ -11,7 +11,11 @@
 
 #include "src/settings/modules/GeneralSettings.h"
 
+#include "src/generator/PrismNextStateGenerator.h"
+#include "src/generator/PrismStateLabelingGenerator.h"
+
 #include "src/utility/prism.h"
+#include "src/utility/constants.h"
 #include "src/utility/macros.h"
 #include "src/utility/ConstantsComparator.h"
 #include "src/exceptions/WrongFormatException.h"
@@ -21,13 +25,14 @@
 
 namespace storm {
     namespace builder {
+       
         /*!
          * A structure that is used to keep track of a reward model currently being built.
          */
         template <typename ValueType>
         struct RewardModelBuilder {
         public:
-            RewardModelBuilder(bool deterministicModel, bool hasStateRewards, bool hasStateActionRewards, bool hasTransitionRewards) : hasStateRewards(hasStateRewards), hasStateActionRewards(hasStateActionRewards), hasTransitionRewards(hasTransitionRewards), stateRewardVector(), stateActionRewardVector(), transitionRewardMatrixBuilder(0, 0, 0, false, !deterministicModel, 0) {
+            RewardModelBuilder(bool deterministicModel, bool hasStateRewards, bool hasStateActionRewards, bool hasTransitionRewards) : hasStateRewards(hasStateRewards), hasStateActionRewards(hasStateActionRewards), hasTransitionRewards(hasTransitionRewards), stateRewardVector(), stateActionRewardVector() {
                 // Intentionally left empty.
             }
             
@@ -37,19 +42,14 @@ namespace storm {
                     stateRewardVector.resize(rowGroupCount);
                     optionalStateRewardVector = std::move(stateRewardVector);
                 }
-
+                
                 boost::optional<std::vector<ValueType>> optionalStateActionRewardVector;
                 if (hasStateActionRewards) {
                     stateActionRewardVector.resize(rowCount);
                     optionalStateActionRewardVector = std::move(stateActionRewardVector);
                 }
                 
-                boost::optional<storm::storage::SparseMatrix<ValueType>> optionalTransitionRewardMatrix;
-                if (hasTransitionRewards) {
-                    optionalTransitionRewardMatrix = transitionRewardMatrixBuilder.build(rowCount, columnCount, rowGroupCount);
-                }
-                
-                return storm::models::sparse::StandardRewardModel<ValueType>(std::move(optionalStateRewardVector), std::move(optionalStateActionRewardVector), std::move(optionalTransitionRewardMatrix));
+                return storm::models::sparse::StandardRewardModel<ValueType>(std::move(optionalStateRewardVector), std::move(optionalStateActionRewardVector));
             }
             
             bool hasStateRewards;
@@ -61,75 +61,40 @@ namespace storm {
             
             // The state-action reward vector.
             std::vector<ValueType> stateActionRewardVector;
-            
-            // A builder that is used for constructing the transition reward matrix.
-            storm::storage::SparseMatrixBuilder<ValueType> transitionRewardMatrixBuilder;
         };
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::StateInformation::StateInformation(uint_fast64_t numberOfStates) : valuations(numberOfStates) {
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::StateInformation::StateInformation(uint_fast64_t numberOfStates) : valuations(numberOfStates) {
             // Intentionally left empty.
         }
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::InternalStateInformation::InternalStateInformation(uint64_t bitsPerState) : stateStorage(bitsPerState, 10000000), bitsPerState(bitsPerState), reachableStates() {
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::InternalStateInformation::InternalStateInformation() : stateStorage(64, 10), initialStateIndices(), bitsPerState(64), numberOfStates() {
             // Intentionally left empty.
         }
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::VariableInformation::BooleanVariableInformation::BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset) : variable(variable), initialValue(initialValue), bitOffset(bitOffset) {
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::InternalStateInformation::InternalStateInformation(uint64_t bitsPerState) : stateStorage(bitsPerState, 10000000), initialStateIndices(), bitsPerState(bitsPerState), numberOfStates() {
             // Intentionally left empty.
         }
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::VariableInformation::IntegerVariableInformation::IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth) : variable(variable), initialValue(initialValue), lowerBound(lowerBound), upperBound(upperBound), bitOffset(bitOffset), bitWidth(bitWidth) {
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ModelComponents::ModelComponents() : transitionMatrix(), stateLabeling(), rewardModels(), choiceLabeling() {
             // Intentionally left empty.
         }
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::VariableInformation::VariableInformation(storm::expressions::ExpressionManager const& manager) : manager(manager) {
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options() : explorationOrder(storm::settings::generalSettings().getExplorationOrder()), buildCommandLabels(false), buildAllRewardModels(true), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(true), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() {
             // Intentionally left empty.
         }
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        uint_fast64_t ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::VariableInformation::getBitOffset(storm::expressions::Variable const& variable) const {
-            auto const& booleanIndex = booleanVariableToIndexMap.find(variable);
-            if (booleanIndex != booleanVariableToIndexMap.end()) {
-                return booleanVariables[booleanIndex->second].bitOffset;
-            }
-            auto const& integerIndex = integerVariableToIndexMap.find(variable);
-            if (integerIndex != integerVariableToIndexMap.end()) {
-                return integerVariables[integerIndex->second].bitOffset;
-            }
-            STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit index of unknown variable.");
-        }
-
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        uint_fast64_t ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::VariableInformation::getBitWidth(storm::expressions::Variable const& variable) const {
-            auto const& integerIndex = integerVariableToIndexMap.find(variable);
-            if (integerIndex != integerVariableToIndexMap.end()) {
-                return integerVariables[integerIndex->second].bitWidth;
-            }
-            STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit width of unknown variable.");
-        }
-        
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::ModelComponents::ModelComponents() : transitionMatrix(), stateLabeling(), rewardModels(), choiceLabeling() {
-            // Intentionally left empty.
-        }
-
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::Options::Options() : buildCommandLabels(false), buildAllRewardModels(true), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(true), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() {
-            // Intentionally left empty.
-        }
-        
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::Options::Options(storm::logic::Formula const& formula) : buildCommandLabels(false), buildAllRewardModels(false), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(std::set<std::string>()), expressionLabels(std::vector<storm::expressions::Expression>()), terminalStates(), negatedTerminalStates() {
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options(storm::logic::Formula const& formula) : explorationOrder(storm::settings::generalSettings().getExplorationOrder()), buildCommandLabels(false), buildAllRewardModels(false), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(std::set<std::string>()), expressionLabels(std::vector<storm::expressions::Expression>()), terminalStates(), negatedTerminalStates() {
             this->preserveFormula(formula);
         }
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::Options::Options(std::vector<std::shared_ptr<const storm::logic::Formula>> const& formulas) : buildCommandLabels(false), buildAllRewardModels(false), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() {
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options(std::vector<std::shared_ptr<const storm::logic::Formula>> const& formulas) : explorationOrder(storm::settings::generalSettings().getExplorationOrder()), buildCommandLabels(false), buildAllRewardModels(false), buildStateInformation(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() {
             if (formulas.empty()) {
                 this->buildAllRewardModels = true;
                 this->buildAllLabels = true;
@@ -143,8 +108,8 @@ namespace storm {
             }
         }
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        void ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::Options::setTerminalStatesFromFormula(storm::logic::Formula const& formula) {
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        void ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::setTerminalStatesFromFormula(storm::logic::Formula const& formula) {
             if (formula.isAtomicExpressionFormula()) {
                 terminalStates = formula.asAtomicExpressionFormula().getExpression();
             } else if (formula.isAtomicLabelFormula()) {
@@ -172,9 +137,9 @@ namespace storm {
                 }
             }
         }
-
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        void ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::Options::preserveFormula(storm::logic::Formula const& formula) {
+        
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        void ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::preserveFormula(storm::logic::Formula const& formula) {
             // If we already had terminal states, we need to erase them.
             if (terminalStates) {
                 terminalStates.reset();
@@ -211,40 +176,23 @@ namespace storm {
             }
         }
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        void ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::Options::addConstantDefinitionsFromString(storm::prism::Program const& program, std::string const& constantDefinitionString) {
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        void ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::addConstantDefinitionsFromString(storm::prism::Program const& program, std::string const& constantDefinitionString) {
             constantDefinitions = storm::utility::prism::parseConstantDefinitionString(program, constantDefinitionString);
         }
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        typename ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::StateInformation const& ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::getStateInformation() const {
-            STORM_LOG_THROW(static_cast<bool>(stateInformation), storm::exceptions::InvalidOperationException, "The state information was not properly build.");
-            return stateInformation.get();
-        }
-        
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        storm::prism::Program const& ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::getTranslatedProgram() const {
-            return preparedProgram.get();
-        }
-        
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::translateProgram(storm::prism::Program program, Options const& options) {
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ExplicitPrismModelBuilder(storm::prism::Program const& program, Options const& options) : program(program), options(options) {
             // Start by defining the undefined constants in the model.
             if (options.constantDefinitions) {
-                preparedProgram = program.defineUndefinedConstants(options.constantDefinitions.get());
+                this->program = program.defineUndefinedConstants(options.constantDefinitions.get());
             } else {
-                preparedProgram = program;
+                this->program = program;
             }
-                        
+            
             // If the program still contains undefined constants and we are not in a parametric setting, assemble an appropriate error message.
-#ifdef STORM_HAVE_CARL
-            // If the program either has undefined constants or we are building a parametric model, but the parameters
-            // not only appear in the probabilities, we re
-            if (!std::is_same<ValueType, storm::RationalFunction>::value && preparedProgram->hasUndefinedConstants()) {
-#else
-            if (preparedProgram->hasUndefinedConstants()) {
-#endif
-                std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = preparedProgram->getUndefinedConstants();
+            if (!std::is_same<ValueType, storm::RationalFunction>::value && this->program.hasUndefinedConstants()) {
+                std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = this->program.getUndefinedConstants();
                 std::stringstream stream;
                 bool printComma = false;
                 for (auto const& constant : undefinedConstants) {
@@ -257,59 +205,78 @@ namespace storm {
                 }
                 stream << ".";
                 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " + stream.str());
-#ifdef STORM_HAVE_CARL
-            } else if (std::is_same<ValueType, storm::RationalFunction>::value && !preparedProgram->hasUndefinedConstantsOnlyInUpdateProbabilitiesAndRewards()) {
+            } else if (std::is_same<ValueType, storm::RationalFunction>::value && !this->program.hasUndefinedConstantsOnlyInUpdateProbabilitiesAndRewards()) {
                 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The program contains undefined constants that appear in some places other than update probabilities and reward value expressions, which is not admitted.");
-#endif
             }
-                            
+            
             // If the set of labels we are supposed to built is restricted, we need to remove the other labels from the program.
             if (options.labelsToBuild) {
                 if (!options.buildAllLabels) {
-                    preparedProgram->filterLabels(options.labelsToBuild.get());
+                    this->program.filterLabels(options.labelsToBuild.get());
                 }
             }
             
             // If we need to build labels for expressions that may appear in some formula, we need to add appropriate
             // labels to the program.
             if (options.expressionLabels) {
-                std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = preparedProgram->getConstantsSubstitution();
-
+                std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = this->program.getConstantsSubstitution();
+                
                 for (auto const& expression : options.expressionLabels.get()) {
                     std::stringstream stream;
                     stream << expression.substitute(constantsSubstitution);
                     std::string name = stream.str();
-                    if (!preparedProgram->hasLabel(name)) {
-                        preparedProgram->addLabel(name, expression);
+                    if (!this->program.hasLabel(name)) {
+                        this->program.addLabel(name, expression);
                     }
                 }
             }
             
             // Now that the program is fixed, we we need to substitute all constants with their concrete value.
-            preparedProgram = preparedProgram->substituteConstants();
+            this->program = this->program.substituteConstants();
+
+            // Create the variable information for the transformed program.
+            this->variableInformation = VariableInformation(this->program);
+            
+            // Create the internal state storage.
+            this->internalStateInformation = InternalStateInformation(variableInformation.getTotalBitOffset(true));
+        }
+        
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        typename ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::StateInformation const& ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::getStateInformation() const {
+            STORM_LOG_THROW(static_cast<bool>(stateInformation), storm::exceptions::InvalidOperationException, "The state information was not properly build.");
+            return stateInformation.get();
+        }
+        
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        storm::prism::Program const& ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::getTranslatedProgram() const {
+            return program;
+        }
+        
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::translate() {
+            STORM_LOG_DEBUG("Building representation of program:" << std::endl << program << std::endl);
+            STORM_LOG_DEBUG("Exploration order is: " << options.explorationOrder);
             
-            STORM_LOG_DEBUG("Building representation of program:" << std::endl << *preparedProgram << std::endl);
-                
             // Select the appropriate reward models (after the constants have been substituted).
             std::vector<std::reference_wrapper<storm::prism::RewardModel const>> selectedRewardModels;
-                
+            
             // First, we make sure that all selected reward models actually exist.
             for (auto const& rewardModelName : options.rewardModelsToBuild) {
-                STORM_LOG_THROW(rewardModelName.empty() || preparedProgram->hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException, "Model does not possess a reward model with the name '" << rewardModelName << "'.");
+                STORM_LOG_THROW(rewardModelName.empty() || program.hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException, "Model does not possess a reward model with the name '" << rewardModelName << "'.");
             }
-                
-            for (auto const& rewardModel : preparedProgram->getRewardModels()) {
+            
+            for (auto const& rewardModel : program.getRewardModels()) {
                 if (options.buildAllRewardModels || options.rewardModelsToBuild.find(rewardModel.getName()) != options.rewardModelsToBuild.end()) {
                     selectedRewardModels.push_back(rewardModel);
                 }
             }
             // If no reward model was selected until now and a referenced reward model appears to be unique, we build
             // the only existing reward model (given that no explicit name was given for the referenced reward model).
-            if (selectedRewardModels.empty() && preparedProgram->getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") {
-                selectedRewardModels.push_back(preparedProgram->getRewardModel(0));
+            if (selectedRewardModels.empty() && program.getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") {
+                selectedRewardModels.push_back(program.getRewardModel(0));
             }
-                
-            ModelComponents modelComponents = buildModelComponents(*preparedProgram, selectedRewardModels, options);
+            
+            ModelComponents modelComponents = buildModelComponents(selectedRewardModels);
             
             std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> result;
             switch (program.getModelType()) {
@@ -330,19 +297,9 @@ namespace storm {
             return result;
         }
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        void ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::unpackStateIntoEvaluator(storm::storage::BitVector const& currentState, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator) {
-            for (auto const& booleanVariable : variableInformation.booleanVariables) {
-                evaluator.setBooleanValue(booleanVariable.variable, currentState.get(booleanVariable.bitOffset));
-            }
-            for (auto const& integerVariable : variableInformation.integerVariables) {
-                evaluator.setIntegerValue(integerVariable.variable, currentState.getAsInt(integerVariable.bitOffset, integerVariable.bitWidth) + integerVariable.lowerBound);
-            }
-        }
-            
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        storm::expressions::SimpleValuation ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::unpackStateIntoValuation(storm::storage::BitVector const& currentState, VariableInformation const& variableInformation) {
-            storm::expressions::SimpleValuation result(variableInformation.manager.getSharedPointer());
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        storm::expressions::SimpleValuation ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::unpackStateIntoValuation(storm::storage::BitVector const& currentState) {
+            storm::expressions::SimpleValuation result(program.getManager().getSharedPointer());
             for (auto const& booleanVariable : variableInformation.booleanVariables) {
                 result.setBooleanValue(booleanVariable.variable, currentState.get(booleanVariable.bitOffset));
             }
@@ -352,620 +309,192 @@ namespace storm {
             return result;
         }
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        typename ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::CompressedState ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::applyUpdate(VariableInformation const& variableInformation, CompressedState const& state, storm::prism::Update const& update, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator) {
-            return applyUpdate(variableInformation, state, state, update, evaluator);
-        }
-        
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        typename ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::CompressedState ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::applyUpdate(VariableInformation const& variableInformation, CompressedState const& state, CompressedState const& baseState, storm::prism::Update const& update, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator) {
-            CompressedState newState(state);
-            
-            auto assignmentIt = update.getAssignments().begin();
-            auto assignmentIte = update.getAssignments().end();
-            
-            // Iterate over all boolean assignments and carry them out.
-            auto boolIt = variableInformation.booleanVariables.begin();
-            for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasBooleanType(); ++assignmentIt) {
-                while (assignmentIt->getVariable() != boolIt->variable) {
-                    ++boolIt;
-                }
-                newState.set(boolIt->bitOffset, evaluator.asBool(assignmentIt->getExpression()));
-            }
-            
-            // Iterate over all integer assignments and carry them out.
-            auto integerIt = variableInformation.integerVariables.begin();
-            for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasIntegerType(); ++assignmentIt) {
-                while (assignmentIt->getVariable() != integerIt->variable) {
-                    ++integerIt;
-                }
-                int_fast64_t assignedValue = evaluator.asInt(assignmentIt->getExpression());
-                STORM_LOG_THROW(assignedValue <= integerIt->upperBound, storm::exceptions::WrongFormatException, "The update " << update << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getVariableName() << "'.");
-                newState.setFromInt(integerIt->bitOffset, integerIt->bitWidth, assignedValue - integerIt->lowerBound);
-                STORM_LOG_ASSERT(static_cast<int_fast64_t>(newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth)) + integerIt->lowerBound == assignedValue, "Writing to the bit vector bucket failed (read " << newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth) << " but wrote " << assignedValue << ").");
-            }
-            
-            // Check that we processed all assignments.
-            STORM_LOG_ASSERT(assignmentIt == assignmentIte, "Not all assignments were consumed.");
-            
-            return newState;
-        }
-        
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        IndexType ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::getOrAddStateIndex(CompressedState const& state, InternalStateInformation& internalStateInformation, std::queue<storm::storage::BitVector>& stateQueue) {
-            uint32_t newIndex = internalStateInformation.reachableStates.size();
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        StateType ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::getOrAddStateIndex(CompressedState const& state) {
+            uint32_t newIndex = internalStateInformation.numberOfStates;
             
             // Check, if the state was already registered.
             std::pair<uint32_t, std::size_t> actualIndexBucketPair = internalStateInformation.stateStorage.findOrAddAndGetBucket(state, newIndex);
             
             if (actualIndexBucketPair.first == newIndex) {
-                stateQueue.push(state);
-                internalStateInformation.reachableStates.push_back(state);
-            }
-            
-            return actualIndexBucketPair.first;
-        }
-        
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::getActiveCommandsByActionIndex(storm::prism::Program const& program,storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, uint_fast64_t const& actionIndex) {
-            boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> result((std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>()));
-            
-            // Iterate over all modules.
-            for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
-                storm::prism::Module const& module = program.getModule(i);
-                
-                // If the module has no command labeled with the given action, we can skip this module.
-                if (!module.hasActionIndex(actionIndex)) {
-                    continue;
-                }
-                
-                std::set<uint_fast64_t> const& commandIndices = module.getCommandIndicesByActionIndex(actionIndex);
-                
-                // If the module contains the action, but there is no command in the module that is labeled with
-                // this action, we don't have any feasible command combinations.
-                if (commandIndices.empty()) {
-                    return boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>();
-                }
-                
-                std::vector<std::reference_wrapper<storm::prism::Command const>> commands;
-                
-                // Look up commands by their indices and add them if the guard evaluates to true in the given state.
-                for (uint_fast64_t commandIndex : commandIndices) {
-                    storm::prism::Command const& command = module.getCommand(commandIndex);
-                    if (evaluator.asBool(command.getGuardExpression())) {
-                        commands.push_back(command);
-                    }
-                }
-                
-                // If there was no enabled command although the module has some command with the required action label,
-                // we must not return anything.
-                if (commands.size() == 0) {
-                    return boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>();
-                }
-                
-                result.get().push_back(std::move(commands));
-            }
-            
-            return result;
-        }
-        
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        std::vector<Choice<ValueType>> ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::getUnlabeledTransitions(storm::prism::Program const& program, bool discreteTimeModel, InternalStateInformation& internalStateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, bool choiceLabeling, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, std::queue<storm::storage::BitVector>& stateQueue, storm::utility::ConstantsComparator<ValueType> const& comparator) {
-            std::vector<Choice<ValueType>> result;
-            
-            // Iterate over all modules.
-            for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
-                storm::prism::Module const& module = program.getModule(i);
-                
-                // Iterate over all commands.
-                for (uint_fast64_t j = 0; j < module.getNumberOfCommands(); ++j) {
-                    storm::prism::Command const& command = module.getCommand(j);
-                    
-                    // Only consider unlabeled commands.
-                    if (command.isLabeled()) continue;
-                    
-                    // Skip the command, if it is not enabled.
-                    if (!evaluator.asBool(command.getGuardExpression())) {
-                        continue;
-                    }
-                    
-                    result.push_back(Choice<ValueType>(0, choiceLabeling));
-                    Choice<ValueType>& choice = result.back();
-                    
-                    // Remember the command labels only if we were asked to.
-                    if (choiceLabeling) {
-                        choice.addChoiceLabel(command.getGlobalIndex());
-                    }
-                    
-                    // Iterate over all updates of the current command.
-                    ValueType probabilitySum = storm::utility::zero<ValueType>();
-                    for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) {
-                        storm::prism::Update const& update = command.getUpdate(k);
-                        
-                        // Obtain target state index and add it to the list of known states. If it has not yet been
-                        // seen, we also add it to the set of states that have yet to be explored.
-                        uint32_t stateIndex = getOrAddStateIndex(applyUpdate(variableInformation, currentState, update, evaluator), internalStateInformation, stateQueue);
-                        
-                        // Update the choice by adding the probability/target state to it.
-                        ValueType probability = evaluator.asRational(update.getLikelihoodExpression());
-                        choice.addProbability(stateIndex, probability);
-                        probabilitySum += probability;
-                    }
+                if (options.explorationOrder == ExplorationOrder::Dfs) {
+                    statesToExplore.push_front(state);
 
-                    // Check that the resulting distribution is in fact a distribution.
-                    STORM_LOG_THROW(!discreteTimeModel || comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Probabilities do not sum to one for command '" << command << "' (actually sum to " << probabilitySum << ").");
+                    // Reserve one slot for the new state in the remapping.
+                    stateRemapping.get().push_back(storm::utility::zero<StateType>());
+                } else if (options.explorationOrder == ExplorationOrder::Bfs) {
+                    statesToExplore.push_back(state);
+                } else {
+                    STORM_LOG_ASSERT(false, "Invalid exploration order.");
                 }
+                ++internalStateInformation.numberOfStates;
             }
             
-            return result;
+            return actualIndexBucketPair.first;
         }
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        std::vector<Choice<ValueType>> ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::getLabeledTransitions(storm::prism::Program const& program, bool discreteTimeModel, InternalStateInformation& internalStateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, bool choiceLabeling, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, std::queue<storm::storage::BitVector>& stateQueue, storm::utility::ConstantsComparator<ValueType> const& comparator) {
-            std::vector<Choice<ValueType>> result;
-            
-            for (uint_fast64_t actionIndex : program.getSynchronizingActionIndices()) {
-                boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> optionalActiveCommandLists = getActiveCommandsByActionIndex(program, evaluator, actionIndex);
-                
-                // Only process this action label, if there is at least one feasible solution.
-                if (optionalActiveCommandLists) {
-                    std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>> const& activeCommandList = optionalActiveCommandLists.get();
-                    std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>::const_iterator> iteratorList(activeCommandList.size());
-                    
-                    // Initialize the list of iterators.
-                    for (size_t i = 0; i < activeCommandList.size(); ++i) {
-                        iteratorList[i] = activeCommandList[i].cbegin();
-                    }
-                    
-                    // As long as there is one feasible combination of commands, keep on expanding it.
-                    bool done = false;
-                    while (!done) {
-                        std::unordered_map<CompressedState, ValueType>* currentTargetStates = new std::unordered_map<CompressedState, ValueType>();
-                        std::unordered_map<CompressedState, ValueType>* newTargetStates = new std::unordered_map<CompressedState, ValueType>();
-                        currentTargetStates->emplace(currentState, storm::utility::one<ValueType>());
-                        
-                        for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) {
-                            storm::prism::Command const& command = *iteratorList[i];
-                            
-                            for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) {
-                                storm::prism::Update const& update = command.getUpdate(j);
-                                
-                                for (auto const& stateProbabilityPair : *currentTargetStates) {
-                                    // Compute the new state under the current update and add it to the set of new target states.
-                                    CompressedState newTargetState = applyUpdate(variableInformation, stateProbabilityPair.first, currentState, update, evaluator);
-                                    newTargetStates->emplace(newTargetState, stateProbabilityPair.second * evaluator.asRational(update.getLikelihoodExpression()));
-                                }
-                            }
-                            
-                            // If there is one more command to come, shift the target states one time step back.
-                            if (i < iteratorList.size() - 1) {
-                                delete currentTargetStates;
-                                currentTargetStates = newTargetStates;
-                                newTargetStates = new std::unordered_map<CompressedState, ValueType>();
-                            }
-                        }
-                        
-                        // At this point, we applied all commands of the current command combination and newTargetStates
-                        // contains all target states and their respective probabilities. That means we are now ready to
-                        // add the choice to the list of transitions.
-                        result.push_back(Choice<ValueType>(actionIndex, choiceLabeling));
-                        
-                        // Now create the actual distribution.
-                        Choice<ValueType>& choice = result.back();
-                        
-                        // Remember the command labels only if we were asked to.
-                        if (choiceLabeling) {
-                            // Add the labels of all commands to this choice.
-                            for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) {
-                                choice.addChoiceLabel(iteratorList[i]->get().getGlobalIndex());
-                            }
-                        }
-                        
-                        ValueType probabilitySum = storm::utility::zero<ValueType>();
-                        for (auto const& stateProbabilityPair : *newTargetStates) {
-                            uint32_t actualIndex = getOrAddStateIndex(stateProbabilityPair.first, internalStateInformation, stateQueue);
-                            choice.addProbability(actualIndex, stateProbabilityPair.second);
-                            probabilitySum += stateProbabilityPair.second;
-                        }
-                        
-                        // Check that the resulting distribution is in fact a distribution.
-                        STORM_LOG_THROW(!discreteTimeModel || !comparator.isConstant(probabilitySum) || comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Sum of update probabilities do not some to one for some command (actually sum to " << probabilitySum << ").");
-                        
-                        // Dispose of the temporary maps.
-                        delete currentTargetStates;
-                        delete newTargetStates;
-                        
-                        // Now, check whether there is one more command combination to consider.
-                        bool movedIterator = false;
-                        for (int_fast64_t j = iteratorList.size() - 1; j >= 0; --j) {
-                            ++iteratorList[j];
-                            if (iteratorList[j] != activeCommandList[j].end()) {
-                                movedIterator = true;
-                            } else {
-                                // Reset the iterator to the beginning of the list.
-                                iteratorList[j] = activeCommandList[j].begin();
-                            }
-                        }
-                        
-                        done = !movedIterator;
-                    }
-                }
-            }
-            
-            return result;
-        }
-
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::buildMatrices(storm::prism::Program const& program, VariableInformation const& variableInformation, std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, InternalStateInformation& internalStateInformation, bool commandLabels, bool deterministicModel, bool discreteTimeModel, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression) {
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildMatrices(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression) {
             // Create choice labels, if requested,
             boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> choiceLabels;
-            if (commandLabels) {
+            if (options.buildCommandLabels) {
                 choiceLabels = std::vector<boost::container::flat_set<uint_fast64_t>>();
             }
-            
-            // A comparator that can be used to check whether we actually have distributions.
-            storm::utility::ConstantsComparator<ValueType> comparator;
-            
-            // Initialize a queue and insert the initial state.
-            std::queue<storm::storage::BitVector> stateQueue;
-            CompressedState initialState(internalStateInformation.bitsPerState);
-            
-            // We need to initialize the values of the variables to their initial value.
-            for (auto const& booleanVariable : variableInformation.booleanVariables) {
-                initialState.set(booleanVariable.bitOffset, booleanVariable.initialValue);
+
+            // Create a generator that is able to expand states.
+            storm::generator::PrismNextStateGenerator<ValueType, StateType> generator(program, variableInformation, options.buildCommandLabels);
+            if (terminalExpression) {
+                generator.setTerminalExpression(terminalExpression.get());
             }
-            for (auto const& integerVariable : variableInformation.integerVariables) {
-                initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast<uint_fast64_t>(integerVariable.initialValue - integerVariable.lowerBound));
+            for (auto const& rewardModel : selectedRewardModels) {
+                generator.addRewardModel(rewardModel.get());
             }
+
+            // Create a callback for the next-state generator to enable it to request the index of states.
+            std::function<StateType (CompressedState const&)> stateToIdCallback = std::bind(&ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::getOrAddStateIndex, this, std::placeholders::_1);
             
-            // At this point, we determine whether there are reward models with state-action rewards, because we might
-            // want to know that quickly later on.
-            bool hasStateActionRewards = false;
-            for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt) {
-                if (rewardModelIt->get().hasStateActionRewards()) {
-                    hasStateActionRewards = true;
-                    break;
-                }
+            // If the exploration order is something different from breadth-first, we need to keep track of the remapping
+            // from state ids to row groups. For this, we actually store the reversed mapping of row groups to state-ids
+            // and later reverse it.
+            if (options.explorationOrder != ExplorationOrder::Bfs) {
+                stateRemapping = std::vector<uint_fast64_t>();
             }
             
-            // Insert the initial state in the global state to index mapping and state queue.
-            uint32_t stateIndex = getOrAddStateIndex(initialState, internalStateInformation, stateQueue);
-            internalStateInformation.initialStateIndices.push_back(stateIndex);
+            // Let the generator create all initial states.
+            this->internalStateInformation.initialStateIndices = generator.getInitialStates(stateToIdCallback);
             
             // Now explore the current state until there is no more reachable state.
+            uint_fast64_t currentRowGroup = 0;
             uint_fast64_t currentRow = 0;
-            
-            // The evaluator used to determine the truth value of guards and predicates in the *current* state.
-            storm::expressions::ExpressionEvaluator<ValueType> evaluator(program.getManager());
-            
-            // Perform a BFS through the model.
-            while (!stateQueue.empty()) {
-                // Get the current state and unpack it.
-                storm::storage::BitVector currentState = stateQueue.front();
-                stateQueue.pop();
-                IndexType stateIndex = internalStateInformation.stateStorage.getValue(currentState);
-                STORM_LOG_TRACE("Exploring state with id " << stateIndex << ".");
-                unpackStateIntoEvaluator(currentState, variableInformation, evaluator);
-                
-                // If a terminal expression was given, we check whether the current state needs to be explored further.
-                std::vector<Choice<ValueType>> allUnlabeledChoices;
-                std::vector<Choice<ValueType>> allLabeledChoices;
-                bool deadlockOnPurpose = false;
-                if (terminalExpression && evaluator.asBool(terminalExpression.get())) {
-                    //std::cout << unpackStateIntoValuation(currentState, variableInformation).toString(true) << std::endl;
-                    //allUnlabeledChoices = getUnlabeledTransitions(program, discreteTimeModel, internalStateInformation, variableInformation, currentState, commandLabels, evaluator, stateQueue, comparator);
-                    //allLabeledChoices = getLabeledTransitions(program, discreteTimeModel, internalStateInformation, variableInformation, currentState, commandLabels, evaluator, stateQueue, comparator);
 
-                        // Nothing to do in this case.
-                    deadlockOnPurpose = true;
-                } else {
-                    // Retrieve all choices for the current state.
-                    allUnlabeledChoices = getUnlabeledTransitions(program, discreteTimeModel, internalStateInformation, variableInformation, currentState, commandLabels, evaluator, stateQueue, comparator);
-                    allLabeledChoices = getLabeledTransitions(program, discreteTimeModel, internalStateInformation, variableInformation, currentState, commandLabels, evaluator, stateQueue, comparator);
+            // Perform a search through the model.
+            while (!statesToExplore.empty()) {
+                // Get the first state in the queue.
+                CompressedState currentState = statesToExplore.front();
+                StateType currentIndex = internalStateInformation.stateStorage.getValue(currentState);
+                statesToExplore.pop_front();
+                
+                // If the exploration order differs from breadth-first, we remember that this row group was actually
+                // filled with the transitions of a different state.
+                if (options.explorationOrder != ExplorationOrder::Bfs) {
+                    stateRemapping.get()[currentIndex] = currentRowGroup;
                 }
                 
-                uint_fast64_t totalNumberOfChoices = allUnlabeledChoices.size() + allLabeledChoices.size();
+                STORM_LOG_TRACE("Exploring state with id " << currentIndex << ".");
+                
+                storm::generator::StateBehavior<ValueType, StateType> behavior = generator.expand(currentState, stateToIdCallback);
                 
-                // If the current state does not have a single choice, we equip it with a self-loop if that was
-                // requested and issue an error otherwise.
-                if (totalNumberOfChoices == 0) {
-                    if (!storm::settings::generalSettings().isDontFixDeadlocksSet() || deadlockOnPurpose) {
-                        if (commandLabels) {
+                // If there is no behavior, we might have to introduce a self-loop.
+                if (behavior.empty()) {
+                    if (!storm::settings::generalSettings().isDontFixDeadlocksSet() || !behavior.wasExpanded()) {
+                        if (options.buildCommandLabels) {
                             // Insert empty choice labeling for added self-loop transitions.
                             choiceLabels.get().push_back(boost::container::flat_set<uint_fast64_t>());
                         }
-                        if (!deterministicModel) {
+                        if (!generator.isDeterministicModel()) {
                             transitionMatrixBuilder.newRowGroup(currentRow);
                         }
                         
-                        transitionMatrixBuilder.addNextValue(currentRow, stateIndex, storm::utility::one<ValueType>());
+                        transitionMatrixBuilder.addNextValue(currentRow, currentIndex, storm::utility::one<ValueType>());
                         
                         auto builderIt = rewardModelBuilders.begin();
-                        for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) {
-                            if (rewardModelIt->get().hasStateRewards()) {
+                        for (auto const& rewardModel : selectedRewardModels) {
+                            if (rewardModel.get().hasStateRewards()) {
                                 builderIt->stateRewardVector.push_back(storm::utility::zero<ValueType>());
                             }
                             
-                            if (rewardModelIt->get().hasStateActionRewards()) {
+                            if (rewardModel.get().hasStateActionRewards()) {
                                 builderIt->stateActionRewardVector.push_back(storm::utility::zero<ValueType>());
                             }
+                            ++builderIt;
                         }
                         
                         ++currentRow;
+                        ++currentRowGroup;
                     } else {
-                        std::cout << unpackStateIntoValuation(currentState, variableInformation).toString(true) << std::endl;
+                        std::cout << unpackStateIntoValuation(currentState).toString(true) << std::endl;
                         STORM_LOG_THROW(false, storm::exceptions::WrongFormatException,
                                         "Error while creating sparse matrix from probabilistic program: found deadlock state. For fixing these, please provide the appropriate option.");
-
-                    }
-                } else if (totalNumberOfChoices == 1) {
-                    if (!deterministicModel) {
-                        transitionMatrixBuilder.newRowGroup(currentRow);
                     }
-                    
-                    bool labeledChoice = allUnlabeledChoices.empty() ? true : false;
-                    Choice<ValueType> const& globalChoice = labeledChoice ? allLabeledChoices.front() : allUnlabeledChoices.front();
-                    
+                } else {
+                    // Add the state rewards to the corresponding reward models.
                     auto builderIt = rewardModelBuilders.begin();
-                    for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) {
-                        if (rewardModelIt->get().hasStateRewards()) {
-                            builderIt->stateRewardVector.push_back(storm::utility::zero<ValueType>());
-                            for (auto const& stateReward : rewardModelIt->get().getStateRewards()) {
-                                if (evaluator.asBool(stateReward.getStatePredicateExpression())) {
-                                    builderIt->stateRewardVector.back() += ValueType(evaluator.asRational(stateReward.getRewardValueExpression()));
-                                }
-                            }
-                        }
-                        
-                        if (rewardModelIt->get().hasStateActionRewards()) {
-                            builderIt->stateActionRewardVector.push_back(storm::utility::zero<ValueType>());
-                            for (auto const& stateActionReward : rewardModelIt->get().getStateActionRewards()) {
-                                if ((labeledChoice && stateActionReward.isLabeled() && stateActionReward.getActionIndex() == globalChoice.getActionIndex()) || (!labeledChoice && !stateActionReward.isLabeled())) {
-                                    if (evaluator.asBool(stateActionReward.getStatePredicateExpression())) {
-                                        builderIt->stateActionRewardVector.back() += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression()));
-                                    }
-                                }
-                            }
+                    auto stateRewardIt = behavior.getStateRewards().begin();
+                    for (auto const& rewardModel : selectedRewardModels) {
+                        if (rewardModel.get().hasStateRewards()) {
+                            builderIt->stateRewardVector.push_back(*stateRewardIt);
                         }
+                        ++stateRewardIt;
+                        ++builderIt;
                     }
                     
-                    for (auto const& stateProbabilityPair : globalChoice) {
-                        transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second);
-                    }
-                    
-                    if (commandLabels) {
-                        // Now add the resulting distribution as the only choice of the current state.
-                        choiceLabels.get().push_back(globalChoice.getChoiceLabels());
+                    // If the model is nondeterministic, we need to open a row group.
+                    if (!generator.isDeterministicModel()) {
+                        transitionMatrixBuilder.newRowGroup(currentRow);
                     }
                     
-                    ++currentRow;
-                } else {
-                    // Then, based on whether the model is deterministic or not, either add the choices individually
-                    // or compose them to one choice.
-                    if (deterministicModel) {
-                        Choice<ValueType> globalChoice;
-
-                        // We need to prepare the entries of those vectors that are going to be used.
-                        auto builderIt = rewardModelBuilders.begin();
-                        for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) {
-                            if (rewardModelIt->get().hasStateRewards()) {
-                                builderIt->stateRewardVector.push_back(storm::utility::zero<ValueType>());
-                                for (auto const& stateReward : rewardModelIt->get().getStateRewards()) {
-                                    if (evaluator.asBool(stateReward.getStatePredicateExpression())) {
-                                        builderIt->stateRewardVector.back() += ValueType(evaluator.asRational(stateReward.getRewardValueExpression()));
-                                    }
-                                }
-                            }
-                            
-                            if (rewardModelIt->get().hasStateActionRewards()) {
-                                builderIt->stateActionRewardVector.push_back(storm::utility::zero<ValueType>());
-                            }
-                        }
-                        
-                        // If there is one state-action reward model, we need to scale the rewards according to the
-                        // multiple choices.
-                        ValueType totalExitMass = storm::utility::zero<ValueType>();
-                        if (hasStateActionRewards) {
-                            if (discreteTimeModel) {
-                                totalExitMass = static_cast<ValueType>(totalNumberOfChoices);
-                            } else {
-                                // In the CTMC, we need to compute the exit rate of the state here, sin
-                                for (auto const& choice : allUnlabeledChoices) {
-                                    totalExitMass += choice.getTotalMass();
-                                }
-                                for (auto const& choice : allLabeledChoices) {
-                                    totalExitMass += choice.getTotalMass();
-                                }
-                            }
+                    // Now add all choices.
+                    for (auto const& choice : behavior) {
+                        // Add command labels if requested.
+                        if (options.buildCommandLabels) {
+                            choiceLabels.get().push_back(choice.getChoiceLabels());
                         }
                         
-                        // Combine all the choices and scale them with the total number of choices of the current state.
-                        for (auto const& choice : allUnlabeledChoices) {
-                            if (commandLabels) {
-                                globalChoice.addChoiceLabels(choice.getChoiceLabels());
-                            }
-                            
-                            auto builderIt = rewardModelBuilders.begin();
-                            for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) {
-                                if (rewardModelIt->get().hasStateActionRewards()) {
-                                    for (auto const& stateActionReward : rewardModelIt->get().getStateActionRewards()) {
-                                        if (!stateActionReward.isLabeled()) {
-                                            if (evaluator.asBool(stateActionReward.getStatePredicateExpression())) {
-                                                builderIt->stateActionRewardVector.back() += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass() / totalExitMass;
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                            
-                            for (auto const& stateProbabilityPair : choice) {
-                                if (discreteTimeModel) {
-                                    globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second / totalNumberOfChoices;
-                                } else {
-                                    globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second;
-                                }
-                            }
-                        }
-                        for (auto const& choice : allLabeledChoices) {
-                            if (commandLabels) {
-                                globalChoice.addChoiceLabels(choice.getChoiceLabels());
-                            }
-                            
-                            auto builderIt = rewardModelBuilders.begin();
-                            for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) {
-                                if (rewardModelIt->get().hasStateActionRewards()) {
-                                    for (auto const& stateActionReward : rewardModelIt->get().getStateActionRewards()) {
-                                        if (stateActionReward.isLabeled() && stateActionReward.getActionIndex() == choice.getActionIndex()) {
-                                            if (evaluator.asBool(stateActionReward.getStatePredicateExpression())) {
-                                                builderIt->stateActionRewardVector.back() += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass() / totalExitMass;
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                            
-                            for (auto const& stateProbabilityPair : choice) {
-                                if (discreteTimeModel) {
-                                    globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second / totalNumberOfChoices;
-                                } else {
-                                    globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second;
-                                }
-                            }
-                        }
-                        
-                        
-                        if (commandLabels) {
-                            // Now add the resulting distribution as the only choice of the current state.
-                            choiceLabels.get().push_back(globalChoice.getChoiceLabels());
-                        }
-                        
-                        for (auto const& stateProbabilityPair : globalChoice) {
+                        // Add the probabilistic behavior to the matrix.
+                        for (auto const& stateProbabilityPair : choice) {
                             transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second);
                         }
                         
-                        ++currentRow;
-                    } else {
-                        // If the model is nondeterministic, we add all choices individually.
-                        transitionMatrixBuilder.newRowGroup(currentRow);
-
+                        // Add the rewards to the reward models.
                         auto builderIt = rewardModelBuilders.begin();
-                        for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) {
-                            if (rewardModelIt->get().hasStateRewards()) {
-                                builderIt->stateRewardVector.push_back(storm::utility::zero<ValueType>());
-                                
-                                for (auto const& stateReward : rewardModelIt->get().getStateRewards()) {
-                                    if (evaluator.asBool(stateReward.getStatePredicateExpression())) {
-                                        builderIt->stateRewardVector.back() += ValueType(evaluator.asRational(stateReward.getRewardValueExpression()));
-                                    }
-                                }
+                        auto choiceRewardIt = choice.getChoiceRewards().begin();
+                        for (auto const& rewardModel : selectedRewardModels) {
+                            if (rewardModel.get().hasStateActionRewards()) {
+                                builderIt->stateActionRewardVector.push_back(*choiceRewardIt);
                             }
+                            ++choiceRewardIt;
+                            ++builderIt;
                         }
-                        
-                        // First, process all unlabeled choices.
-                        for (auto const& choice : allUnlabeledChoices) {
-                            std::map<uint_fast64_t, ValueType> stateToRewardMap;
-                            if (commandLabels) {
-                                choiceLabels.get().emplace_back(std::move(choice.getChoiceLabels()));
-                            }
-                            
-                            auto builderIt = rewardModelBuilders.begin();
-                            for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) {
-                                if (rewardModelIt->get().hasStateActionRewards()) {
-                                    builderIt->stateActionRewardVector.push_back(storm::utility::zero<ValueType>());
-                                    for (auto const& stateActionReward : rewardModelIt->get().getStateActionRewards()) {
-                                        if (!stateActionReward.isLabeled()) {
-                                            if (evaluator.asBool(stateActionReward.getStatePredicateExpression())) {
-                                                builderIt->stateActionRewardVector.back() += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression()));
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                            
-                            for (auto const& stateProbabilityPair : choice) {
-                                transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second);
-                            }
-                            
-                            ++currentRow;
-                        }
-                        
-                        // Then, process all labeled choices.
-                        for (auto const& choice : allLabeledChoices) {
-                            std::map<uint_fast64_t, ValueType> stateToRewardMap;
-                            if (commandLabels) {
-                                choiceLabels.get().emplace_back(std::move(choice.getChoiceLabels()));
-                            }
-                            
-                            auto builderIt = rewardModelBuilders.begin();
-                            for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) {
-                                if (rewardModelIt->get().hasStateActionRewards()) {
-                                    builderIt->stateActionRewardVector.push_back(storm::utility::zero<ValueType>());
-                                    for (auto const& stateActionReward : rewardModelIt->get().getStateActionRewards()) {
-                                        if (stateActionReward.isLabeled() && stateActionReward.getActionIndex() == choice.getActionIndex()) {
-                                            if (evaluator.asBool(stateActionReward.getStatePredicateExpression())) {
-                                                builderIt->stateActionRewardVector.back() += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression()));
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                            
-                            for (auto const& stateProbabilityPair : choice) {
-                                transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second);
-                            }
-                            
-                            ++currentRow;
-                        }
+                        ++currentRow;
                     }
+                    ++currentRowGroup;
                 }
             }
+
+            // If the exploration order was not breadth-first, we need to fix the entries in the matrix according to
+            // (reversed) mapping of row groups to indices.
+            if (options.explorationOrder != ExplorationOrder::Bfs) {
+                STORM_LOG_ASSERT(stateRemapping, "Unable to fix columns without mapping.");
+                std::vector<uint_fast64_t> const& remapping = stateRemapping.get();
+                
+                // We need to fix the following entities:
+                // (a) the transition matrix
+                // (b) the initial states
+                // (c) the hash map storing the mapping states -> ids
+                
+                // Fix (a).
+                transitionMatrixBuilder.replaceColumns(remapping, 0);
+
+                // Fix (b).
+                std::vector<StateType> newInitialStateIndices(this->internalStateInformation.initialStateIndices.size());
+                std::transform(this->internalStateInformation.initialStateIndices.begin(), this->internalStateInformation.initialStateIndices.end(), newInitialStateIndices.begin(), [&remapping] (StateType const& state) { return remapping[state]; } );
+                std::sort(newInitialStateIndices.begin(), newInitialStateIndices.end());
+                this->internalStateInformation.initialStateIndices = std::move(newInitialStateIndices);
+                
+                // Fix (c).
+                this->internalStateInformation.stateStorage.remap([&remapping] (StateType const& state) { return remapping[state]; } );
+            }
             
             return choiceLabels;
         }
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        typename ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::ModelComponents ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::buildModelComponents(storm::prism::Program const& program, std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, Options const& options) {
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        typename ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::ModelComponents ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildModelComponents(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels) {
             ModelComponents modelComponents;
-            
-            uint_fast64_t bitOffset = 0;
-            VariableInformation variableInformation(program.getManager());
-            for (auto const& booleanVariable : program.getGlobalBooleanVariables()) {
-                variableInformation.booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), booleanVariable.getInitialValueExpression().evaluateAsBool(), bitOffset);
-                ++bitOffset;
-                variableInformation.booleanVariableToIndexMap[booleanVariable.getExpressionVariable()] = variableInformation.booleanVariables.size() - 1;
-            }
-            for (auto const& integerVariable : program.getGlobalIntegerVariables()) {
-                int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt();
-                int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt();
-                uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1)));
-                variableInformation.integerVariables.emplace_back(integerVariable.getExpressionVariable(), integerVariable.getInitialValueExpression().evaluateAsInt(), lowerBound, upperBound, bitOffset, bitwidth);
-                bitOffset += bitwidth;
-                variableInformation.integerVariableToIndexMap[integerVariable.getExpressionVariable()] = variableInformation.integerVariables.size() - 1;
-            }
-            for (auto const& module : program.getModules()) {
-                for (auto const& booleanVariable : module.getBooleanVariables()) {
-                    variableInformation.booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), booleanVariable.getInitialValueExpression().evaluateAsBool(), bitOffset);
-                    ++bitOffset;
-                    variableInformation.booleanVariableToIndexMap[booleanVariable.getExpressionVariable()] = variableInformation.booleanVariables.size() - 1;
-                }
-                for (auto const& integerVariable : module.getIntegerVariables()) {
-                    int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt();
-                    int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt();
-                    uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1)));
-                    variableInformation.integerVariables.emplace_back(integerVariable.getExpressionVariable(), integerVariable.getInitialValueExpression().evaluateAsInt(), lowerBound, upperBound, bitOffset, bitwidth);
-                    bitOffset += bitwidth;
-                    variableInformation.integerVariableToIndexMap[integerVariable.getExpressionVariable()] = variableInformation.integerVariables.size() - 1;
-                }
-            }
-            
-            // Create the structure for storing the reachable state space.
-            uint64_t bitsPerState = ((bitOffset / 64) + 1) * 64;
-            InternalStateInformation internalStateInformation(bitsPerState);
-            
+                        
             // Determine whether we have to combine different choices to one or whether this model can have more than
             // one choice per state.
-            bool deterministicModel = program.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::CTMC;
-            bool discreteTimeModel = program.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::MDP;
+            bool deterministicModel = program.isDeterministicModel();
             
             // Prepare the transition matrix builder and the reward model builders.
             storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !deterministicModel, 0);
@@ -1005,7 +534,7 @@ namespace storm {
                 STORM_LOG_TRACE("Making the states satisfying " << terminalExpression.get() << " terminal.");
             }
             
-            modelComponents.choiceLabeling = buildMatrices(program, variableInformation, selectedRewardModels, internalStateInformation, options.buildCommandLabels, deterministicModel, discreteTimeModel, transitionMatrixBuilder, rewardModelBuilders, terminalExpression);
+            modelComponents.choiceLabeling = buildMatrices(selectedRewardModels, transitionMatrixBuilder, rewardModelBuilders, terminalExpression);
             modelComponents.transitionMatrix = transitionMatrixBuilder.build();
             
             // Now finalize all reward models.
@@ -1015,48 +544,23 @@ namespace storm {
             }
             
             // Build the state labeling.
-            modelComponents.stateLabeling = buildStateLabeling(program, variableInformation, internalStateInformation);
+            modelComponents.stateLabeling = buildStateLabeling();
             
             // Finally -- if requested -- build the state information that can be retrieved from the outside.
             if (options.buildStateInformation) {
-                stateInformation = StateInformation(internalStateInformation.reachableStates.size());
+                stateInformation = StateInformation(internalStateInformation.numberOfStates);
                 for (auto const& bitVectorIndexPair : internalStateInformation.stateStorage) {
-                    stateInformation.get().valuations[bitVectorIndexPair.second] = unpackStateIntoValuation(bitVectorIndexPair.first, variableInformation);
+                    stateInformation.get().valuations[bitVectorIndexPair.second] = unpackStateIntoValuation(bitVectorIndexPair.first);
                 }
             }
             
             return modelComponents;
         }
         
-        template <typename ValueType, typename RewardModelType, typename IndexType>
-        storm::models::sparse::StateLabeling ExplicitPrismModelBuilder<ValueType, RewardModelType, IndexType>::buildStateLabeling(storm::prism::Program const& program, VariableInformation const& variableInformation, InternalStateInformation const& internalStateInformation) {
-            storm::expressions::ExpressionEvaluator<ValueType> evaluator(program.getManager());
-            
-            std::vector<storm::prism::Label> const& labels = program.getLabels();
-            
-            storm::models::sparse::StateLabeling result(internalStateInformation.reachableStates.size());
-            
-            // Initialize labeling.
-            for (auto const& label : labels) {
-                result.addLabel(label.getName());
-            }
-            for (uint_fast64_t index = 0; index < internalStateInformation.reachableStates.size(); index++) {
-                unpackStateIntoEvaluator(internalStateInformation.reachableStates[index], variableInformation, evaluator);
-                for (auto const& label : labels) {
-                    // Add label to state, if the corresponding expression is true.
-                    if (evaluator.asBool(label.getStatePredicateExpression())) {
-                        result.addLabelToState(label.getName(), index);
-                    }
-                }
-            }
-            
-            // Also label the initial state with the special label "init".
-            result.addLabel("init");
-            for (auto index : internalStateInformation.initialStateIndices) {
-                result.addLabelToState("init", index);
-            }
-            
-            return result;
+        template <typename ValueType, typename RewardModelType, typename StateType>
+        storm::models::sparse::StateLabeling ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::buildStateLabeling() {
+            storm::generator::PrismStateLabelingGenerator<ValueType, StateType> generator(program, variableInformation);
+            return generator.generate(internalStateInformation.stateStorage, internalStateInformation.initialStateIndices);
         }
         
         // Explicitly instantiate the class.
diff --git a/src/builder/ExplicitPrismModelBuilder.h b/src/builder/ExplicitPrismModelBuilder.h
index ccb0622e7..ab2eb9815 100644
--- a/src/builder/ExplicitPrismModelBuilder.h
+++ b/src/builder/ExplicitPrismModelBuilder.h
@@ -1,10 +1,10 @@
-#ifndef STORM_ADAPTERS_EXPLICITPRISMMODELBUILDER_H
-#define	STORM_ADAPTERS_EXPLICITPRISMMODELBUILDER_H
+#ifndef STORM_BUILDER_EXPLICITPRISMMODELBUILDER_H
+#define	STORM_BUILDER_EXPLICITPRISMMODELBUILDER_H
 
 #include <memory>
 #include <utility>
 #include <vector>
-#include <queue>
+#include <deque>
 #include <cstdint>
 #include <boost/functional/hash.hpp>
 #include <boost/container/flat_set.hpp>
@@ -22,9 +22,13 @@
 #include "src/storage/SparseMatrix.h"
 #include "src/settings/SettingsManager.h"
 
-#include "src/utility/constants.h"
 #include "src/utility/prism.h"
 
+#include "src/builder/ExplorationOrder.h"
+
+#include "src/generator/CompressedState.h"
+#include "src/generator/VariableInformation.h"
+
 namespace storm {
     namespace utility {
         template<typename ValueType> class ConstantsComparator;
@@ -33,30 +37,33 @@ namespace storm {
     namespace builder {
         
         using namespace storm::utility::prism;
+        using namespace storm::generator;
         
         // Forward-declare classes.
         template <typename ValueType> struct RewardModelBuilder;
         
-        template<typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>, typename IndexType = uint32_t>
+        template<typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>, typename StateType = uint32_t>
         class ExplicitPrismModelBuilder {
         public:
-            typedef storm::storage::BitVector CompressedState;
-            
             // A structure holding information about the reachable state space while building it.
             struct InternalStateInformation {
+                // Builds an empty state information.
+                InternalStateInformation();
+                
+                // Creates a state information structure for storing states of the given bit width.
                 InternalStateInformation(uint64_t bitsPerState);
 
                 // This member stores all the states and maps them to their unique indices.
-                storm::storage::BitVectorHashMap<IndexType> stateStorage;
+                storm::storage::BitVectorHashMap<StateType> stateStorage;
                 
                 // A list of initial states in terms of their global indices.
-                std::vector<IndexType> initialStateIndices;
+                std::vector<StateType> initialStateIndices;
 
                 // The number of bits of each state.
                 uint64_t bitsPerState;
                 
-                // A list of reachable states as indices in the stateToIndexMap.
-                std::vector<storm::storage::BitVector> reachableStates;
+                // The number of states that were found in the exploration so far.
+                uint_fast64_t numberOfStates;
             };
             
             // A structure holding information about the reachable state space that can be retrieved from the outside.
@@ -74,60 +81,6 @@ namespace storm {
                 }
             };
             
-            // A structure storing information about the used variables of the program.
-            struct VariableInformation {
-                VariableInformation(storm::expressions::ExpressionManager const& manager);
-                
-                struct BooleanVariableInformation {
-                    BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset);
-                    
-                    // The boolean variable.
-                    storm::expressions::Variable variable;
-                    
-                    // Its initial value.
-                    bool initialValue;
-                    
-                    // Its bit offset in the compressed state.
-                    uint_fast64_t bitOffset;
-                };
-
-                struct IntegerVariableInformation {
-                    IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth);
-                    
-                    // The integer variable.
-                    storm::expressions::Variable variable;
-                    
-                    // Its initial value.
-                    int_fast64_t initialValue;
-                    
-                    // The lower bound of its range.
-                    int_fast64_t lowerBound;
-                    
-                    // The upper bound of its range.
-                    int_fast64_t upperBound;
-                    
-                    // Its bit offset in the compressed state.
-                    uint_fast64_t bitOffset;
-                    
-                    // Its bit width in the compressed state.
-                    uint_fast64_t bitWidth;
-                };
-                
-                // Provide methods to access the bit offset and width of variables in the compressed state.
-                uint_fast64_t getBitOffset(storm::expressions::Variable const& variable) const;
-                uint_fast64_t getBitWidth(storm::expressions::Variable const& variable) const;
-
-                // The known boolean variables.
-                boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> booleanVariableToIndexMap;
-                std::vector<BooleanVariableInformation> booleanVariables;
-
-                // The known integer variables.
-                boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> integerVariableToIndexMap;
-                std::vector<IntegerVariableInformation> integerVariables;
-                
-                storm::expressions::ExpressionManager const& manager;
-            };
-            
             // A structure holding the individual components of a model.
             struct ModelComponents {
                 ModelComponents();
@@ -151,6 +104,11 @@ namespace storm {
                  */
                 Options();
                 
+                /*!
+                 * Copies the given set of options.
+                 */
+                Options(Options const& other) = default;
+                
                 /*! Creates an object representing the suggested building options assuming that the given formula is the
                  * only one to check. Additional formulas may be preserved by calling <code>preserveFormula</code>.
                  *
@@ -193,6 +151,9 @@ namespace storm {
                  */
                 void setTerminalStatesFromFormula(storm::logic::Formula const& formula);
                 
+                // The order in which to explore the model.
+                ExplorationOrder explorationOrder;
+                
                 // A flag that indicates whether or not command labels are to be built.
                 bool buildCommandLabels;
                 
@@ -228,6 +189,13 @@ namespace storm {
                 boost::optional<boost::variant<storm::expressions::Expression, std::string>> negatedTerminalStates;
             };
             
+            /*!
+             * Creates a builder for the given program.
+             *
+             * @param program The program to build.
+             */
+            ExplicitPrismModelBuilder(storm::prism::Program const& program, Options const& options = Options());
+            
             /*!
              * Convert the program given at construction time to an abstract model. The type of the model is the one
              * specified in the program. The given reward model name selects the rewards that the model will contain.
@@ -238,7 +206,7 @@ namespace storm {
              * @param rewardModel The reward model that is to be built.
              * @return The explicit model that was given by the probabilistic program.
              */
-            std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> translateProgram(storm::prism::Program program, Options const& options = Options());
+            std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> translate();
             
             /*!
              * If requested in the options, information about the variable valuations in the reachable states can be
@@ -249,39 +217,14 @@ namespace storm {
             StateInformation const& getStateInformation() const;
             
             /*!
-             * Retrieves the program that was actually translated (i.e. including constant substitutions etc.). Note
-             * that this function may only be called after a succesful translation.
+             * Retrieves the program that was actually translated (i.e. including constant substitutions etc.).
              *
              * @return The translated program.
              */
             storm::prism::Program const& getTranslatedProgram() const;
             
         private:
-            static void unpackStateIntoEvaluator(storm::storage::BitVector const& currentState, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator);
-
-            static storm::expressions::SimpleValuation unpackStateIntoValuation(storm::storage::BitVector const& currentState, VariableInformation const& variableInformation);
-
-            /*!
-             * Applies an update to the given state and returns the resulting new state object. This methods does not
-             * modify the given state but returns a new one.
-             *
-             * @params state The state to which to apply the update.
-             * @params update The update to apply.
-             * @return The resulting state.
-             */
-            static CompressedState applyUpdate(VariableInformation const& variableInformation, CompressedState const& state, storm::prism::Update const& update, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator);
-            
-            /*!
-             * Applies an update to the given state and returns the resulting new state object. The update is evaluated
-             * over the variable values of the given base state. This methods does not modify the given state but
-             * returns a new one.
-             *
-             * @param state The state to which to apply the update.
-             * @param baseState The state used for evaluating the update.
-             * @param update The update to apply.
-             * @return The resulting state.
-             */
-            static CompressedState applyUpdate(VariableInformation const& variableInformation, CompressedState const& state, CompressedState const& baseState, storm::prism::Update const& update, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator);
+            storm::expressions::SimpleValuation unpackStateIntoValuation(storm::storage::BitVector const& currentState);
             
             /*!
              * Retrieves the state id of the given state. If the state has not been encountered yet, it will be added to
@@ -293,29 +236,8 @@ namespace storm {
              * @param internalStateInformation The information about the already explored part of the reachable state space.
              * @return A pair indicating whether the state was already discovered before and the state id of the state.
              */
-            static IndexType getOrAddStateIndex(CompressedState const& state, InternalStateInformation& internalStateInformation, std::queue<storm::storage::BitVector>& stateQueue);
+            StateType getOrAddStateIndex(CompressedState const& state);
     
-            /*!
-             * Retrieves all commands that are labeled with the given label and enabled in the given state, grouped by
-             * modules.
-             *
-             * This function will iterate over all modules and retrieve all commands that are labeled with the given
-             * action and active (i.e. enabled) in the current state. The result is a list of lists of commands in which
-             * the inner lists contain all commands of exactly one module. If a module does not have *any* (including
-             * disabled) commands, there will not be a list of commands of that module in the result. If, however, the
-             * module has a command with a relevant label, but no enabled one, nothing is returned to indicate that there
-             * is no legal transition possible.
-             *
-             * @param The program in which to search for active commands.
-             * @param state The current state.
-             * @param actionIndex The index of the action label to select.
-             * @return A list of lists of active commands or nothing.
-             */
-            static boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> getActiveCommandsByActionIndex(storm::prism::Program const& program,storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, uint_fast64_t const& actionIndex);
-                        
-            static std::vector<Choice<ValueType>> getUnlabeledTransitions(storm::prism::Program const& program, bool discreteTimeModel, InternalStateInformation& internalStateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, bool choiceLabeling, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, std::queue<storm::storage::BitVector>& stateQueue, storm::utility::ConstantsComparator<ValueType> const& comparator);
-            
-            static std::vector<Choice<ValueType>> getLabeledTransitions(storm::prism::Program const& program, bool discreteTimeModel, InternalStateInformation& internalStateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, bool choiceLabeling, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, std::queue<storm::storage::BitVector>& stateQueue, storm::utility::ConstantsComparator<ValueType> const& comparator);
             /*!
              * Builds the transition matrix and the transition reward matrix based for the given program.
              *
@@ -333,7 +255,7 @@ namespace storm {
              * @return A tuple containing a vector with all rows at which the nondeterministic choices of each state begin
              * and a vector containing the labels associated with each choice.
              */
-            static boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> buildMatrices(storm::prism::Program const& program, VariableInformation const& variableInformation, std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, InternalStateInformation& internalStateInformation, bool commandLabels, bool deterministicModel, bool discreteTimeModel, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression);
+            boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> buildMatrices(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression);
             
             /*!
              * Explores the state space of the given program and returns the components of the model as a result.
@@ -343,7 +265,7 @@ namespace storm {
              * @param options A set of options used to customize the building process.
              * @return A structure containing the components of the resulting model.
              */
-            ModelComponents buildModelComponents(storm::prism::Program const& program, std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, Options const& options);
+            ModelComponents buildModelComponents(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels);
             
             /*!
              * Builds the state labeling for the given program.
@@ -353,17 +275,34 @@ namespace storm {
              * @param internalStateInformation Information about the state space of the program.
              * @return The state labeling of the given program.
              */
-            static storm::models::sparse::StateLabeling buildStateLabeling(storm::prism::Program const& program, VariableInformation const& variableInformation, InternalStateInformation const& internalStateInformation);
+            storm::models::sparse::StateLabeling buildStateLabeling();
+            
+            // The program to translate. The necessary transformations are performed upon construction of the builder.
+            storm::prism::Program program;
+            
+            // The options to be used for translating the program.
+            Options options;
+            
+            // The variable information.
+            VariableInformation variableInformation;
+            
+            // Internal information about the states that were explored.
+            InternalStateInformation internalStateInformation;
             
             // This member holds information about reachable states that can be retrieved from the outside after a
             // successful build.
             boost::optional<StateInformation> stateInformation;
             
-            // This member holds the program that was most recently translated (if any).
-            boost::optional<storm::prism::Program> preparedProgram;
+            // A set of states that still need to be explored.
+            std::deque<CompressedState> statesToExplore;
+            
+            // An optional mapping from state indices to the row groups in which they actually reside. This needs to be
+            // built in case the exploration order is not BFS.
+            boost::optional<std::vector<uint_fast64_t>> stateRemapping;
+
         };
         
     } // namespace adapters
 } // namespace storm
 
-#endif	/* STORM_ADAPTERS_EXPLICITPRISMMODELBUILDER_H */
+#endif	/* STORM_BUILDER_EXPLICITPRISMMODELBUILDER_H */
diff --git a/src/builder/ExplorationOrder.cpp b/src/builder/ExplorationOrder.cpp
new file mode 100644
index 000000000..fb0b82766
--- /dev/null
+++ b/src/builder/ExplorationOrder.cpp
@@ -0,0 +1,22 @@
+#include "src/builder/ExplorationOrder.h"
+
+namespace storm {
+    namespace builder {
+        
+        std::ostream& operator<<(std::ostream& out, ExplorationOrder const& order) {
+            switch (order) {
+                case ExplorationOrder::Dfs:
+                    out << "depth-first";
+                    break;
+                case ExplorationOrder::Bfs:
+                    out << "breadth-first";
+                    break;
+                default:
+                    out << "undefined";
+                    break;
+            }
+            return out;
+        }
+        
+    }
+}
\ No newline at end of file
diff --git a/src/builder/ExplorationOrder.h b/src/builder/ExplorationOrder.h
new file mode 100644
index 000000000..94c6363b3
--- /dev/null
+++ b/src/builder/ExplorationOrder.h
@@ -0,0 +1,17 @@
+#ifndef STORM_BUILDER_EXPLORATIONORDER_H_
+#define STORM_BUILDER_EXPLORATIONORDER_H_
+
+#include <ostream>
+
+namespace storm {
+    namespace builder {
+        
+        // An enum that contains all currently supported exploration orders.
+        enum class ExplorationOrder { Dfs, Bfs };
+        
+        std::ostream& operator<<(std::ostream& out, ExplorationOrder const& order);
+        
+    }
+}
+
+#endif /* STORM_BUILDER_EXPLORATIONORDER_H_ */
\ No newline at end of file
diff --git a/src/generator/Choice.cpp b/src/generator/Choice.cpp
new file mode 100644
index 000000000..9202f2c5e
--- /dev/null
+++ b/src/generator/Choice.cpp
@@ -0,0 +1,105 @@
+#include "src/generator/Choice.h"
+
+#include "src/adapters/CarlAdapter.h"
+
+#include "src/utility/constants.h"
+
+namespace storm {
+    namespace generator {
+        
+        template<typename ValueType, typename StateType>
+        Choice<ValueType, StateType>::Choice(uint_fast64_t actionIndex, bool markovian) : markovian(markovian), actionIndex(actionIndex), distribution(), totalMass(storm::utility::zero<ValueType>()), choiceRewards() {
+            // Intentionally left empty.
+        }
+        
+        template<typename ValueType, typename StateType>
+        typename storm::storage::Distribution<ValueType, StateType>::iterator Choice<ValueType, StateType>::begin() {
+            return distribution.begin();
+        }
+        
+        template<typename ValueType, typename StateType>
+        typename storm::storage::Distribution<ValueType, StateType>::const_iterator Choice<ValueType, StateType>::begin() const {
+            return distribution.cbegin();
+        }
+        
+        template<typename ValueType, typename StateType>
+        typename storm::storage::Distribution<ValueType, StateType>::iterator Choice<ValueType, StateType>::end() {
+            return distribution.end();
+        }
+        
+        template<typename ValueType, typename StateType>
+        typename storm::storage::Distribution<ValueType, StateType>::const_iterator Choice<ValueType, StateType>::end() const {
+            return distribution.cend();
+        }
+        
+        template<typename ValueType, typename StateType>
+        void Choice<ValueType, StateType>::addChoiceLabel(uint_fast64_t label) {
+            if (!choiceLabels) {
+                choiceLabels = LabelSet();
+            }
+            choiceLabels->insert(label);
+        }
+        
+        template<typename ValueType, typename StateType>
+        void Choice<ValueType, StateType>::addChoiceLabels(LabelSet const& labelSet) {
+            if (!choiceLabels) {
+                choiceLabels = LabelSet();
+            }
+            choiceLabels->insert(labelSet.begin(), labelSet.end());
+        }
+        
+        template<typename ValueType, typename StateType>
+        boost::container::flat_set<uint_fast64_t> const& Choice<ValueType, StateType>::getChoiceLabels() const {
+            return *choiceLabels;
+        }
+        
+        template<typename ValueType, typename StateType>
+        uint_fast64_t Choice<ValueType, StateType>::getActionIndex() const {
+            return actionIndex;
+        }
+        
+        template<typename ValueType, typename StateType>
+        ValueType Choice<ValueType, StateType>::getTotalMass() const {
+            return totalMass;
+        }
+        
+        template<typename ValueType, typename StateType>
+        void Choice<ValueType, StateType>::addProbability(StateType const& state, ValueType const& value) {
+            totalMass += value;
+            distribution.addProbability(state, value);
+        }
+        
+        template<typename ValueType, typename StateType>
+        void Choice<ValueType, StateType>::addChoiceReward(ValueType const& value) {
+            choiceRewards.push_back(value);
+        }
+        
+        template<typename ValueType, typename StateType>
+        std::vector<ValueType> const& Choice<ValueType, StateType>::getChoiceRewards() const {
+            return choiceRewards;
+        }
+        
+        template<typename ValueType, typename StateType>
+        bool Choice<ValueType, StateType>::isMarkovian() const {
+            return markovian;
+        }
+        
+        template<typename ValueType, typename StateType>
+        std::size_t Choice<ValueType, StateType>::size() const {
+            return distribution.size();
+        }
+        
+        template<typename ValueType, typename StateType>
+        std::ostream& operator<<(std::ostream& out, Choice<ValueType, StateType> const& choice) {
+            out << "<";
+            for (auto const& stateProbabilityPair : choice) {
+                out << stateProbabilityPair.first << " : " << stateProbabilityPair.second << ", ";
+            }
+            out << ">";
+            return out;
+        }
+        
+        template class Choice<double>;
+        template class Choice<storm::RationalFunction>;
+    }
+}
\ No newline at end of file
diff --git a/src/generator/Choice.h b/src/generator/Choice.h
new file mode 100644
index 000000000..76b6c8d16
--- /dev/null
+++ b/src/generator/Choice.h
@@ -0,0 +1,150 @@
+#ifndef STORM_GENERATOR_CHOICE_H_
+#define STORM_GENERATOR_CHOICE_H_
+
+#include <cstdint>
+#include <functional>
+
+#include <boost/optional.hpp>
+#include <boost/container/flat_set.hpp>
+
+#include "src/storage/Distribution.h"
+
+namespace storm {
+    namespace generator {
+        
+        // A structure holding information about a particular choice.
+        template<typename ValueType, typename StateType=uint32_t>
+        struct Choice {
+        public:
+            typedef boost::container::flat_set<uint_fast64_t> LabelSet;
+            
+            Choice(uint_fast64_t actionIndex = 0, bool markovian = false);
+            
+            Choice(Choice const& other) = default;
+            Choice& operator=(Choice const& other) = default;
+            Choice(Choice&& other) = default;
+            Choice& operator=(Choice&& other) = default;
+            
+            /*!
+             * Returns an iterator to the distribution associated with this choice.
+             *
+             * @return An iterator to the first element of the distribution.
+             */
+            typename storm::storage::Distribution<ValueType, StateType>::iterator begin();
+            
+            /*!
+             * Returns an iterator to the distribution associated with this choice.
+             *
+             * @return An iterator to the first element of the distribution.
+             */
+            typename storm::storage::Distribution<ValueType, StateType>::const_iterator begin() const;
+            
+            /*!
+             * Returns an iterator past the end of the distribution associated with this choice.
+             *
+             * @return An iterator past the end of the distribution.
+             */
+            typename storm::storage::Distribution<ValueType, StateType>::iterator end();
+            
+            /*!
+             * Returns an iterator past the end of the distribution associated with this choice.
+             *
+             * @return An iterator past the end of the distribution.
+             */
+            typename storm::storage::Distribution<ValueType, StateType>::const_iterator end() const;
+            
+            /*!
+             * Inserts the contents of this object to the given output stream.
+             *
+             * @param out The stream in which to insert the contents.
+             */
+            template<typename ValueTypePrime, typename StateTypePrime>
+            friend std::ostream& operator<<(std::ostream& out, Choice<ValueTypePrime, StateTypePrime> const& choice);
+            
+            /*!
+             * Adds the given label to the labels associated with this choice.
+             *
+             * @param label The label to associate with this choice.
+             */
+            void addChoiceLabel(uint_fast64_t label);
+            
+            /*!
+             * Adds the given label set to the labels associated with this choice.
+             *
+             * @param labelSet The label set to associate with this choice.
+             */
+            void addChoiceLabels(LabelSet const& labelSet);
+            
+            /*!
+             * Retrieves the set of labels associated with this choice.
+             *
+             * @return The set of labels associated with this choice.
+             */
+            LabelSet const& getChoiceLabels() const;
+            
+            /*!
+             * Retrieves the index of the action of this choice.
+             *
+             * @return The index of the action of this choice.
+             */
+            uint_fast64_t getActionIndex() const;
+            
+            /*!
+             * Retrieves the total mass of this choice.
+             *
+             * @return The total mass.
+             */
+            ValueType getTotalMass() const;
+            
+            /*!
+             * Adds the given probability value to the given state in the underlying distribution.
+             */
+            void addProbability(StateType const& state, ValueType const& value);
+            
+            /*!
+             * Adds the given value to the reward associated with this choice.
+             */
+            void addChoiceReward(ValueType const& value);
+            
+            /*!
+             * Retrieves the rewards for this choice under selected reward models.
+             */
+            std::vector<ValueType> const& getChoiceRewards() const;
+            
+            /*!
+             * Retrieves whether the choice is Markovian.
+             */
+            bool isMarkovian() const;
+            
+            /*!
+             * Retrieves the size of the distribution associated with this choice.
+             */
+            std::size_t size() const;
+            
+        private:
+            // A flag indicating whether this choice is Markovian or not.
+            bool markovian;
+
+            // The action index associated with this choice.
+            uint_fast64_t actionIndex;
+            
+            // The distribution that is associated with the choice.
+            storm::storage::Distribution<ValueType, StateType> distribution;
+            
+            // The total probability mass (or rates) of this choice.
+            ValueType totalMass;
+            
+            // The reward values associated with this choice.
+            std::vector<ValueType> choiceRewards;
+            
+            // The labels that are associated with this choice.
+            boost::optional<LabelSet> choiceLabels;
+        };
+
+        template<typename ValueType, typename StateType>
+        std::ostream& operator<<(std::ostream& out, Choice<ValueType, StateType> const& choice);
+
+    }
+}
+
+#endif /* STORM_GENERATOR_CHOICE_H_ */
\ No newline at end of file
diff --git a/src/generator/CompressedState.cpp b/src/generator/CompressedState.cpp
new file mode 100644
index 000000000..c63504ebb
--- /dev/null
+++ b/src/generator/CompressedState.cpp
@@ -0,0 +1,23 @@
+#include "src/generator/CompressedState.h"
+
+#include "src/generator/VariableInformation.h"
+#include "src/storage/expressions/ExpressionEvaluator.h"
+
+namespace storm {
+    namespace generator {
+        
+        template<typename ValueType>
+        void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator) {
+            for (auto const& booleanVariable : variableInformation.booleanVariables) {
+                evaluator.setBooleanValue(booleanVariable.variable, state.get(booleanVariable.bitOffset));
+            }
+            for (auto const& integerVariable : variableInformation.integerVariables) {
+                evaluator.setIntegerValue(integerVariable.variable, state.getAsInt(integerVariable.bitOffset, integerVariable.bitWidth) + integerVariable.lowerBound);
+            }
+
+        }
+
+        template void unpackStateIntoEvaluator<double>(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<double>& evaluator);
+        template void unpackStateIntoEvaluator<storm::RationalFunction>(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<storm::RationalFunction>& evaluator);
+    }
+}
\ No newline at end of file
diff --git a/src/generator/CompressedState.h b/src/generator/CompressedState.h
new file mode 100644
index 000000000..52f0b4a62
--- /dev/null
+++ b/src/generator/CompressedState.h
@@ -0,0 +1,30 @@
+#ifndef STORM_GENERATOR_COMPRESSEDSTATE_H_
+#define STORM_GENERATOR_COMPRESSEDSTATE_H_
+
+#include "src/storage/BitVector.h"
+
+namespace storm {
+    namespace expressions {
+        template<typename ValueType> class ExpressionEvaluator;
+    }
+    
+    namespace generator {
+        
+        typedef storm::storage::BitVector CompressedState;
+
+        class VariableInformation;
+        
+        /*!
+         * Unpacks the compressed state into the evaluator.
+         *
+         * @param state The state to unpack.
+         * @param variableInformation The information about how the variables are packed with the state.
+         * @param evaluator The evaluator into which to load the state.
+         */
+        template<typename ValueType>
+        void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator);
+    }
+}
+
+#endif /* STORM_GENERATOR_COMPRESSEDSTATE_H_ */
+
diff --git a/src/generator/NextStateGenerator.h b/src/generator/NextStateGenerator.h
new file mode 100644
index 000000000..779a49ef3
--- /dev/null
+++ b/src/generator/NextStateGenerator.h
@@ -0,0 +1,24 @@
+#ifndef STORM_GENERATOR_NEXTSTATEGENERATOR_H_
+#define STORM_GENERATOR_NEXTSTATEGENERATOR_H_
+
+#include <vector>
+#include <cstdint>
+
+#include "src/generator/CompressedState.h"
+#include "src/generator/StateBehavior.h"
+
+namespace storm {
+    namespace generator {
+        template<typename ValueType, typename StateType = uint32_t>
+        class NextStateGenerator {
+        public:
+            typedef std::function<StateType (CompressedState const&)> StateToIdCallback;
+
+            virtual bool isDeterministicModel() const = 0;
+            virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) = 0;
+            virtual StateBehavior<ValueType, StateType> expand(CompressedState const& state, StateToIdCallback const& stateToIdCallback) = 0;
+        };
+    }
+}
+
+#endif /* STORM_GENERATOR_NEXTSTATEGENERATOR_H_ */
\ No newline at end of file
diff --git a/src/generator/PrismNextStateGenerator.cpp b/src/generator/PrismNextStateGenerator.cpp
new file mode 100644
index 000000000..fac3be0f5
--- /dev/null
+++ b/src/generator/PrismNextStateGenerator.cpp
@@ -0,0 +1,404 @@
+#include "src/generator/PrismNextStateGenerator.h"
+
+#include <boost/container/flat_map.hpp>
+
+#include "src/utility/constants.h"
+#include "src/utility/macros.h"
+#include "src/exceptions/WrongFormatException.h"
+
+namespace storm {
+    namespace generator {
+        
+        template<typename ValueType, typename StateType>
+        PrismNextStateGenerator<ValueType, StateType>::PrismNextStateGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation, bool buildChoiceLabeling) : program(program), selectedRewardModels(), buildChoiceLabeling(buildChoiceLabeling), variableInformation(variableInformation), evaluator(program.getManager()), comparator() {
+            // Intentionally left empty.
+        }
+        
+        template<typename ValueType, typename StateType>
+        void PrismNextStateGenerator<ValueType, StateType>::addRewardModel(storm::prism::RewardModel const& rewardModel) {
+            selectedRewardModels.push_back(rewardModel);
+            hasStateActionRewards |= rewardModel.hasStateActionRewards();
+        }
+        
+        template<typename ValueType, typename StateType>
+        void PrismNextStateGenerator<ValueType, StateType>::setTerminalExpression(storm::expressions::Expression const& terminalExpression) {
+            this->terminalExpression = terminalExpression;
+        }
+        
+        template<typename ValueType, typename StateType>
+        bool PrismNextStateGenerator<ValueType, StateType>::isDeterministicModel() const {
+            return program.isDeterministicModel();
+        }
+        
+        template<typename ValueType, typename StateType>
+        std::vector<StateType> PrismNextStateGenerator<ValueType, StateType>::getInitialStates(StateToIdCallback const& stateToIdCallback) {
+            // FIXME: This only works for models with exactly one initial state. We should make this more general.
+            CompressedState initialState(variableInformation.getTotalBitOffset());
+            
+            // We need to initialize the values of the variables to their initial value.
+            for (auto const& booleanVariable : variableInformation.booleanVariables) {
+                initialState.set(booleanVariable.bitOffset, booleanVariable.initialValue);
+            }
+            for (auto const& integerVariable : variableInformation.integerVariables) {
+                initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast<uint_fast64_t>(integerVariable.initialValue - integerVariable.lowerBound));
+            }
+
+            // Register initial state and return it.
+            StateType id = stateToIdCallback(initialState);
+            return {id};
+        }
+        
+        template<typename ValueType, typename StateType>
+        StateBehavior<ValueType, StateType> PrismNextStateGenerator<ValueType, StateType>::expand(CompressedState const& state, StateToIdCallback const& stateToIdCallback) {
+            // Since almost all subsequent operations are based on the evaluator, we load the state into it now.
+            unpackStateIntoEvaluator(state, variableInformation, evaluator);
+
+            // Prepare the result, in case we return early.
+            StateBehavior<ValueType, StateType> result;
+            
+            // First, construct the state rewards, as we may return early if there are no choices later and we already
+            // need the state rewards then.
+            for (auto const& rewardModel : selectedRewardModels) {
+                ValueType stateRewardValue = storm::utility::zero<ValueType>();
+                if (rewardModel.get().hasStateRewards()) {
+                    for (auto const& stateReward : rewardModel.get().getStateRewards()) {
+                        if (evaluator.asBool(stateReward.getStatePredicateExpression())) {
+                            stateRewardValue += ValueType(evaluator.asRational(stateReward.getRewardValueExpression()));
+                        }
+                    }
+                }
+                result.addStateReward(stateRewardValue);
+            }
+            
+            // If a terminal expression was set and we must not expand this state, return now.
+            if (terminalExpression && evaluator.asBool(terminalExpression.get())) {
+                return result;
+            }
+            
+            // Get all choices for the state.
+            std::vector<Choice<ValueType>> allChoices = getUnlabeledChoices(state, stateToIdCallback);
+            std::vector<Choice<ValueType>> allLabeledChoices = getLabeledChoices(state, stateToIdCallback);
+            for (auto& choice : allLabeledChoices) {
+                allChoices.push_back(std::move(choice));
+            }
+            
+            std::size_t totalNumberOfChoices = allChoices.size();
+            
+            // If there is not a single choice, we return immediately, because the state has no behavior (other than
+            // the state reward).
+            if (totalNumberOfChoices == 0) {
+                return result;
+            }
+            
+            // If the model is a deterministic model, we need to fuse the choices into one.
+            if (program.isDeterministicModel() && totalNumberOfChoices > 1) {
+                Choice<ValueType> globalChoice;
+                
+                // For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs
+                // this is equal to the number of choices, which is why we initialize it like this here.
+                ValueType totalExitRate = program.isDiscreteTimeModel() ? static_cast<ValueType>(totalNumberOfChoices) : storm::utility::zero<ValueType>();
+                
+                // Iterate over all choices and combine the probabilities/rates into one choice.
+                for (auto const& choice : allChoices) {
+                    for (auto const& stateProbabilityPair : choice) {
+                        if (program.isDiscreteTimeModel()) {
+                            globalChoice.addProbability(stateProbabilityPair.first, stateProbabilityPair.second / totalNumberOfChoices);
+                        } else {
+                            globalChoice.addProbability(stateProbabilityPair.first, stateProbabilityPair.second);
+                        }
+                    }
+                    
+                    if (hasStateActionRewards && !program.isDiscreteTimeModel()) {
+                        totalExitRate += choice.getTotalMass();
+                    }
+                    
+                    if (buildChoiceLabeling) {
+                        globalChoice.addChoiceLabels(choice.getChoiceLabels());
+                    }
+                }
+                
+                // Now construct the state-action reward for all selected reward models.
+                for (auto const& rewardModel : selectedRewardModels) {
+                    ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
+                    if (rewardModel.get().hasStateActionRewards()) {
+                        for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) {
+                            for (auto const& choice : allChoices) {
+                                if (stateActionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(stateActionReward.getStatePredicateExpression())) {
+                                    stateActionRewardValue += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass() / totalExitRate;
+                                }
+                            }
+                            
+                        }
+                    }
+                    globalChoice.addChoiceReward(stateActionRewardValue);
+                }
+                
+                // Move the newly fused choice in place.
+                allChoices.clear();
+                allChoices.push_back(std::move(globalChoice));
+            }
+            
+            // Move all remaining choices in place.
+            for (auto& choice : allChoices) {
+                result.addChoice(std::move(choice));
+            }
+            
+            result.setExpanded();
+            return result;
+        }
+        
+        template<typename ValueType, typename StateType>
+        CompressedState PrismNextStateGenerator<ValueType, StateType>::applyUpdate(CompressedState const& state, storm::prism::Update const& update) {
+            CompressedState newState(state);
+            
+            auto assignmentIt = update.getAssignments().begin();
+            auto assignmentIte = update.getAssignments().end();
+            
+            // Iterate over all boolean assignments and carry them out.
+            auto boolIt = variableInformation.booleanVariables.begin();
+            for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasBooleanType(); ++assignmentIt) {
+                while (assignmentIt->getVariable() != boolIt->variable) {
+                    ++boolIt;
+                }
+                newState.set(boolIt->bitOffset, evaluator.asBool(assignmentIt->getExpression()));
+            }
+            
+            // Iterate over all integer assignments and carry them out.
+            auto integerIt = variableInformation.integerVariables.begin();
+            for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasIntegerType(); ++assignmentIt) {
+                while (assignmentIt->getVariable() != integerIt->variable) {
+                    ++integerIt;
+                }
+                int_fast64_t assignedValue = evaluator.asInt(assignmentIt->getExpression());
+                STORM_LOG_THROW(assignedValue <= integerIt->upperBound, storm::exceptions::WrongFormatException, "The update " << update << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getVariableName() << "'.");
+                newState.setFromInt(integerIt->bitOffset, integerIt->bitWidth, assignedValue - integerIt->lowerBound);
+                STORM_LOG_ASSERT(static_cast<int_fast64_t>(newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth)) + integerIt->lowerBound == assignedValue, "Writing to the bit vector bucket failed (read " << newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth) << " but wrote " << assignedValue << ").");
+            }
+            
+            // Check that we processed all assignments.
+            STORM_LOG_ASSERT(assignmentIt == assignmentIte, "Not all assignments were consumed.");
+            
+            return newState;
+        }
+        
+        template<typename ValueType, typename StateType>
+        boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> PrismNextStateGenerator<ValueType, StateType>::getActiveCommandsByActionIndex(uint_fast64_t const& actionIndex) {
+            boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> result((std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>()));
+            
+            // Iterate over all modules.
+            for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
+                storm::prism::Module const& module = program.getModule(i);
+                
+                // If the module has no command labeled with the given action, we can skip this module.
+                if (!module.hasActionIndex(actionIndex)) {
+                    continue;
+                }
+                
+                std::set<uint_fast64_t> const& commandIndices = module.getCommandIndicesByActionIndex(actionIndex);
+                
+                // If the module contains the action, but there is no command in the module that is labeled with
+                // this action, we don't have any feasible command combinations.
+                if (commandIndices.empty()) {
+                    return boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>();
+                }
+                
+                std::vector<std::reference_wrapper<storm::prism::Command const>> commands;
+                
+                // Look up commands by their indices and add them if the guard evaluates to true in the given state.
+                for (uint_fast64_t commandIndex : commandIndices) {
+                    storm::prism::Command const& command = module.getCommand(commandIndex);
+                    if (evaluator.asBool(command.getGuardExpression())) {
+                        commands.push_back(command);
+                    }
+                }
+                
+                // If there was no enabled command although the module has some command with the required action label,
+                // we must not return anything.
+                if (commands.size() == 0) {
+                    return boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>();
+                }
+                
+                result.get().push_back(std::move(commands));
+            }
+            
+            return result;
+        }
+        
+        template<typename ValueType, typename StateType>
+        std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::getUnlabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback) {
+            std::vector<Choice<ValueType>> result;
+            
+            // Iterate over all modules.
+            for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
+                storm::prism::Module const& module = program.getModule(i);
+                
+                // Iterate over all commands.
+                for (uint_fast64_t j = 0; j < module.getNumberOfCommands(); ++j) {
+                    storm::prism::Command const& command = module.getCommand(j);
+                    
+                    // Only consider unlabeled commands.
+                    if (command.isLabeled()) continue;
+                    
+                    // Skip the command, if it is not enabled.
+                    if (!evaluator.asBool(command.getGuardExpression())) {
+                        continue;
+                    }
+                    
+                    result.push_back(Choice<ValueType>(command.getActionIndex()));
+                    Choice<ValueType>& choice = result.back();
+                    
+                    // Remember the command labels only if we were asked to.
+                    if (buildChoiceLabeling) {
+                        choice.addChoiceLabel(command.getGlobalIndex());
+                    }
+                    
+                    // Iterate over all updates of the current command.
+                    ValueType probabilitySum = storm::utility::zero<ValueType>();
+                    for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) {
+                        storm::prism::Update const& update = command.getUpdate(k);
+                        
+                        // Obtain target state index and add it to the list of known states. If it has not yet been
+                        // seen, we also add it to the set of states that have yet to be explored.
+                        StateType stateIndex = stateToIdCallback(applyUpdate(state, update));
+                        
+                        // Update the choice by adding the probability/target state to it.
+                        ValueType probability = evaluator.asRational(update.getLikelihoodExpression());
+                        choice.addProbability(stateIndex, probability);
+                        probabilitySum += probability;
+                    }
+                    
+                    // Create the state-action reward for the newly created choice.
+                    for (auto const& rewardModel : selectedRewardModels) {
+                        ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
+                        if (rewardModel.get().hasStateActionRewards()) {
+                            for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) {
+                                if (stateActionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(stateActionReward.getStatePredicateExpression())) {
+                                    stateActionRewardValue += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass();
+                                }
+                            }
+                        }
+                        choice.addChoiceReward(stateActionRewardValue);
+                    }
+                    
+                    // Check that the resulting distribution is in fact a distribution.
+                    STORM_LOG_THROW(!program.isDiscreteTimeModel() || comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Probabilities do not sum to one for command '" << command << "' (actually sum to " << probabilitySum << ").");
+                }
+            }
+            
+            return result;
+        }
+        
+        template<typename ValueType, typename StateType>
+        std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::getLabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback) {
+            std::vector<Choice<ValueType>> result;
+            
+            for (uint_fast64_t actionIndex : program.getSynchronizingActionIndices()) {
+                boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> optionalActiveCommandLists = getActiveCommandsByActionIndex(actionIndex);
+                
+                // Only process this action label, if there is at least one feasible solution.
+                if (optionalActiveCommandLists) {
+                    std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>> const& activeCommandList = optionalActiveCommandLists.get();
+                    std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>::const_iterator> iteratorList(activeCommandList.size());
+                    
+                    // Initialize the list of iterators.
+                    for (size_t i = 0; i < activeCommandList.size(); ++i) {
+                        iteratorList[i] = activeCommandList[i].cbegin();
+                    }
+                    
+                    // As long as there is one feasible combination of commands, keep on expanding it.
+                    bool done = false;
+                    while (!done) {
+                        boost::container::flat_map<CompressedState, ValueType>* currentTargetStates = new boost::container::flat_map<CompressedState, ValueType>();
+                        boost::container::flat_map<CompressedState, ValueType>* newTargetStates = new boost::container::flat_map<CompressedState, ValueType>();
+                        
+                        currentTargetStates->emplace(state, storm::utility::one<ValueType>());
+                        
+                        for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) {
+                            storm::prism::Command const& command = *iteratorList[i];
+                            
+                            for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) {
+                                storm::prism::Update const& update = command.getUpdate(j);
+                                
+                                for (auto const& stateProbabilityPair : *currentTargetStates) {
+                                    // Compute the new state under the current update and add it to the set of new target states.
+                                    CompressedState newTargetState = applyUpdate(stateProbabilityPair.first, update);
+                                    newTargetStates->emplace(newTargetState, stateProbabilityPair.second * evaluator.asRational(update.getLikelihoodExpression()));
+                                }
+                            }
+                            
+                            // If there is one more command to come, shift the target states one time step back.
+                            if (i < iteratorList.size() - 1) {
+                                delete currentTargetStates;
+                                currentTargetStates = newTargetStates;
+                                newTargetStates = new boost::container::flat_map<CompressedState, ValueType>();
+                            }
+                        }
+                        
+                        // At this point, we applied all commands of the current command combination and newTargetStates
+                        // contains all target states and their respective probabilities. That means we are now ready to
+                        // add the choice to the list of transitions.
+                        result.push_back(Choice<ValueType>(actionIndex));
+                        
+                        // Now create the actual distribution.
+                        Choice<ValueType>& choice = result.back();
+                        
+                        // Remember the command labels only if we were asked to.
+                        if (buildChoiceLabeling) {
+                            // Add the labels of all commands to this choice.
+                            for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) {
+                                choice.addChoiceLabel(iteratorList[i]->get().getGlobalIndex());
+                            }
+                        }
+                        
+                        // Add the probabilities/rates to the newly created choice.
+                        ValueType probabilitySum = storm::utility::zero<ValueType>();
+                        for (auto const& stateProbabilityPair : *newTargetStates) {
+                            StateType actualIndex = stateToIdCallback(stateProbabilityPair.first);
+                            choice.addProbability(actualIndex, stateProbabilityPair.second);
+                            probabilitySum += stateProbabilityPair.second;
+                        }
+                        
+                        // Check that the resulting distribution is in fact a distribution.
+                        STORM_LOG_THROW(!program.isDiscreteTimeModel() || !comparator.isConstant(probabilitySum) || comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Sum of update probabilities do not some to one for some command (actually sum to " << probabilitySum << ").");
+                        
+                        // Create the state-action reward for the newly created choice.
+                        for (auto const& rewardModel : selectedRewardModels) {
+                            ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
+                            if (rewardModel.get().hasStateActionRewards()) {
+                                for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) {
+                                    if (stateActionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(stateActionReward.getStatePredicateExpression())) {
+                                        stateActionRewardValue += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass();
+                                    }
+                                }
+                            }
+                            choice.addChoiceReward(stateActionRewardValue);
+                        }
+                        
+                        // Dispose of the temporary maps.
+                        delete currentTargetStates;
+                        delete newTargetStates;
+                        
+                        // Now, check whether there is one more command combination to consider.
+                        bool movedIterator = false;
+                        for (int_fast64_t j = iteratorList.size() - 1; j >= 0; --j) {
+                            ++iteratorList[j];
+                            if (iteratorList[j] != activeCommandList[j].end()) {
+                                movedIterator = true;
+                            } else {
+                                // Reset the iterator to the beginning of the list.
+                                iteratorList[j] = activeCommandList[j].begin();
+                            }
+                        }
+                        
+                        done = !movedIterator;
+                    }
+                }
+            }
+            
+            return result;
+        }
+        
+        template class PrismNextStateGenerator<double>;
+        template class PrismNextStateGenerator<storm::RationalFunction>;
+    }
+}
\ No newline at end of file
diff --git a/src/generator/PrismNextStateGenerator.h b/src/generator/PrismNextStateGenerator.h
new file mode 100644
index 000000000..d8eddc0ac
--- /dev/null
+++ b/src/generator/PrismNextStateGenerator.h
@@ -0,0 +1,108 @@
+#ifndef STORM_GENERATOR_PRISMNEXTSTATEGENERATOR_H_
+#define STORM_GENERATOR_PRISMNEXTSTATEGENERATOR_H_
+
+#include "src/generator/NextStateGenerator.h"
+#include "src/generator/VariableInformation.h"
+
+#include "src/storage/prism/Program.h"
+#include "src/storage/expressions/ExpressionEvaluator.h"
+
+#include "src/utility/ConstantsComparator.h"
+
+namespace storm {
+    namespace generator {
+        
+        template<typename ValueType, typename StateType = uint32_t>
+        class PrismNextStateGenerator : public NextStateGenerator<ValueType, StateType> {
+        public:
+            typedef typename NextStateGenerator<ValueType, StateType>::StateToIdCallback StateToIdCallback;
+            
+            PrismNextStateGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation, bool buildChoiceLabeling);
+            
+            /*!
+             * Adds a reward model to the list of selected reward models ()
+             */
+            void addRewardModel(storm::prism::RewardModel const& rewardModel);
+            
+            /*!
+             * Sets an expression such that if it evaluates to true in a state, prevents the exploration.
+             */
+            void setTerminalExpression(storm::expressions::Expression const& terminalExpression);
+            
+            virtual bool isDeterministicModel() const override;
+            virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) override;
+            virtual StateBehavior<ValueType, StateType> expand(CompressedState const& state, StateToIdCallback const& stateToIdCallback) override;
+
+        private:
+            /*!
+             * Applies an update to the state currently loaded into the evaluator and applies the resulting values to
+             * the given compressed state.
+             * @params state The state to which to apply the new values.
+             * @params update The update to apply.
+             * @return The resulting state.
+             */
+            CompressedState applyUpdate(CompressedState const& state, storm::prism::Update const& update);
+            
+            /*!
+             * Retrieves all commands that are labeled with the given label and enabled in the given state, grouped by
+             * modules.
+             *
+             * This function will iterate over all modules and retrieve all commands that are labeled with the given
+             * action and active (i.e. enabled) in the current state. The result is a list of lists of commands in which
+             * the inner lists contain all commands of exactly one module. If a module does not have *any* (including
+             * disabled) commands, there will not be a list of commands of that module in the result. If, however, the
+             * module has a command with a relevant label, but no enabled one, nothing is returned to indicate that there
+             * is no legal transition possible.
+             *
+             * @param The program in which to search for active commands.
+             * @param state The current state.
+             * @param actionIndex The index of the action label to select.
+             * @return A list of lists of active commands or nothing.
+             */
+            boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> getActiveCommandsByActionIndex(uint_fast64_t const& actionIndex);
+            
+            /*!
+             * Retrieves all unlabeled choices possible from the given state.
+             *
+             * @param state The state for which to retrieve the unlabeled choices.
+             * @return The unlabeled choices of the state.
+             */
+            std::vector<Choice<ValueType>> getUnlabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback);
+            
+            /*!
+             * Retrieves all labeled choices possible from the given state.
+             *
+             * @param state The state for which to retrieve the unlabeled choices.
+             * @return The labeled choices of the state.
+             */
+            std::vector<Choice<ValueType>> getLabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback);
+            
+            // The program used for the generation of next states.
+            storm::prism::Program const& program;
+            
+            // The reward models that need to be considered.
+            std::vector<std::reference_wrapper<storm::prism::RewardModel const>> selectedRewardModels;
+            
+            // A flag that stores whether at least one of the selected reward models has state-action rewards.
+            bool hasStateActionRewards;
+            
+            // A flag that stores whether or not to build the choice labeling.
+            bool buildChoiceLabeling;
+            
+            // An optional expression that governs which states must not be explored.
+            boost::optional<storm::expressions::Expression> terminalExpression;
+
+            // Information about how the variables are packed.
+            VariableInformation const& variableInformation;
+            
+            // An evaluator used to evaluate expressions.
+            storm::expressions::ExpressionEvaluator<ValueType> evaluator;
+            
+            // A comparator used to compare constants.
+            storm::utility::ConstantsComparator<ValueType> comparator;
+        };
+        
+    }
+}
+
+#endif /* STORM_GENERATOR_PRISMNEXTSTATEGENERATOR_H_ */
\ No newline at end of file
diff --git a/src/generator/PrismStateLabelingGenerator.cpp b/src/generator/PrismStateLabelingGenerator.cpp
new file mode 100644
index 000000000..6022ce063
--- /dev/null
+++ b/src/generator/PrismStateLabelingGenerator.cpp
@@ -0,0 +1,50 @@
+#include "src/generator/PrismStateLabelingGenerator.h"
+
+#include "src/generator/CompressedState.h"
+
+#include "src/storage/expressions/ExpressionEvaluator.h"
+
+namespace storm {
+    namespace generator {
+        
+        template<typename ValueType, typename StateType>
+        PrismStateLabelingGenerator<ValueType, StateType>::PrismStateLabelingGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation) : program(program), variableInformation(variableInformation) {
+            // Intentionally left empty.
+        }
+        
+        template<typename ValueType, typename StateType>
+        storm::models::sparse::StateLabeling PrismStateLabelingGenerator<ValueType, StateType>::generate(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices) {
+            std::vector<storm::prism::Label> const& labels = program.getLabels();
+            
+            storm::expressions::ExpressionEvaluator<ValueType> evaluator(program.getManager());
+            storm::models::sparse::StateLabeling result(states.size());
+            
+            // Initialize labeling.
+            for (auto const& label : labels) {
+                result.addLabel(label.getName());
+            }
+            for (auto const& stateIndexPair : states) {
+                unpackStateIntoEvaluator(stateIndexPair.first, variableInformation, evaluator);
+                
+                for (auto const& label : labels) {
+                    // Add label to state, if the corresponding expression is true.
+                    if (evaluator.asBool(label.getStatePredicateExpression())) {
+                        result.addLabelToState(label.getName(), stateIndexPair.second);
+                    }
+                }
+            }
+            
+            // Also label the initial state with the special label "init".
+            result.addLabel("init");
+            for (auto index : initialStateIndices) {
+                result.addLabelToState("init", index);
+            }
+            
+            return result;
+        }
+        
+        template class PrismStateLabelingGenerator<double, uint32_t>;
+        template class PrismStateLabelingGenerator<storm::RationalFunction, uint32_t>;
+
+    }
+}
\ No newline at end of file
diff --git a/src/generator/PrismStateLabelingGenerator.h b/src/generator/PrismStateLabelingGenerator.h
new file mode 100644
index 000000000..9859453ba
--- /dev/null
+++ b/src/generator/PrismStateLabelingGenerator.h
@@ -0,0 +1,31 @@
+#ifndef STORM_GENERATOR_PRISMSTATELABELINGGENERATOR_H_
+#define STORM_GENERATOR_PRISMSTATELABELINGGENERATOR_H_
+
+#include "src/generator/StateLabelingGenerator.h"
+
+#include "src/generator/VariableInformation.h"
+
+#include "src/storage/prism/Program.h"
+
+namespace storm {
+    namespace generator {
+        
+        template<typename ValueType, typename StateType = uint32_t>
+        class PrismStateLabelingGenerator : public StateLabelingGenerator<StateType> {
+        public:
+            PrismStateLabelingGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation);
+            
+            virtual storm::models::sparse::StateLabeling generate(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices = {}) override;
+            
+        private:
+            // The program for which to generate the labels.
+            storm::prism::Program const& program;
+            
+            // Information about how the variables are packed.
+            VariableInformation const& variableInformation;
+        };
+        
+    }
+}
+
+#endif /* STORM_GENERATOR_PRISMSTATELABELINGGENERATOR_H_ */
\ No newline at end of file
diff --git a/src/generator/StateBehavior.cpp b/src/generator/StateBehavior.cpp
new file mode 100644
index 000000000..e14417779
--- /dev/null
+++ b/src/generator/StateBehavior.cpp
@@ -0,0 +1,57 @@
+#include "src/generator/StateBehavior.h"
+
+#include "src/adapters/CarlAdapter.h"
+
+namespace storm {
+    namespace generator {
+
+        template<typename ValueType, typename StateType>
+        StateBehavior<ValueType, StateType>::StateBehavior() : expanded(false) {
+            // Intentionally left empty.
+        }
+        
+        template<typename ValueType, typename StateType>
+        void StateBehavior<ValueType, StateType>::addChoice(Choice<ValueType, StateType>&& choice) {
+            choices.push_back(std::move(choice));
+        }
+        
+        template<typename ValueType, typename StateType>
+        void StateBehavior<ValueType, StateType>::addStateReward(ValueType const& stateReward) {
+            stateRewards.push_back(stateReward);
+        }
+        
+        template<typename ValueType, typename StateType>
+        void StateBehavior<ValueType, StateType>::setExpanded(bool newValue) {
+            this->expanded = newValue;
+        }
+        
+        template<typename ValueType, typename StateType>
+        bool StateBehavior<ValueType, StateType>::wasExpanded() const {
+            return expanded;
+        }
+        
+        template<typename ValueType, typename StateType>
+        bool StateBehavior<ValueType, StateType>::empty() const {
+            return choices.empty();
+        }
+        
+        template<typename ValueType, typename StateType>
+        typename std::vector<Choice<ValueType, StateType>>::const_iterator StateBehavior<ValueType, StateType>::begin() const {
+            return choices.begin();
+        }
+        
+        template<typename ValueType, typename StateType>
+        typename std::vector<Choice<ValueType, StateType>>::const_iterator StateBehavior<ValueType, StateType>::end() const {
+            return choices.end();
+        }
+        
+        template<typename ValueType, typename StateType>
+        std::vector<ValueType> const& StateBehavior<ValueType, StateType>::getStateRewards() const {
+            return stateRewards;
+        }
+        
+        template class StateBehavior<double>;
+        template class StateBehavior<storm::RationalFunction>;
+
+    }
+}
\ No newline at end of file
diff --git a/src/generator/StateBehavior.h b/src/generator/StateBehavior.h
new file mode 100644
index 000000000..393c3280c
--- /dev/null
+++ b/src/generator/StateBehavior.h
@@ -0,0 +1,73 @@
+#ifndef STORM_GENERATOR_PRISM_STATEBEHAVIOR_H_
+#define STORM_GENERATOR_PRISM_STATEBEHAVIOR_H_
+
+#include <cstdint>
+
+#include "src/generator/Choice.h"
+
+namespace storm {
+    namespace generator {
+        
+        template<typename ValueType, typename StateType = uint32_t>
+        class StateBehavior {
+        public:
+            /*!
+             * Creates an empty behavior, i.e. the state was not yet expanded.
+             */
+            StateBehavior();
+            
+            /*!
+             * Adds the given choice to the behavior of the state.
+             */
+            void addChoice(Choice<ValueType, StateType>&& choice);
+            
+            /*!
+             * Adds the given state reward to the behavior of the state.
+             */
+            void addStateReward(ValueType const& stateReward);
+            
+            /*!
+             * Sets whether the state was expanded.
+             */
+            void setExpanded(bool newValue = true);
+            
+            /*!
+             * Retrieves whether the state was expanded.
+             */
+            bool wasExpanded() const;
+            
+            /*!
+             * Retrieves whether the behavior is empty in the sense that there are no available choices.
+             */
+            bool empty() const;
+            
+            /*!
+             * Retrieves an iterator to the choices available in the behavior.
+             */
+            typename std::vector<Choice<ValueType, StateType>>::const_iterator begin() const;
+
+            /*!
+             * Retrieves an iterator past the choices available in the behavior.
+             */
+            typename std::vector<Choice<ValueType, StateType>>::const_iterator end() const;
+
+            /*!
+             * Retrieves the list of state rewards under selected reward models.
+             */
+            std::vector<ValueType> const& getStateRewards() const;
+            
+        private:
+            // The choices available in the state.
+            std::vector<Choice<ValueType, StateType>> choices;
+            
+            // The state rewards (under the different, selected reward models) of the state.
+            std::vector<ValueType> stateRewards;
+            
+            // A flag indicating whether the state was actually expanded.
+            bool expanded;
+        };
+        
+    }
+}
+
+#endif /* STORM_GENERATOR_PRISM_STATEBEHAVIOR_H_ */
diff --git a/src/generator/StateLabelingGenerator.h b/src/generator/StateLabelingGenerator.h
new file mode 100644
index 000000000..17401c703
--- /dev/null
+++ b/src/generator/StateLabelingGenerator.h
@@ -0,0 +1,20 @@
+#ifndef STORM_GENERATOR_STATELABELINGGENERATOR_H_
+#define STORM_GENERATOR_STATELABELINGGENERATOR_H_
+
+#include "src/models/sparse/StateLabeling.h"
+
+#include "src/storage/BitVectorHashMap.h"
+
+namespace storm {
+    namespace generator {
+        
+        template<typename StateType = uint32_t>
+        class StateLabelingGenerator {
+        public:
+            virtual storm::models::sparse::StateLabeling generate(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices = {}) = 0;
+        };
+        
+    }
+}
+
+#endif /* STORM_GENERATOR_STATELABELINGGENERATOR_H_ */
\ No newline at end of file
diff --git a/src/generator/VariableInformation.cpp b/src/generator/VariableInformation.cpp
new file mode 100644
index 000000000..a5be93a6e
--- /dev/null
+++ b/src/generator/VariableInformation.cpp
@@ -0,0 +1,77 @@
+#include "src/generator/VariableInformation.h"
+
+#include "src/utility/macros.h"
+#include "src/exceptions/InvalidArgumentException.h"
+
+namespace storm {
+    namespace generator {
+        
+        BooleanVariableInformation::BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset) : variable(variable), initialValue(initialValue), bitOffset(bitOffset) {
+            // Intentionally left empty.
+        }
+        
+        IntegerVariableInformation::IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth) : variable(variable), initialValue(initialValue), lowerBound(lowerBound), upperBound(upperBound), bitOffset(bitOffset), bitWidth(bitWidth) {
+            // Intentionally left empty.
+        }
+        
+        VariableInformation::VariableInformation(storm::prism::Program const& program) : totalBitOffset(0) {
+            for (auto const& booleanVariable : program.getGlobalBooleanVariables()) {
+                booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), booleanVariable.getInitialValueExpression().evaluateAsBool(), totalBitOffset);
+                ++totalBitOffset;
+                booleanVariableToIndexMap[booleanVariable.getExpressionVariable()] = booleanVariables.size() - 1;
+            }
+            for (auto const& integerVariable : program.getGlobalIntegerVariables()) {
+                int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt();
+                int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt();
+                uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1)));
+                integerVariables.emplace_back(integerVariable.getExpressionVariable(), integerVariable.getInitialValueExpression().evaluateAsInt(), lowerBound, upperBound, totalBitOffset, bitwidth);
+                totalBitOffset += bitwidth;
+                integerVariableToIndexMap[integerVariable.getExpressionVariable()] = integerVariables.size() - 1;
+            }
+            for (auto const& module : program.getModules()) {
+                for (auto const& booleanVariable : module.getBooleanVariables()) {
+                    booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), booleanVariable.getInitialValueExpression().evaluateAsBool(), totalBitOffset);
+                    ++totalBitOffset;
+                    booleanVariableToIndexMap[booleanVariable.getExpressionVariable()] = booleanVariables.size() - 1;
+                }
+                for (auto const& integerVariable : module.getIntegerVariables()) {
+                    int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt();
+                    int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt();
+                    uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1)));
+                    integerVariables.emplace_back(integerVariable.getExpressionVariable(), integerVariable.getInitialValueExpression().evaluateAsInt(), lowerBound, upperBound, totalBitOffset, bitwidth);
+                    totalBitOffset += bitwidth;
+                    integerVariableToIndexMap[integerVariable.getExpressionVariable()] = integerVariables.size() - 1;
+                }
+            }
+        }
+        
+        uint_fast64_t VariableInformation::getTotalBitOffset(bool roundTo64Bit) const {
+            uint_fast64_t result = totalBitOffset;
+            if (roundTo64Bit) {
+                result = ((result >> 6) + 1) << 6;
+            }
+            return result;
+        }
+        
+        uint_fast64_t VariableInformation::getBitOffset(storm::expressions::Variable const& variable) const {
+            auto const& booleanIndex = booleanVariableToIndexMap.find(variable);
+            if (booleanIndex != booleanVariableToIndexMap.end()) {
+                return booleanVariables[booleanIndex->second].bitOffset;
+            }
+            auto const& integerIndex = integerVariableToIndexMap.find(variable);
+            if (integerIndex != integerVariableToIndexMap.end()) {
+                return integerVariables[integerIndex->second].bitOffset;
+            }
+            STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit index of unknown variable.");
+        }
+        
+        uint_fast64_t VariableInformation::getBitWidth(storm::expressions::Variable const& variable) const {
+            auto const& integerIndex = integerVariableToIndexMap.find(variable);
+            if (integerIndex != integerVariableToIndexMap.end()) {
+                return integerVariables[integerIndex->second].bitWidth;
+            }
+            STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit width of unknown variable.");
+        }
+        
+    }
+}
\ No newline at end of file
diff --git a/src/generator/VariableInformation.h b/src/generator/VariableInformation.h
new file mode 100644
index 000000000..8c2841dfd
--- /dev/null
+++ b/src/generator/VariableInformation.h
@@ -0,0 +1,75 @@
+#ifndef STORM_GENERATOR_VARIABLEINFORMATION_H_
+#define STORM_GENERATOR_VARIABLEINFORMATION_H_
+
+#include <vector>
+#include <boost/container/flat_map.hpp>
+
+#include "src/storage/expressions/Variable.h"
+#include "src/storage/prism/Program.h"
+
+namespace storm {
+    namespace generator {
+        
+        // A structure storing information about the boolean variables of the program.
+        struct BooleanVariableInformation {
+            BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset);
+            
+            // The boolean variable.
+            storm::expressions::Variable variable;
+            
+            // Its initial value.
+            bool initialValue;
+            
+            // Its bit offset in the compressed state.
+            uint_fast64_t bitOffset;
+        };
+        
+        // A structure storing information about the integer variables of the program.
+        struct IntegerVariableInformation {
+            IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth);
+            
+            // The integer variable.
+            storm::expressions::Variable variable;
+            
+            // Its initial value.
+            int_fast64_t initialValue;
+            
+            // The lower bound of its range.
+            int_fast64_t lowerBound;
+            
+            // The upper bound of its range.
+            int_fast64_t upperBound;
+            
+            // Its bit offset in the compressed state.
+            uint_fast64_t bitOffset;
+            
+            // Its bit width in the compressed state.
+            uint_fast64_t bitWidth;
+        };
+        
+        // A structure storing information about the used variables of the program.
+        struct VariableInformation {
+            VariableInformation() = default;
+            VariableInformation(storm::prism::Program const& program);
+            uint_fast64_t getTotalBitOffset(bool roundTo64Bit = false) const;
+            
+            // Provide methods to access the bit offset and width of variables in the compressed state.
+            uint_fast64_t getBitOffset(storm::expressions::Variable const& variable) const;
+            uint_fast64_t getBitWidth(storm::expressions::Variable const& variable) const;
+            
+            // The total bit offset over all variables.
+            uint_fast64_t totalBitOffset;
+            
+            // The known boolean variables.
+            boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> booleanVariableToIndexMap;
+            std::vector<BooleanVariableInformation> booleanVariables;
+            
+            // The known integer variables.
+            boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> integerVariableToIndexMap;
+            std::vector<IntegerVariableInformation> integerVariables;
+        };
+        
+    }
+}
+
+#endif /* STORM_GENERATOR_VARIABLEINFORMATION_H_ */
\ No newline at end of file
diff --git a/src/logic/BinaryBooleanStateFormula.cpp b/src/logic/BinaryBooleanStateFormula.cpp
index 180ea12c1..d6757e508 100644
--- a/src/logic/BinaryBooleanStateFormula.cpp
+++ b/src/logic/BinaryBooleanStateFormula.cpp
@@ -2,10 +2,13 @@
 
 #include "src/logic/FormulaVisitor.h"
 
+#include "src/utility/macros.h"
+#include "src/exceptions/InvalidPropertyException.h"
+
 namespace storm {
     namespace logic {
         BinaryBooleanStateFormula::BinaryBooleanStateFormula(OperatorType operatorType, std::shared_ptr<Formula const> const& leftSubformula, std::shared_ptr<Formula const> const& rightSubformula) : BinaryStateFormula(leftSubformula, rightSubformula), operatorType(operatorType) {
-            // Intentionally left empty.
+            STORM_LOG_THROW(this->getLeftSubformula().hasQualitativeResult() && this->getRightSubformula().hasQualitativeResult(), storm::exceptions::InvalidPropertyException, "Boolean formula must have subformulas with qualitative result.");
         }
         
         bool BinaryBooleanStateFormula::isBinaryBooleanStateFormula() const {
diff --git a/src/logic/BinaryBooleanStateFormula.h b/src/logic/BinaryBooleanStateFormula.h
index 6956e56c6..892d28bc9 100644
--- a/src/logic/BinaryBooleanStateFormula.h
+++ b/src/logic/BinaryBooleanStateFormula.h
@@ -25,7 +25,7 @@ namespace storm {
             
             virtual bool isAnd() const;
             virtual bool isOr() const;
-            
+                        
             virtual std::ostream& writeToStream(std::ostream& out) const override;
             
             virtual std::shared_ptr<Formula> substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const override;
diff --git a/src/logic/BinaryPathFormula.cpp b/src/logic/BinaryPathFormula.cpp
index 4e028d567..40c187013 100644
--- a/src/logic/BinaryPathFormula.cpp
+++ b/src/logic/BinaryPathFormula.cpp
@@ -32,5 +32,13 @@ namespace storm {
             this->getLeftSubformula().gatherReferencedRewardModels(referencedRewardModels);
             this->getRightSubformula().gatherReferencedRewardModels(referencedRewardModels);
         }
+        
+        bool BinaryPathFormula::hasQualitativeResult() const {
+            return false;
+        }
+        
+        bool BinaryPathFormula::hasQuantitativeResult() const {
+            return true;
+        }
     }
 }
\ No newline at end of file
diff --git a/src/logic/BinaryPathFormula.h b/src/logic/BinaryPathFormula.h
index fe0526bee..5550bd466 100644
--- a/src/logic/BinaryPathFormula.h
+++ b/src/logic/BinaryPathFormula.h
@@ -24,6 +24,9 @@ namespace storm {
             virtual void gatherAtomicLabelFormulas(std::vector<std::shared_ptr<AtomicLabelFormula const>>& atomicLabelFormulas) const override;
             virtual void gatherReferencedRewardModels(std::set<std::string>& referencedRewardModels) const override;
             
+            virtual bool hasQualitativeResult() const override;
+            virtual bool hasQuantitativeResult() const override;
+            
         private:
             std::shared_ptr<Formula const> leftSubformula;
             std::shared_ptr<Formula const> rightSubformula;
diff --git a/src/logic/ConditionalFormula.cpp b/src/logic/ConditionalFormula.cpp
index af3e1d95b..b12b831be 100644
--- a/src/logic/ConditionalFormula.cpp
+++ b/src/logic/ConditionalFormula.cpp
@@ -49,6 +49,14 @@ namespace storm {
             this->getConditionFormula().gatherReferencedRewardModels(referencedRewardModels);
         }
         
+        bool ConditionalFormula::hasQualitativeResult() const {
+            return false;
+        }
+        
+        bool ConditionalFormula::hasQuantitativeResult() const {
+            return true;
+        }
+        
         std::ostream& ConditionalFormula::writeToStream(std::ostream& out) const {
             this->getSubformula().writeToStream(out);
             out << " || ";
diff --git a/src/logic/ConditionalFormula.h b/src/logic/ConditionalFormula.h
index fc6b61655..66d71ebba 100644
--- a/src/logic/ConditionalFormula.h
+++ b/src/logic/ConditionalFormula.h
@@ -32,6 +32,9 @@ namespace storm {
             virtual void gatherAtomicLabelFormulas(std::vector<std::shared_ptr<AtomicLabelFormula const>>& atomicLabelFormulas) const override;
             virtual void gatherReferencedRewardModels(std::set<std::string>& referencedRewardModels) const override;
             
+            virtual bool hasQualitativeResult() const override;
+            virtual bool hasQuantitativeResult() const override;
+
         private:
             std::shared_ptr<Formula const> subformula;
             std::shared_ptr<Formula const> conditionFormula;
diff --git a/src/logic/EventuallyFormula.cpp b/src/logic/EventuallyFormula.cpp
index 71ff4ac54..56c9decff 100644
--- a/src/logic/EventuallyFormula.cpp
+++ b/src/logic/EventuallyFormula.cpp
@@ -7,10 +7,14 @@
 namespace storm {
     namespace logic {
         EventuallyFormula::EventuallyFormula(std::shared_ptr<Formula const> const& subformula, FormulaContext context) : UnaryPathFormula(subformula), context(context) {
-            STORM_LOG_THROW(context == FormulaContext::Probability || context == FormulaContext::Reward || context == FormulaContext::ExpectedTime, storm::exceptions::InvalidPropertyException, "Invalid context for formula.");
+            STORM_LOG_THROW(context == FormulaContext::Probability || context == FormulaContext::Reward || context == FormulaContext::Time, storm::exceptions::InvalidPropertyException, "Invalid context for formula.");
         }
         
         bool EventuallyFormula::isEventuallyFormula() const {
+            return true;
+        }
+        
+        bool EventuallyFormula::isReachabilityProbabilityFormula() const {
             return context == FormulaContext::Probability;
         }
         
@@ -18,8 +22,8 @@ namespace storm {
             return context == FormulaContext::Reward;
         }
         
-        bool EventuallyFormula::isReachbilityExpectedTimeFormula() const {
-            return context == FormulaContext::ExpectedTime;
+        bool EventuallyFormula::isReachabilityTimeFormula() const {
+            return context == FormulaContext::Time;
         }
         
         bool EventuallyFormula::isProbabilityPathFormula() const {
@@ -30,8 +34,8 @@ namespace storm {
             return this->isReachabilityRewardFormula();
         }
         
-        bool EventuallyFormula::isExpectedTimePathFormula() const {
-            return this->isReachbilityExpectedTimeFormula();
+        bool EventuallyFormula::isTimePathFormula() const {
+            return this->isReachabilityTimeFormula();
         }
         
         boost::any EventuallyFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const {
diff --git a/src/logic/EventuallyFormula.h b/src/logic/EventuallyFormula.h
index 5a0070a16..f3716fee9 100644
--- a/src/logic/EventuallyFormula.h
+++ b/src/logic/EventuallyFormula.h
@@ -15,11 +15,12 @@ namespace storm {
             }
             
             virtual bool isEventuallyFormula() const override;
+            virtual bool isReachabilityProbabilityFormula() const override;
             virtual bool isReachabilityRewardFormula() const override;
-            virtual bool isReachbilityExpectedTimeFormula() const override;
+            virtual bool isReachabilityTimeFormula() const override;
             virtual bool isProbabilityPathFormula() const override;
             virtual bool isRewardPathFormula() const override;
-            virtual bool isExpectedTimePathFormula() const override;
+            virtual bool isTimePathFormula() const override;
             
             virtual boost::any accept(FormulaVisitor const& visitor, boost::any const& data) const override;
 
diff --git a/src/logic/ExpectedTimeOperatorFormula.cpp b/src/logic/ExpectedTimeOperatorFormula.cpp
deleted file mode 100644
index 5dc8161ae..000000000
--- a/src/logic/ExpectedTimeOperatorFormula.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#include "src/logic/ExpectedTimeOperatorFormula.h"
-
-#include "src/logic/FormulaVisitor.h"
-
-namespace storm {
-    namespace logic {
-        ExpectedTimeOperatorFormula::ExpectedTimeOperatorFormula(std::shared_ptr<Formula const> const& subformula) : ExpectedTimeOperatorFormula(boost::none, boost::none, subformula) {
-            // Intentionally left empty.
-        }
-        
-        ExpectedTimeOperatorFormula::ExpectedTimeOperatorFormula(Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : ExpectedTimeOperatorFormula(boost::none, bound, subformula) {
-            // Intentionally left empty.
-        }
-        
-        ExpectedTimeOperatorFormula::ExpectedTimeOperatorFormula(OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : ExpectedTimeOperatorFormula(boost::optional<OptimizationDirection>(optimalityType), bound, subformula) {
-            // Intentionally left empty.
-        }
-        
-        ExpectedTimeOperatorFormula::ExpectedTimeOperatorFormula(OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula) : ExpectedTimeOperatorFormula(boost::optional<OptimizationDirection>(optimalityType), boost::none, subformula) {
-            // Intentionally left empty.
-        }
-        
-        bool ExpectedTimeOperatorFormula::isExpectedTimeOperatorFormula() const {
-            return true;
-        }
-        
-        boost::any ExpectedTimeOperatorFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const {
-            return visitor.visit(*this, data);
-        }
-        
-        ExpectedTimeOperatorFormula::ExpectedTimeOperatorFormula(boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula) : OperatorFormula(optimalityType, bound, subformula) {
-            // Intentionally left empty.
-        }
-        
-        std::shared_ptr<Formula> ExpectedTimeOperatorFormula::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const {
-            return std::make_shared<ExpectedTimeOperatorFormula>(this->optimalityType, this->bound, this->getSubformula().substitute(substitution));
-        }
-        
-        std::ostream& ExpectedTimeOperatorFormula::writeToStream(std::ostream& out) const {
-            out << "ET";
-            OperatorFormula::writeToStream(out);
-            return out;
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/logic/ExpectedTimeOperatorFormula.h b/src/logic/ExpectedTimeOperatorFormula.h
deleted file mode 100644
index 5e1925b44..000000000
--- a/src/logic/ExpectedTimeOperatorFormula.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef STORM_LOGIC_EXPECTEDTIMEOPERATORFORMULA_H_
-#define STORM_LOGIC_EXPECTEDTIMEOPERATORFORMULA_H_
-
-#include "src/logic/OperatorFormula.h"
-
-#include "src/logic/FormulaVisitor.h"
-
-namespace storm {
-    namespace logic {
-        class ExpectedTimeOperatorFormula : public OperatorFormula {
-        public:
-            ExpectedTimeOperatorFormula(std::shared_ptr<Formula const> const& subformula);
-            ExpectedTimeOperatorFormula(Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula);
-            ExpectedTimeOperatorFormula(OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula);
-            ExpectedTimeOperatorFormula(OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula);
-            ExpectedTimeOperatorFormula(boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula);
-            
-            virtual ~ExpectedTimeOperatorFormula() {
-                // Intentionally left empty.
-            }
-            
-            virtual bool isExpectedTimeOperatorFormula() const override;
-
-            virtual boost::any accept(FormulaVisitor const& visitor, boost::any const& data) const override;
-            
-            virtual std::shared_ptr<Formula> substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const override;
-            
-            virtual std::ostream& writeToStream(std::ostream& out) const override;
-        };
-    }
-}
-
-#endif /* STORM_LOGIC_EXPECTEDTIMEOPERATORFORMULA_H_ */
\ No newline at end of file
diff --git a/src/logic/Formula.cpp b/src/logic/Formula.cpp
index 6c7084f53..c48548f10 100644
--- a/src/logic/Formula.cpp
+++ b/src/logic/Formula.cpp
@@ -62,6 +62,10 @@ namespace storm {
             return false;
         }
         
+        bool Formula::isReachabilityProbabilityFormula() const {
+            return false;
+        }
+        
         bool Formula::isGloballyFormula() const {
             return false;
         }
@@ -90,7 +94,7 @@ namespace storm {
             return false;
         }
         
-        bool Formula::isExpectedTimePathFormula() const {
+        bool Formula::isTimePathFormula() const {
             return false;
         }
         
@@ -102,7 +106,7 @@ namespace storm {
             return false;
         }
         
-        bool Formula::isExpectedTimeOperatorFormula() const {
+        bool Formula::isTimeOperatorFormula() const {
             return false;
         }
         
@@ -122,7 +126,7 @@ namespace storm {
             return false;
         }
         
-        bool Formula::isReachbilityExpectedTimeFormula() const {
+        bool Formula::isReachabilityTimeFormula() const {
             return false;
         }
         
@@ -138,6 +142,14 @@ namespace storm {
             return false;
         }
         
+        bool Formula::hasQualitativeResult() const {
+            return true;
+        }
+        
+        bool Formula::hasQuantitativeResult() const {
+            return false;
+        }
+        
         bool Formula::isInFragment(FragmentSpecification const& fragment) const {
             FragmentChecker checker;
             return checker.conformsToSpecification(*this, fragment);
@@ -264,6 +276,22 @@ namespace storm {
             return dynamic_cast<EventuallyFormula const&>(*this);
         }
         
+        EventuallyFormula& Formula::asReachabilityProbabilityFormula() {
+            return dynamic_cast<EventuallyFormula&>(*this);
+        }
+        
+        EventuallyFormula const& Formula::asReachabilityProbabilityFormula() const {
+            return dynamic_cast<EventuallyFormula const&>(*this);
+        }
+        
+        EventuallyFormula& Formula::asReachabilityTimeFormula() {
+            return dynamic_cast<EventuallyFormula&>(*this);
+        }
+
+        EventuallyFormula const& Formula::asReachabilityTimeFormula() const {
+            return dynamic_cast<EventuallyFormula const&>(*this);
+        }
+        
         GloballyFormula& Formula::asGloballyFormula() {
             return dynamic_cast<GloballyFormula&>(*this);
         }
@@ -304,12 +332,12 @@ namespace storm {
             return dynamic_cast<LongRunAverageOperatorFormula const&>(*this);
         }
         
-        ExpectedTimeOperatorFormula& Formula::asExpectedTimeOperatorFormula() {
-            return dynamic_cast<ExpectedTimeOperatorFormula&>(*this);
+        TimeOperatorFormula& Formula::asTimeOperatorFormula() {
+            return dynamic_cast<TimeOperatorFormula&>(*this);
         }
         
-        ExpectedTimeOperatorFormula const& Formula::asExpectedTimeOperatorFormula() const {
-            return dynamic_cast<ExpectedTimeOperatorFormula const&>(*this);
+        TimeOperatorFormula const& Formula::asTimeOperatorFormula() const {
+            return dynamic_cast<TimeOperatorFormula const&>(*this);
         }
         
         CumulativeRewardFormula& Formula::asCumulativeRewardFormula() {
diff --git a/src/logic/Formula.h b/src/logic/Formula.h
index 7d77de7b3..b77ecfb20 100644
--- a/src/logic/Formula.h
+++ b/src/logic/Formula.h
@@ -42,7 +42,7 @@ namespace storm {
             
             virtual bool isProbabilityPathFormula() const;
             virtual bool isRewardPathFormula() const;
-            virtual bool isExpectedTimePathFormula() const;
+            virtual bool isTimePathFormula() const;
 
             virtual bool isBinaryBooleanStateFormula() const;
             virtual bool isUnaryBooleanStateFormula() const;
@@ -50,7 +50,7 @@ namespace storm {
             // Operator formulas.
             virtual bool isOperatorFormula() const;
             virtual bool isLongRunAverageOperatorFormula() const;
-            virtual bool isExpectedTimeOperatorFormula() const;
+            virtual bool isTimeOperatorFormula() const;
             virtual bool isProbabilityOperatorFormula() const;
             virtual bool isRewardOperatorFormula() const;
 
@@ -65,8 +65,9 @@ namespace storm {
             virtual bool isNextFormula() const;
             virtual bool isUntilFormula() const;
             virtual bool isBoundedUntilFormula() const;
-            virtual bool isEventuallyFormula() const;
             virtual bool isGloballyFormula() const;
+            virtual bool isEventuallyFormula() const;
+            virtual bool isReachabilityProbabilityFormula() const;
 
             // Reward formulas.
             virtual bool isCumulativeRewardFormula() const;
@@ -75,7 +76,7 @@ namespace storm {
             virtual bool isLongRunAverageRewardFormula() const;
             
             // Expected time formulas.
-            virtual bool isReachbilityExpectedTimeFormula() const;
+            virtual bool isReachabilityTimeFormula() const;
             
             // Type checks for abstract intermediate classes.
             virtual bool isBinaryPathFormula() const;
@@ -83,6 +84,10 @@ namespace storm {
             virtual bool isUnaryPathFormula() const;
             virtual bool isUnaryStateFormula() const;
 
+            // Accessors for the return type of a formula.
+            virtual bool hasQualitativeResult() const;
+            virtual bool hasQuantitativeResult() const;
+            
             bool isInFragment(FragmentSpecification const& fragment) const;
             FormulaInformation info() const;
             
@@ -126,8 +131,14 @@ namespace storm {
             EventuallyFormula& asEventuallyFormula();
             EventuallyFormula const& asEventuallyFormula() const;
             
+            EventuallyFormula& asReachabilityProbabilityFormula();
+            EventuallyFormula const& asReachabilityProbabilityFormula() const;
+            
             EventuallyFormula& asReachabilityRewardFormula();
             EventuallyFormula const& asReachabilityRewardFormula() const;
+
+            EventuallyFormula& asReachabilityTimeFormula();
+            EventuallyFormula const& asReachabilityTimeFormula() const;
             
             GloballyFormula& asGloballyFormula();
             GloballyFormula const& asGloballyFormula() const;
@@ -147,8 +158,8 @@ namespace storm {
             LongRunAverageOperatorFormula& asLongRunAverageOperatorFormula();
             LongRunAverageOperatorFormula const& asLongRunAverageOperatorFormula() const;
 
-            ExpectedTimeOperatorFormula& asExpectedTimeOperatorFormula();
-            ExpectedTimeOperatorFormula const& asExpectedTimeOperatorFormula() const;
+            TimeOperatorFormula& asTimeOperatorFormula();
+            TimeOperatorFormula const& asTimeOperatorFormula() const;
             
             CumulativeRewardFormula& asCumulativeRewardFormula();
             CumulativeRewardFormula const& asCumulativeRewardFormula() const;
diff --git a/src/logic/FormulaContext.h b/src/logic/FormulaContext.h
index 41113cb8d..70ab01a3d 100644
--- a/src/logic/FormulaContext.h
+++ b/src/logic/FormulaContext.h
@@ -4,7 +4,7 @@
 namespace storm {
     namespace logic {
         
-        enum class FormulaContext { Undefined, Probability, Reward, LongRunAverage, ExpectedTime };
+        enum class FormulaContext { Undefined, Probability, Reward, LongRunAverage, Time };
         
     }
 }
diff --git a/src/logic/FormulaInformationVisitor.cpp b/src/logic/FormulaInformationVisitor.cpp
index f8ef57f92..b44045766 100644
--- a/src/logic/FormulaInformationVisitor.cpp
+++ b/src/logic/FormulaInformationVisitor.cpp
@@ -41,7 +41,7 @@ namespace storm {
             return f.getSubformula().accept(*this);
         }
         
-        boost::any FormulaInformationVisitor::visit(ExpectedTimeOperatorFormula const& f, boost::any const& data) const {
+        boost::any FormulaInformationVisitor::visit(TimeOperatorFormula const& f, boost::any const& data) const {
             return f.getSubformula().accept(*this);
         }
         
diff --git a/src/logic/FormulaInformationVisitor.h b/src/logic/FormulaInformationVisitor.h
index 2e2cc0d6d..8e706cabf 100644
--- a/src/logic/FormulaInformationVisitor.h
+++ b/src/logic/FormulaInformationVisitor.h
@@ -19,7 +19,7 @@ namespace storm {
             virtual boost::any visit(ConditionalFormula const& f, boost::any const& data) const override;
             virtual boost::any visit(CumulativeRewardFormula const& f, boost::any const& data) const override;
             virtual boost::any visit(EventuallyFormula const& f, boost::any const& data) const override;
-            virtual boost::any visit(ExpectedTimeOperatorFormula const& f, boost::any const& data) const override;
+            virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const override;
             virtual boost::any visit(GloballyFormula const& f, boost::any const& data) const override;
             virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const override;
             virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const override;
diff --git a/src/logic/FormulaVisitor.h b/src/logic/FormulaVisitor.h
index a2e5b1a4f..1208b63a6 100644
--- a/src/logic/FormulaVisitor.h
+++ b/src/logic/FormulaVisitor.h
@@ -18,7 +18,7 @@ namespace storm {
             virtual boost::any visit(ConditionalFormula const& f, boost::any const& data) const = 0;
             virtual boost::any visit(CumulativeRewardFormula const& f, boost::any const& data) const = 0;
             virtual boost::any visit(EventuallyFormula const& f, boost::any const& data) const = 0;
-            virtual boost::any visit(ExpectedTimeOperatorFormula const& f, boost::any const& data) const = 0;
+            virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const = 0;
             virtual boost::any visit(GloballyFormula const& f, boost::any const& data) const = 0;
             virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const = 0;
             virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const = 0;
diff --git a/src/logic/Formulas.h b/src/logic/Formulas.h
index a5218eeb8..7183dcb01 100644
--- a/src/logic/Formulas.h
+++ b/src/logic/Formulas.h
@@ -18,7 +18,7 @@
 #include "src/logic/RewardOperatorFormula.h"
 #include "src/logic/StateFormula.h"
 #include "src/logic/LongRunAverageOperatorFormula.h"
-#include "src/logic/ExpectedTimeOperatorFormula.h"
+#include "src/logic/TimeOperatorFormula.h"
 #include "src/logic/UnaryBooleanStateFormula.h"
 #include "src/logic/UnaryPathFormula.h"
 #include "src/logic/UnaryStateFormula.h"
diff --git a/src/logic/FormulasForwardDeclarations.h b/src/logic/FormulasForwardDeclarations.h
index 13b4c326c..43fcf0ab9 100644
--- a/src/logic/FormulasForwardDeclarations.h
+++ b/src/logic/FormulasForwardDeclarations.h
@@ -15,7 +15,7 @@ namespace storm {
         class ConditionalFormula;
         class CumulativeRewardFormula;
         class EventuallyFormula;
-        class ExpectedTimeOperatorFormula;
+        class TimeOperatorFormula;
         class GloballyFormula;
         class InstantaneousRewardFormula;
         class LongRunAverageOperatorFormula;
diff --git a/src/logic/FragmentChecker.cpp b/src/logic/FragmentChecker.cpp
index 6bf03ddb7..09bfc31dd 100644
--- a/src/logic/FragmentChecker.cpp
+++ b/src/logic/FragmentChecker.cpp
@@ -73,7 +73,7 @@ namespace storm {
             }
             if (inherited.getSpecification().areOnlyEventuallyFormuluasInConditionalFormulasAllowed()) {
                 if (f.isConditionalProbabilityFormula()) {
-                    result = result && f.getSubformula().isEventuallyFormula() && f.getConditionFormula().isEventuallyFormula();
+                    result = result && f.getSubformula().isReachabilityProbabilityFormula() && f.getConditionFormula().isReachabilityProbabilityFormula();
                 } else if (f.isConditionalRewardFormula()) {
                     result = result && f.getSubformula().isReachabilityRewardFormula() && f.getConditionFormula().isEventuallyFormula();
                 }
@@ -91,26 +91,29 @@ namespace storm {
         boost::any FragmentChecker::visit(EventuallyFormula const& f, boost::any const& data) const {
             InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
             bool result = true;
-            if (f.isEventuallyFormula()) {
-                result = inherited.getSpecification().areEventuallyFormulasAllowed();
+            if (f.isReachabilityProbabilityFormula()) {
+                result = inherited.getSpecification().areReachabilityProbabilityFormulasAllowed();
                 if (!inherited.getSpecification().areNestedPathFormulasAllowed()) {
                     result = result && !f.getSubformula().isPathFormula();
                 }
             } else if (f.isReachabilityRewardFormula()) {
                 result = result && inherited.getSpecification().areReachabilityRewardFormulasAllowed();
                 result = result && f.getSubformula().isStateFormula();
-            } else if (f.isReachbilityExpectedTimeFormula()) {
-                result = result && inherited.getSpecification().areReachbilityExpectedTimeFormulasAllowed();
+            } else if (f.isReachabilityTimeFormula()) {
+                result = result && inherited.getSpecification().areReachbilityTimeFormulasAllowed();
                 result = result && f.getSubformula().isStateFormula();
             }
             result = result && boost::any_cast<bool>(f.getSubformula().accept(*this, data));
             return result;
         }
         
-        boost::any FragmentChecker::visit(ExpectedTimeOperatorFormula const& f, boost::any const& data) const {
+        boost::any FragmentChecker::visit(TimeOperatorFormula const& f, boost::any const& data) const {
             InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
-            bool result = inherited.getSpecification().areExpectedTimeOperatorsAllowed();
-            result = result && f.getSubformula().isExpectedTimePathFormula();
+            bool result = inherited.getSpecification().areTimeOperatorsAllowed();
+            result = result && (!f.hasQualitativeResult() || inherited.getSpecification().areQualitativeOperatorResultsAllowed());
+            result = result && (!f.hasQuantitativeResult() || inherited.getSpecification().areQuantitativeOperatorResultsAllowed());
+            result = result && f.getSubformula().isTimePathFormula();
+            result = result && (inherited.getSpecification().isVarianceMeasureTypeAllowed() || f.getMeasureType() == RewardMeasureType::Expectation);
             if (!inherited.getSpecification().areNestedOperatorsAllowed()) {
                 result = result && boost::any_cast<bool>(f.getSubformula().accept(*this, InheritedInformation(inherited.getSpecification().copy().setOperatorsAllowed(false))));
             } else {
@@ -164,6 +167,8 @@ namespace storm {
         boost::any FragmentChecker::visit(ProbabilityOperatorFormula const& f, boost::any const& data) const {
             InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
             bool result = inherited.getSpecification().areProbabilityOperatorsAllowed();
+            result = result && (!f.hasQualitativeResult() || inherited.getSpecification().areQualitativeOperatorResultsAllowed());
+            result = result && (!f.hasQuantitativeResult() || inherited.getSpecification().areQuantitativeOperatorResultsAllowed());
             result = result && (f.getSubformula().isProbabilityPathFormula() || f.getSubformula().isConditionalProbabilityFormula());
             if (!inherited.getSpecification().areNestedOperatorsAllowed()) {
                 result = result && boost::any_cast<bool>(f.getSubformula().accept(*this, InheritedInformation(inherited.getSpecification().copy().setOperatorsAllowed(false))));
@@ -176,7 +181,10 @@ namespace storm {
         boost::any FragmentChecker::visit(RewardOperatorFormula const& f, boost::any const& data) const {
             InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
             bool result = inherited.getSpecification().areRewardOperatorsAllowed();
+            result = result && (!f.hasQualitativeResult() || inherited.getSpecification().areQualitativeOperatorResultsAllowed());
+            result = result && (!f.hasQuantitativeResult() || inherited.getSpecification().areQuantitativeOperatorResultsAllowed());
             result = result && (f.getSubformula().isRewardPathFormula() || f.getSubformula().isConditionalRewardFormula());
+            result = result && (inherited.getSpecification().isVarianceMeasureTypeAllowed() || f.getMeasureType() == RewardMeasureType::Expectation);
             if (!inherited.getSpecification().areNestedOperatorsAllowed()) {
                 result = result && boost::any_cast<bool>(f.getSubformula().accept(*this, InheritedInformation(inherited.getSpecification().copy().setOperatorsAllowed(false))));
             } else {
diff --git a/src/logic/FragmentChecker.h b/src/logic/FragmentChecker.h
index 3d22390e6..9b0377aba 100644
--- a/src/logic/FragmentChecker.h
+++ b/src/logic/FragmentChecker.h
@@ -20,7 +20,7 @@ namespace storm {
             virtual boost::any visit(ConditionalFormula const& f, boost::any const& data) const override;
             virtual boost::any visit(CumulativeRewardFormula const& f, boost::any const& data) const override;
             virtual boost::any visit(EventuallyFormula const& f, boost::any const& data) const override;
-            virtual boost::any visit(ExpectedTimeOperatorFormula const& f, boost::any const& data) const override;
+            virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const override;
             virtual boost::any visit(GloballyFormula const& f, boost::any const& data) const override;
             virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const override;
             virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const override;
diff --git a/src/logic/FragmentSpecification.cpp b/src/logic/FragmentSpecification.cpp
index 378fe3a88..31f2eeee2 100644
--- a/src/logic/FragmentSpecification.cpp
+++ b/src/logic/FragmentSpecification.cpp
@@ -22,7 +22,7 @@ namespace storm {
             
             pctl.setProbabilityOperatorsAllowed(true);
             pctl.setGloballyFormulasAllowed(true);
-            pctl.setEventuallyFormulasAllowed(true);
+            pctl.setReachabilityProbabilityFormulasAllowed(true);
             pctl.setNextFormulasAllowed(true);
             pctl.setUntilFormulasAllowed(true);
             pctl.setBoundedUntilFormulasAllowed(true);
@@ -70,7 +70,7 @@ namespace storm {
             longRunAverageOperator = false;
             
             globallyFormula = false;
-            eventuallyFormula = false;
+            reachabilityProbabilityFormula = false;
             nextFormula = false;
             untilFormula = false;
             boundedUntilFormula = false;
@@ -89,13 +89,17 @@ namespace storm {
             conditionalProbabilityFormula = false;
             conditionalRewardFormula = false;
             
-            reachabilityExpectedTimeFormula = false;
+            reachabilityTimeFormula = false;
             
             nestedOperators = true;
             nestedPathFormulas = false;
             onlyEventuallyFormuluasInConditionalFormulas = true;
             stepBoundedUntilFormulas = false;
             timeBoundedUntilFormulas = false;
+            varianceAsMeasureType = false;
+            
+            qualitativeOperatorResults = true;
+            quantitativeOperatorResults = true;
         }
         
         FragmentSpecification FragmentSpecification::copy() const {
@@ -120,11 +124,11 @@ namespace storm {
             return *this;
         }
         
-        bool FragmentSpecification::areExpectedTimeOperatorsAllowed() const {
+        bool FragmentSpecification::areTimeOperatorsAllowed() const {
             return expectedTimeOperator;
         }
         
-        FragmentSpecification& FragmentSpecification::setExpectedTimeOperatorsAllowed(bool newValue) {
+        FragmentSpecification& FragmentSpecification::setTimeOperatorsAllowed(bool newValue) {
             this->expectedTimeOperator = newValue;
             return *this;
         }
@@ -147,12 +151,12 @@ namespace storm {
             return *this;
         }
         
-        bool FragmentSpecification::areEventuallyFormulasAllowed() const {
-            return eventuallyFormula;
+        bool FragmentSpecification::areReachabilityProbabilityFormulasAllowed() const {
+            return reachabilityProbabilityFormula;
         }
         
-        FragmentSpecification& FragmentSpecification::setEventuallyFormulasAllowed(bool newValue) {
-            this->eventuallyFormula = newValue;
+        FragmentSpecification& FragmentSpecification::setReachabilityProbabilityFormulasAllowed(bool newValue) {
+            this->reachabilityProbabilityFormula = newValue;
             return *this;
         }
         
@@ -282,12 +286,12 @@ namespace storm {
             return *this;
         }
         
-        bool FragmentSpecification::areReachbilityExpectedTimeFormulasAllowed() const {
-            return reachabilityExpectedTimeFormula;
+        bool FragmentSpecification::areReachbilityTimeFormulasAllowed() const {
+            return reachabilityTimeFormula;
         }
             
-        FragmentSpecification& FragmentSpecification::setReachbilityExpectedTimeFormulasAllowed(bool newValue) {
-            this->reachabilityExpectedTimeFormula = newValue;
+        FragmentSpecification& FragmentSpecification::setReachbilityTimeFormulasAllowed(bool newValue) {
+            this->reachabilityTimeFormula = newValue;
             return *this;
         }
         
@@ -340,13 +344,13 @@ namespace storm {
             this->setProbabilityOperatorsAllowed(newValue);
             this->setRewardOperatorsAllowed(newValue);
             this->setLongRunAverageOperatorsAllowed(newValue);
-            this->setExpectedTimeOperatorsAllowed(newValue);
+            this->setTimeOperatorsAllowed(newValue);
             return *this;
         }
         
-        FragmentSpecification& FragmentSpecification::setExpectedTimeAllowed(bool newValue) {
-            this->setExpectedTimeOperatorsAllowed(newValue);
-            this->setReachbilityExpectedTimeFormulasAllowed(newValue);
+        FragmentSpecification& FragmentSpecification::setTimeAllowed(bool newValue) {
+            this->setTimeOperatorsAllowed(newValue);
+            this->setReachbilityTimeFormulasAllowed(newValue);
             return *this;
         }
         
@@ -355,5 +359,33 @@ namespace storm {
             return *this;
         }
         
+        bool FragmentSpecification::isVarianceMeasureTypeAllowed() const {
+            return varianceAsMeasureType;
+        }
+        
+        FragmentSpecification& FragmentSpecification::setVarianceMeasureTypeAllowed(bool newValue) {
+            this->varianceAsMeasureType = newValue;
+            return *this;
+        }
+     
+        bool FragmentSpecification::areQuantitativeOperatorResultsAllowed() const {
+            return this->quantitativeOperatorResults;
+        }
+        
+        FragmentSpecification& FragmentSpecification::setQuantitativeOperatorResultsAllowed(bool newValue) {
+            this->quantitativeOperatorResults = newValue;
+            return *this;
+        }
+        
+        bool FragmentSpecification::areQualitativeOperatorResultsAllowed() const {
+            return this->qualitativeOperatorResults;
+        }
+        
+        FragmentSpecification& FragmentSpecification::setQualitativeOperatorResultsAllowed(bool newValue) {
+            this->qualitativeOperatorResults = newValue;
+            return *this;
+        }
+
+        
     }
 }
\ No newline at end of file
diff --git a/src/logic/FragmentSpecification.h b/src/logic/FragmentSpecification.h
index 1bd46f4f7..5074187b8 100644
--- a/src/logic/FragmentSpecification.h
+++ b/src/logic/FragmentSpecification.h
@@ -19,8 +19,8 @@ namespace storm {
             bool areRewardOperatorsAllowed() const;
             FragmentSpecification& setRewardOperatorsAllowed(bool newValue);
             
-            bool areExpectedTimeOperatorsAllowed() const;
-            FragmentSpecification& setExpectedTimeOperatorsAllowed(bool newValue);
+            bool areTimeOperatorsAllowed() const;
+            FragmentSpecification& setTimeOperatorsAllowed(bool newValue);
 
             bool areLongRunAverageOperatorsAllowed() const;
             FragmentSpecification& setLongRunAverageOperatorsAllowed(bool newValue);
@@ -28,8 +28,8 @@ namespace storm {
             bool areGloballyFormulasAllowed() const;
             FragmentSpecification& setGloballyFormulasAllowed(bool newValue);
 
-            bool areEventuallyFormulasAllowed() const;
-            FragmentSpecification& setEventuallyFormulasAllowed(bool newValue);
+            bool areReachabilityProbabilityFormulasAllowed() const;
+            FragmentSpecification& setReachabilityProbabilityFormulasAllowed(bool newValue);
 
             bool areNextFormulasAllowed() const;
             FragmentSpecification& setNextFormulasAllowed(bool newValue);
@@ -73,8 +73,8 @@ namespace storm {
             bool areConditionalRewardFormulasFormulasAllowed() const;
             FragmentSpecification& setConditionalRewardFormulasAllowed(bool newValue);
 
-            bool areReachbilityExpectedTimeFormulasAllowed() const;
-            FragmentSpecification& setReachbilityExpectedTimeFormulasAllowed(bool newValue);
+            bool areReachbilityTimeFormulasAllowed() const;
+            FragmentSpecification& setReachbilityTimeFormulasAllowed(bool newValue);
 
             bool areNestedOperatorsAllowed() const;
             FragmentSpecification& setNestedOperatorsAllowed(bool newValue);
@@ -91,8 +91,17 @@ namespace storm {
             bool areTimeBoundedUntilFormulasAllowed() const;
             FragmentSpecification& setTimeBoundedUntilFormulasAllowed(bool newValue);
             
+            bool isVarianceMeasureTypeAllowed() const;
+            FragmentSpecification& setVarianceMeasureTypeAllowed(bool newValue);
+            
+            bool areQuantitativeOperatorResultsAllowed() const;
+            FragmentSpecification& setQuantitativeOperatorResultsAllowed(bool newValue);
+
+            bool areQualitativeOperatorResultsAllowed() const;
+            FragmentSpecification& setQualitativeOperatorResultsAllowed(bool newValue);
+            
             FragmentSpecification& setOperatorsAllowed(bool newValue);
-            FragmentSpecification& setExpectedTimeAllowed(bool newValue);
+            FragmentSpecification& setTimeAllowed(bool newValue);
             FragmentSpecification& setLongRunAverageProbabilitiesAllowed(bool newValue);
             
         private:
@@ -103,7 +112,7 @@ namespace storm {
             bool longRunAverageOperator;
             
             bool globallyFormula;
-            bool eventuallyFormula;
+            bool reachabilityProbabilityFormula;
             bool nextFormula;
             bool untilFormula;
             bool boundedUntilFormula;
@@ -122,7 +131,7 @@ namespace storm {
             bool conditionalProbabilityFormula;
             bool conditionalRewardFormula;
             
-            bool reachabilityExpectedTimeFormula;
+            bool reachabilityTimeFormula;
             
             // Members that indicate certain restrictions.
             bool nestedOperators;
@@ -130,6 +139,9 @@ namespace storm {
             bool onlyEventuallyFormuluasInConditionalFormulas;
             bool stepBoundedUntilFormulas;
             bool timeBoundedUntilFormulas;
+            bool varianceAsMeasureType;
+            bool quantitativeOperatorResults;
+            bool qualitativeOperatorResults;
         };
         
         // Propositional.
diff --git a/src/logic/LongRunAverageOperatorFormula.cpp b/src/logic/LongRunAverageOperatorFormula.cpp
index c9d781905..f2e253ead 100644
--- a/src/logic/LongRunAverageOperatorFormula.cpp
+++ b/src/logic/LongRunAverageOperatorFormula.cpp
@@ -2,24 +2,15 @@
 
 #include "src/logic/FormulaVisitor.h"
 
+#include "src/utility/macros.h"
+#include "src/exceptions/InvalidPropertyException.h"
+
 namespace storm {
     namespace logic {
-        LongRunAverageOperatorFormula::LongRunAverageOperatorFormula(std::shared_ptr<Formula const> const& subformula) : LongRunAverageOperatorFormula(boost::none, boost::none, subformula) {
-            // Intentionally left empty.
-        }
-        
-        LongRunAverageOperatorFormula::LongRunAverageOperatorFormula(Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : LongRunAverageOperatorFormula(boost::none, bound, subformula) {
-            // Intentionally left empty.
-        }
-        
-        LongRunAverageOperatorFormula::LongRunAverageOperatorFormula(OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : LongRunAverageOperatorFormula(boost::optional<OptimizationDirection>(optimalityType), bound, subformula) {
+        LongRunAverageOperatorFormula::LongRunAverageOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation) : OperatorFormula(subformula, operatorInformation) {
             // Intentionally left empty.
         }
         
-        LongRunAverageOperatorFormula::LongRunAverageOperatorFormula(OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula) : LongRunAverageOperatorFormula(boost::optional<OptimizationDirection>(optimalityType), boost::none, subformula) {
-            // Intentionally left empty.
-        }
-                
         bool LongRunAverageOperatorFormula::isLongRunAverageOperatorFormula() const {
             return true;
         }
@@ -28,12 +19,8 @@ namespace storm {
             return visitor.visit(*this, data);
         }
         
-        LongRunAverageOperatorFormula::LongRunAverageOperatorFormula(boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula) : OperatorFormula(optimalityType, bound, subformula) {
-            // Intentionally left empty.
-        }
-        
         std::shared_ptr<Formula> LongRunAverageOperatorFormula::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const {
-            return std::make_shared<LongRunAverageOperatorFormula>(this->optimalityType, this->bound, this->getSubformula().substitute(substitution));
+            return std::make_shared<LongRunAverageOperatorFormula>(this->getSubformula().substitute(substitution), this->operatorInformation);
         }
         
         std::ostream& LongRunAverageOperatorFormula::writeToStream(std::ostream& out) const {
diff --git a/src/logic/LongRunAverageOperatorFormula.h b/src/logic/LongRunAverageOperatorFormula.h
index d4a785b80..394188b67 100644
--- a/src/logic/LongRunAverageOperatorFormula.h
+++ b/src/logic/LongRunAverageOperatorFormula.h
@@ -7,11 +7,7 @@ namespace storm {
     namespace logic {
         class LongRunAverageOperatorFormula : public OperatorFormula {
         public:
-            LongRunAverageOperatorFormula(std::shared_ptr<Formula const> const& subformula);
-            LongRunAverageOperatorFormula(Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula);
-            LongRunAverageOperatorFormula(OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula);
-            LongRunAverageOperatorFormula(OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula);
-            LongRunAverageOperatorFormula(boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula);
+            LongRunAverageOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation = OperatorInformation());
             
             virtual ~LongRunAverageOperatorFormula() {
                 // Intentionally left empty.
diff --git a/src/logic/OperatorFormula.cpp b/src/logic/OperatorFormula.cpp
index a9cdc09ae..4a8e2e215 100644
--- a/src/logic/OperatorFormula.cpp
+++ b/src/logic/OperatorFormula.cpp
@@ -2,50 +2,62 @@
 
 namespace storm {
     namespace logic {
-        OperatorFormula::OperatorFormula(boost::optional<storm::solver::OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula) : UnaryStateFormula(subformula), bound(bound), optimalityType(optimalityType) {
+        OperatorInformation::OperatorInformation(boost::optional<storm::solver::OptimizationDirection> const& optimizationDirection, boost::optional<Bound<double>> const& bound) : optimalityType(optimizationDirection), bound(bound) {
+            // Intentionally left empty.
+        }
+        
+        OperatorFormula::OperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation) : UnaryStateFormula(subformula), operatorInformation(operatorInformation) {
             // Intentionally left empty.
         }
         
         bool OperatorFormula::hasBound() const {
-            return static_cast<bool>(bound);
+            return static_cast<bool>(operatorInformation.bound);
         }
         
         ComparisonType OperatorFormula::getComparisonType() const {
-            return bound.get().comparisonType;
+            return operatorInformation.bound.get().comparisonType;
         }
         
         void OperatorFormula::setComparisonType(ComparisonType newComparisonType) {
-            bound.get().comparisonType = newComparisonType;
+            operatorInformation.bound.get().comparisonType = newComparisonType;
         }
         
         double OperatorFormula::getThreshold() const {
-            return bound.get().threshold;
+            return operatorInformation.bound.get().threshold;
         }
         
         void OperatorFormula::setThreshold(double newThreshold) {
-            bound.get().threshold = newThreshold;
+            operatorInformation.bound.get().threshold = newThreshold;
         }
         
         Bound<double> const& OperatorFormula::getBound() const {
-            return bound.get();
+            return operatorInformation.bound.get();
         }
         
         void OperatorFormula::setBound(Bound<double> const& newBound) {
-            bound = newBound;
+            operatorInformation.bound = newBound;
         }
         
         bool OperatorFormula::hasOptimalityType() const {
-            return static_cast<bool>(optimalityType);
+            return static_cast<bool>(operatorInformation.optimalityType);
         }
         
         OptimizationDirection const& OperatorFormula::getOptimalityType() const {
-            return optimalityType.get();
+            return operatorInformation.optimalityType.get();
         }
         
         bool OperatorFormula::isOperatorFormula() const {
             return true;
         }
         
+        bool OperatorFormula::hasQualitativeResult() const {
+            return this->hasBound();
+        }
+        
+        bool OperatorFormula::hasQuantitativeResult() const {
+            return !this->hasBound();
+        }
+        
         std::ostream& OperatorFormula::writeToStream(std::ostream& out) const {
             if (hasOptimalityType()) {
                 out << (getOptimalityType() == OptimizationDirection::Minimize ? "min" : "max");
diff --git a/src/logic/OperatorFormula.h b/src/logic/OperatorFormula.h
index 7660799a4..447647b99 100644
--- a/src/logic/OperatorFormula.h
+++ b/src/logic/OperatorFormula.h
@@ -8,15 +8,23 @@
 #include "src/solver/OptimizationDirection.h"
 
 namespace storm {
-    namespace logic {
+    namespace logic {        
+        struct OperatorInformation {
+            OperatorInformation(boost::optional<storm::solver::OptimizationDirection> const& optimizationDirection = boost::none, boost::optional<Bound<double>> const& bound = boost::none);
+
+            boost::optional<storm::solver::OptimizationDirection> optimalityType;
+            boost::optional<Bound<double>> bound;
+        };
+        
         class OperatorFormula : public UnaryStateFormula {
         public:
-            OperatorFormula(boost::optional<storm::solver::OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula);
+            OperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation = OperatorInformation());
             
             virtual ~OperatorFormula() {
                 // Intentionally left empty.
             }
-            
+
+            // Bound-related accessors.
             bool hasBound() const;
             ComparisonType getComparisonType() const;
             void setComparisonType(ComparisonType newComparisonType);
@@ -24,16 +32,19 @@ namespace storm {
             void setThreshold(double newThreshold);
             Bound<double> const& getBound() const;
             void setBound(Bound<double> const& newBound);
+            
+            // Optimality-type-related accessors.
             bool hasOptimalityType() const;
             storm::solver::OptimizationDirection const& getOptimalityType() const;
             virtual bool isOperatorFormula() const override;
+                        
+            virtual bool hasQualitativeResult() const override;
+            virtual bool hasQuantitativeResult() const override;
             
             virtual std::ostream& writeToStream(std::ostream& out) const override;
             
         protected:
-            std::string operatorSymbol;
-            boost::optional<Bound<double>> bound;
-            boost::optional<storm::solver::OptimizationDirection> optimalityType;
+            OperatorInformation operatorInformation;
         };
     }
 }
diff --git a/src/logic/ProbabilityOperatorFormula.cpp b/src/logic/ProbabilityOperatorFormula.cpp
index 09680cbc5..84d6c55d8 100644
--- a/src/logic/ProbabilityOperatorFormula.cpp
+++ b/src/logic/ProbabilityOperatorFormula.cpp
@@ -2,21 +2,12 @@
 
 #include "src/logic/FormulaVisitor.h"
 
+#include "src/utility/macros.h"
+#include "src/exceptions/InvalidPropertyException.h"
+
 namespace storm {
     namespace logic {
-        ProbabilityOperatorFormula::ProbabilityOperatorFormula(std::shared_ptr<Formula const> const& subformula) : ProbabilityOperatorFormula(boost::none, boost::none, subformula) {
-            // Intentionally left empty.
-        }
-        
-        ProbabilityOperatorFormula::ProbabilityOperatorFormula(Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : ProbabilityOperatorFormula(boost::none, bound, subformula) {
-            // Intentionally left empty.
-        }
-        
-        ProbabilityOperatorFormula::ProbabilityOperatorFormula(OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : ProbabilityOperatorFormula(boost::optional<OptimizationDirection>(optimalityType), bound, subformula) {
-            // Intentionally left empty.
-        }
-        
-        ProbabilityOperatorFormula::ProbabilityOperatorFormula(OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula) : ProbabilityOperatorFormula(boost::optional<OptimizationDirection>(optimalityType), boost::none, subformula) {
+        ProbabilityOperatorFormula::ProbabilityOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation) : OperatorFormula(subformula, operatorInformation) {
             // Intentionally left empty.
         }
         
@@ -27,13 +18,9 @@ namespace storm {
         boost::any ProbabilityOperatorFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const {
             return visitor.visit(*this, data);
         }
-                
-        ProbabilityOperatorFormula::ProbabilityOperatorFormula(boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula) : OperatorFormula(optimalityType, bound, subformula) {
-            // Intentionally left empty.
-        }
         
         std::shared_ptr<Formula> ProbabilityOperatorFormula::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const {
-            return std::make_shared<ProbabilityOperatorFormula>(this->optimalityType, this->bound, this->getSubformula().substitute(substitution));
+            return std::make_shared<ProbabilityOperatorFormula>(this->getSubformula().substitute(substitution), this->operatorInformation);
         }
         
         std::ostream& ProbabilityOperatorFormula::writeToStream(std::ostream& out) const {
diff --git a/src/logic/ProbabilityOperatorFormula.h b/src/logic/ProbabilityOperatorFormula.h
index 1172247d0..786d58b44 100644
--- a/src/logic/ProbabilityOperatorFormula.h
+++ b/src/logic/ProbabilityOperatorFormula.h
@@ -7,11 +7,7 @@ namespace storm {
     namespace logic {
         class ProbabilityOperatorFormula : public OperatorFormula {
         public:
-            ProbabilityOperatorFormula(std::shared_ptr<Formula const> const& subformula);
-            ProbabilityOperatorFormula(Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula);
-            ProbabilityOperatorFormula(OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula);
-            ProbabilityOperatorFormula(OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula);
-            ProbabilityOperatorFormula(boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula);
+            ProbabilityOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation = OperatorInformation());
 
             virtual ~ProbabilityOperatorFormula() {
                 // Intentionally left empty.
diff --git a/src/logic/RewardMeasureType.cpp b/src/logic/RewardMeasureType.cpp
new file mode 100644
index 000000000..37098d550
--- /dev/null
+++ b/src/logic/RewardMeasureType.cpp
@@ -0,0 +1,19 @@
+#include "src/logic/RewardMeasureType.h"
+
+namespace storm {
+    namespace logic {
+        
+        std::ostream& operator<<(std::ostream& out, RewardMeasureType const& type) {
+            switch (type) {
+                case RewardMeasureType::Expectation:
+                    out << "exp";
+                    break;
+                case RewardMeasureType::Variance:
+                    out << "var";
+                    break;
+            }
+            return out;
+        }
+        
+    }
+}
\ No newline at end of file
diff --git a/src/logic/RewardMeasureType.h b/src/logic/RewardMeasureType.h
new file mode 100644
index 000000000..a48697855
--- /dev/null
+++ b/src/logic/RewardMeasureType.h
@@ -0,0 +1,16 @@
+#ifndef STORM_LOGIC_REWARDMEASURETYPE_H_
+#define STORM_LOGIC_REWARDMEASURETYPE_H_
+
+#include <iostream>
+
+namespace storm {
+    namespace logic {
+        
+        enum class RewardMeasureType { Expectation, Variance };
+
+        std::ostream& operator<<(std::ostream& out, RewardMeasureType const& type);
+
+    }
+}
+
+#endif /* STORM_LOGIC_REWARDMEASURETYPE_H_ */
\ No newline at end of file
diff --git a/src/logic/RewardOperatorFormula.cpp b/src/logic/RewardOperatorFormula.cpp
index 711f78789..5daea4b59 100644
--- a/src/logic/RewardOperatorFormula.cpp
+++ b/src/logic/RewardOperatorFormula.cpp
@@ -2,21 +2,12 @@
 
 #include "src/logic/FormulaVisitor.h"
 
+#include "src/utility/macros.h"
+#include "src/exceptions/InvalidPropertyException.h"
+
 namespace storm {
     namespace logic {
-        RewardOperatorFormula::RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, std::shared_ptr<Formula const> const& subformula) : RewardOperatorFormula(rewardModelName, boost::none, boost::none, subformula) {
-            // Intentionally left empty.
-        }
-        
-        RewardOperatorFormula::RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : RewardOperatorFormula(rewardModelName, boost::none, bound, subformula) {
-            // Intentionally left empty.
-        }
-        
-        RewardOperatorFormula::RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula) : RewardOperatorFormula(rewardModelName, boost::optional<OptimizationDirection>(optimalityType), bound, subformula) {
-            // Intentionally left empty.
-        }
-        
-        RewardOperatorFormula::RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula) : RewardOperatorFormula(rewardModelName, boost::optional<OptimizationDirection>(optimalityType), boost::none, subformula) {
+        RewardOperatorFormula::RewardOperatorFormula(std::shared_ptr<Formula const> const& subformula, boost::optional<std::string> const& rewardModelName, OperatorInformation const& operatorInformation, RewardMeasureType rewardMeasureType) : OperatorFormula(subformula, operatorInformation), rewardModelName(rewardModelName), rewardMeasureType(rewardMeasureType) {
             // Intentionally left empty.
         }
         
@@ -49,16 +40,17 @@ namespace storm {
             this->getSubformula().gatherReferencedRewardModels(referencedRewardModels);
         }
         
-        RewardOperatorFormula::RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula) : OperatorFormula(optimalityType, bound, subformula), rewardModelName(rewardModelName) {
-            // Intentionally left empty.
+        std::shared_ptr<Formula> RewardOperatorFormula::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const {
+            return std::make_shared<RewardOperatorFormula>(this->getSubformula().substitute(substitution), this->rewardModelName, this->operatorInformation, this->rewardMeasureType);
         }
         
-        std::shared_ptr<Formula> RewardOperatorFormula::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const {
-            return std::make_shared<RewardOperatorFormula>(this->rewardModelName, this->optimalityType, this->bound, this->getSubformula().substitute(substitution));
+        RewardMeasureType RewardOperatorFormula::getMeasureType() const {
+            return rewardMeasureType;
         }
         
         std::ostream& RewardOperatorFormula::writeToStream(std::ostream& out) const {
             out << "R";
+            out << "[" << rewardMeasureType << "]";
             if (this->hasRewardModelName()) {
                 out << "{\"" << this->getRewardModelName() << "\"}";
             }
diff --git a/src/logic/RewardOperatorFormula.h b/src/logic/RewardOperatorFormula.h
index 6bcf015d8..300a82e37 100644
--- a/src/logic/RewardOperatorFormula.h
+++ b/src/logic/RewardOperatorFormula.h
@@ -1,18 +1,14 @@
 #ifndef STORM_LOGIC_REWARDOPERATORFORMULA_H_
 #define STORM_LOGIC_REWARDOPERATORFORMULA_H_
 
-#include <set>
 #include "src/logic/OperatorFormula.h"
+#include "src/logic/RewardMeasureType.h"
 
 namespace storm {
     namespace logic {
         class RewardOperatorFormula : public OperatorFormula {
         public:
-            RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, std::shared_ptr<Formula const> const& subformula);
-            RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula);
-            RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, OptimizationDirection optimalityType, Bound<double> const& bound, std::shared_ptr<Formula const> const& subformula);
-            RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, OptimizationDirection optimalityType, std::shared_ptr<Formula const> const& subformula);
-            RewardOperatorFormula(boost::optional<std::string> const& rewardModelName, boost::optional<OptimizationDirection> optimalityType, boost::optional<Bound<double>> bound, std::shared_ptr<Formula const> const& subformula);
+            RewardOperatorFormula(std::shared_ptr<Formula const> const& subformula, boost::optional<std::string> const& rewardModelName = boost::none, OperatorInformation const& operatorInformation = OperatorInformation(), RewardMeasureType rewardMeasureType = RewardMeasureType::Expectation);
 
             virtual ~RewardOperatorFormula() {
                 // Intentionally left empty.
@@ -48,11 +44,21 @@ namespace storm {
              */
             std::string const& getRewardModelName() const;
             
+            /*!
+             * Retrieves the measure type of the operator.
+             *
+             * @return The measure type.
+             */
+            RewardMeasureType getMeasureType() const;
+            
             virtual std::shared_ptr<Formula> substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const override;
             
         private:
             // The (optional) name of the reward model this property refers to.
             boost::optional<std::string> rewardModelName;
+            
+            // The measure type of the operator.
+            RewardMeasureType rewardMeasureType;
         };
     }
 }
diff --git a/src/logic/TimeOperatorFormula.cpp b/src/logic/TimeOperatorFormula.cpp
new file mode 100644
index 000000000..6a421a1a5
--- /dev/null
+++ b/src/logic/TimeOperatorFormula.cpp
@@ -0,0 +1,37 @@
+#include "src/logic/TimeOperatorFormula.h"
+
+#include "src/logic/FormulaVisitor.h"
+
+#include "src/utility/macros.h"
+#include "src/exceptions/InvalidPropertyException.h"
+
+namespace storm {
+    namespace logic {
+        TimeOperatorFormula::TimeOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation, RewardMeasureType rewardMeasureType) : OperatorFormula(subformula, operatorInformation), rewardMeasureType(rewardMeasureType) {
+            // Intentionally left empty.
+        }
+        
+        bool TimeOperatorFormula::isTimeOperatorFormula() const {
+            return true;
+        }
+        
+        boost::any TimeOperatorFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const {
+            return visitor.visit(*this, data);
+        }
+        
+        std::shared_ptr<Formula> TimeOperatorFormula::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const {
+            return std::make_shared<TimeOperatorFormula>(this->getSubformula().substitute(substitution), this->operatorInformation, this->rewardMeasureType);
+        }
+        
+        RewardMeasureType TimeOperatorFormula::getMeasureType() const {
+            return rewardMeasureType;
+        }
+        
+        std::ostream& TimeOperatorFormula::writeToStream(std::ostream& out) const {
+            out << "T";
+            out << "[" << rewardMeasureType << "]";
+            OperatorFormula::writeToStream(out);
+            return out;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/logic/TimeOperatorFormula.h b/src/logic/TimeOperatorFormula.h
new file mode 100644
index 000000000..b9f243a4c
--- /dev/null
+++ b/src/logic/TimeOperatorFormula.h
@@ -0,0 +1,40 @@
+#ifndef STORM_LOGIC_EXPECTEDTIMEOPERATORFORMULA_H_
+#define STORM_LOGIC_EXPECTEDTIMEOPERATORFORMULA_H_
+
+#include "src/logic/OperatorFormula.h"
+#include "src/logic/FormulaVisitor.h"
+#include "src/logic/RewardMeasureType.h"
+
+namespace storm {
+    namespace logic {
+        class TimeOperatorFormula : public OperatorFormula {
+        public:
+            TimeOperatorFormula(std::shared_ptr<Formula const> const& subformula, OperatorInformation const& operatorInformation = OperatorInformation(), RewardMeasureType rewardMeasureType = RewardMeasureType::Expectation);
+            
+            virtual ~TimeOperatorFormula() {
+                // Intentionally left empty.
+            }
+            
+            virtual bool isTimeOperatorFormula() const override;
+
+            virtual boost::any accept(FormulaVisitor const& visitor, boost::any const& data) const override;
+            
+            virtual std::shared_ptr<Formula> substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const override;
+            
+            virtual std::ostream& writeToStream(std::ostream& out) const override;
+            
+            /*!
+             * Retrieves the measure type of the operator.
+             *
+             * @return The measure type of the operator.
+             */
+            RewardMeasureType getMeasureType() const;
+            
+        private:
+            // The measure type of the operator.
+            RewardMeasureType rewardMeasureType;
+        };
+    }
+}
+
+#endif /* STORM_LOGIC_EXPECTEDTIMEOPERATORFORMULA_H_ */
\ No newline at end of file
diff --git a/src/logic/UnaryBooleanStateFormula.cpp b/src/logic/UnaryBooleanStateFormula.cpp
index 6d4f9ecdd..3983e5b27 100644
--- a/src/logic/UnaryBooleanStateFormula.cpp
+++ b/src/logic/UnaryBooleanStateFormula.cpp
@@ -2,10 +2,13 @@
 
 #include "src/logic/FormulaVisitor.h"
 
+#include "src/utility/macros.h"
+#include "src/exceptions/InvalidPropertyException.h"
+
 namespace storm {
     namespace logic {
         UnaryBooleanStateFormula::UnaryBooleanStateFormula(OperatorType operatorType, std::shared_ptr<Formula const> const& subformula) : UnaryStateFormula(subformula), operatorType(operatorType) {
-            // Intentionally left empty.
+            STORM_LOG_THROW(this->getSubformula().hasQualitativeResult(), storm::exceptions::InvalidPropertyException, "Boolean formula must have subformulas with qualitative result.");
         }
         
         bool UnaryBooleanStateFormula::isUnaryBooleanStateFormula() const {
diff --git a/src/logic/UnaryPathFormula.cpp b/src/logic/UnaryPathFormula.cpp
index 3e0cdaebc..415fb4d4c 100644
--- a/src/logic/UnaryPathFormula.cpp
+++ b/src/logic/UnaryPathFormula.cpp
@@ -25,5 +25,14 @@ namespace storm {
         void UnaryPathFormula::gatherReferencedRewardModels(std::set<std::string>& referencedRewardModels) const {
             this->getSubformula().gatherReferencedRewardModels(referencedRewardModels);
         }
+        
+        bool UnaryPathFormula::hasQualitativeResult() const {
+            return false;
+        }
+        
+        bool UnaryPathFormula::hasQuantitativeResult() const {
+            return true;
+        }
+
     }
 }
\ No newline at end of file
diff --git a/src/logic/UnaryPathFormula.h b/src/logic/UnaryPathFormula.h
index 3ea27d8f5..bc698338c 100644
--- a/src/logic/UnaryPathFormula.h
+++ b/src/logic/UnaryPathFormula.h
@@ -23,6 +23,9 @@ namespace storm {
             virtual void gatherAtomicLabelFormulas(std::vector<std::shared_ptr<AtomicLabelFormula const>>& atomicLabelFormulas) const override;
             virtual void gatherReferencedRewardModels(std::set<std::string>& referencedRewardModels) const override;
             
+            virtual bool hasQualitativeResult() const override;
+            virtual bool hasQuantitativeResult() const override;
+
         private:
             std::shared_ptr<Formula const> subformula;
         };
diff --git a/src/modelchecker/AbstractModelChecker.cpp b/src/modelchecker/AbstractModelChecker.cpp
index 24f8bb4a3..0a08f9a95 100644
--- a/src/modelchecker/AbstractModelChecker.cpp
+++ b/src/modelchecker/AbstractModelChecker.cpp
@@ -16,16 +16,6 @@ namespace storm {
             STORM_LOG_THROW(this->canHandle(formula), storm::exceptions::InvalidArgumentException, "The model checker is not able to check the formula '" << formula << "'.");
             if (formula.isStateFormula()) {
                 return this->checkStateFormula(checkTask.substituteFormula(formula.asStateFormula()));
-            } else if (formula.isPathFormula()) {
-                if (formula.isProbabilityPathFormula()) {
-                    return this->computeProbabilities(checkTask);
-                } else if (formula.isRewardPathFormula()) {
-                    return this->computeRewards(checkTask);
-                }
-            } else if (formula.isConditionalProbabilityFormula()) {
-                return this->computeConditionalProbabilities(checkTask.substituteFormula(formula.asConditionalFormula()));
-            } else if (formula.isConditionalRewardFormula()) {
-                return this->computeConditionalRewards(checkTask.substituteFormula(formula.asConditionalFormula()));
             }
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given formula '" << formula << "' is invalid.");
         }
@@ -34,8 +24,8 @@ namespace storm {
             storm::logic::Formula const& formula = checkTask.getFormula();
             if (formula.isBoundedUntilFormula()) {
                 return this->computeBoundedUntilProbabilities(checkTask.substituteFormula(formula.asBoundedUntilFormula()));
-            } else if (formula.isEventuallyFormula()) {
-                return this->computeEventuallyProbabilities(checkTask.substituteFormula(formula.asEventuallyFormula()));
+            } else if (formula.isReachabilityProbabilityFormula()) {
+                return this->computeReachabilityProbabilities(checkTask.substituteFormula(formula.asReachabilityProbabilityFormula()));
             } else if (formula.isGloballyFormula()) {
                 return this->computeGloballyProbabilities(checkTask.substituteFormula(formula.asGloballyFormula()));
             } else if (formula.isUntilFormula()) {
@@ -56,7 +46,7 @@ namespace storm {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << ".");
         }
         
-        std::unique_ptr<CheckResult> AbstractModelChecker::computeEventuallyProbabilities(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> AbstractModelChecker::computeReachabilityProbabilities(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
             storm::logic::EventuallyFormula const& pathFormula = checkTask.getFormula();
             storm::logic::UntilFormula newFormula(storm::logic::Formula::getTrueFormula(), pathFormula.getSubformula().asSharedPointer());
             return this->computeUntilProbabilities(checkTask.substituteFormula(newFormula));
@@ -74,39 +64,39 @@ namespace storm {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << ".");
         }
         
-        std::unique_ptr<CheckResult> AbstractModelChecker::computeRewards(CheckTask<storm::logic::Formula> const& checkTask) {
+        std::unique_ptr<CheckResult> AbstractModelChecker::computeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::Formula> const& checkTask) {
             storm::logic::Formula const& rewardFormula = checkTask.getFormula();
             if (rewardFormula.isCumulativeRewardFormula()) {
-                return this->computeCumulativeRewards(checkTask.substituteFormula(rewardFormula.asCumulativeRewardFormula()));
+                return this->computeCumulativeRewards(rewardMeasureType, checkTask.substituteFormula(rewardFormula.asCumulativeRewardFormula()));
             } else if (rewardFormula.isInstantaneousRewardFormula()) {
-                return this->computeInstantaneousRewards(checkTask.substituteFormula(rewardFormula.asInstantaneousRewardFormula()));
+                return this->computeInstantaneousRewards(rewardMeasureType, checkTask.substituteFormula(rewardFormula.asInstantaneousRewardFormula()));
             } else if (rewardFormula.isReachabilityRewardFormula()) {
-                return this->computeReachabilityRewards(checkTask.substituteFormula(rewardFormula.asEventuallyFormula()));
+                return this->computeReachabilityRewards(rewardMeasureType, checkTask.substituteFormula(rewardFormula.asReachabilityRewardFormula()));
             } else if (rewardFormula.isLongRunAverageRewardFormula()) {
-                return this->computeLongRunAverageRewards(checkTask.substituteFormula(rewardFormula.asLongRunAverageRewardFormula()));
+                return this->computeLongRunAverageRewards(rewardMeasureType, checkTask.substituteFormula(rewardFormula.asLongRunAverageRewardFormula()));
             } else if (rewardFormula.isConditionalRewardFormula()) {
-                return this->computeConditionalRewards(checkTask.substituteFormula(rewardFormula.asConditionalFormula()));
+                return this->computeConditionalRewards(rewardMeasureType, checkTask.substituteFormula(rewardFormula.asConditionalFormula()));
             }
             STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given formula '" << rewardFormula << "' is invalid.");
         }
         
-        std::unique_ptr<CheckResult> AbstractModelChecker::computeConditionalRewards(CheckTask<storm::logic::ConditionalFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> AbstractModelChecker::computeConditionalRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::ConditionalFormula> const& checkTask) {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << ".");
         }
         
-        std::unique_ptr<CheckResult> AbstractModelChecker::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> AbstractModelChecker::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << ".");
         }
         
-        std::unique_ptr<CheckResult> AbstractModelChecker::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> AbstractModelChecker::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << ".");
         }
         
-        std::unique_ptr<CheckResult> AbstractModelChecker::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> AbstractModelChecker::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << ".");
         }
         
-        std::unique_ptr<CheckResult> AbstractModelChecker::computeLongRunAverageRewards(CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> AbstractModelChecker::computeLongRunAverageRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask) {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << ".");
         }
         
@@ -114,7 +104,15 @@ namespace storm {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << ".");
         }
         
-        std::unique_ptr<CheckResult> AbstractModelChecker::computeExpectedTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> AbstractModelChecker::computeTimes(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::Formula> const& checkTask) {
+            storm::logic::Formula const& timeFormula = checkTask.getFormula();
+            if (timeFormula.isReachabilityTimeFormula()) {
+                return this->computeReachabilityTimes(rewardMeasureType, checkTask.substituteFormula(timeFormula.asReachabilityTimeFormula()));
+            }
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << ".");
+        }
+        
+        std::unique_ptr<CheckResult> AbstractModelChecker::computeReachabilityTimes(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << ".");
         }
         
@@ -130,8 +128,8 @@ namespace storm {
                 return this->checkProbabilityOperatorFormula(checkTask.substituteFormula(stateFormula.asProbabilityOperatorFormula()));
             } else if (stateFormula.isRewardOperatorFormula()) {
                 return this->checkRewardOperatorFormula(checkTask.substituteFormula(stateFormula.asRewardOperatorFormula()));
-            } else if (stateFormula.isExpectedTimeOperatorFormula()) {
-                return this->checkExpectedTimeOperatorFormula(checkTask.substituteFormula(stateFormula.asExpectedTimeOperatorFormula()));
+            } else if (stateFormula.isTimeOperatorFormula()) {
+                return this->checkTimeOperatorFormula(checkTask.substituteFormula(stateFormula.asTimeOperatorFormula()));
             } else if (stateFormula.isLongRunAverageOperatorFormula()) {
                 return this->checkLongRunAverageOperatorFormula(checkTask.substituteFormula(stateFormula.asLongRunAverageOperatorFormula()));
             } else if (stateFormula.isAtomicExpressionFormula()) {
@@ -193,7 +191,7 @@ namespace storm {
         
         std::unique_ptr<CheckResult> AbstractModelChecker::checkRewardOperatorFormula(CheckTask<storm::logic::RewardOperatorFormula> const& checkTask) {
             storm::logic::RewardOperatorFormula const& stateFormula = checkTask.getFormula();
-            std::unique_ptr<CheckResult> result = this->computeRewards(checkTask.substituteFormula(stateFormula.getSubformula()));
+            std::unique_ptr<CheckResult> result = this->computeRewards(stateFormula.getMeasureType(), checkTask.substituteFormula(stateFormula.getSubformula()));
             
             if (checkTask.isBoundSet()) {
                 STORM_LOG_THROW(result->isQuantitative(), storm::exceptions::InvalidOperationException, "Unable to perform comparison operation on non-quantitative result.");
@@ -203,11 +201,11 @@ namespace storm {
             }
         }
         
-		std::unique_ptr<CheckResult> AbstractModelChecker::checkExpectedTimeOperatorFormula(CheckTask<storm::logic::ExpectedTimeOperatorFormula> const& checkTask) {
-            storm::logic::ExpectedTimeOperatorFormula const& stateFormula = checkTask.getFormula();
-			STORM_LOG_THROW(stateFormula.getSubformula().isReachbilityExpectedTimeFormula(), storm::exceptions::InvalidArgumentException, "The given formula is invalid.");
+		std::unique_ptr<CheckResult> AbstractModelChecker::checkTimeOperatorFormula(CheckTask<storm::logic::TimeOperatorFormula> const& checkTask) {
+            storm::logic::TimeOperatorFormula const& stateFormula = checkTask.getFormula();
+			STORM_LOG_THROW(stateFormula.getSubformula().isReachabilityTimeFormula(), storm::exceptions::InvalidArgumentException, "The given formula is invalid.");
             
-            std::unique_ptr<CheckResult> result = this->computeExpectedTimes(checkTask.substituteFormula(stateFormula.getSubformula().asEventuallyFormula()));
+            std::unique_ptr<CheckResult> result = this->computeTimes(stateFormula.getMeasureType(), checkTask.substituteFormula(stateFormula.getSubformula()));
             
             if (checkTask.isBoundSet()) {
                 STORM_LOG_THROW(result->isQuantitative(), storm::exceptions::InvalidOperationException, "Unable to perform comparison operation on non-quantitative result.");
diff --git a/src/modelchecker/AbstractModelChecker.h b/src/modelchecker/AbstractModelChecker.h
index 90562659b..b6f009197 100644
--- a/src/modelchecker/AbstractModelChecker.h
+++ b/src/modelchecker/AbstractModelChecker.h
@@ -11,6 +11,8 @@ namespace storm {
     namespace modelchecker {
         class CheckResult;
         
+        enum class RewardType { Expectation, Variance };
+        
         class AbstractModelChecker {
         public:
             virtual ~AbstractModelChecker() {
@@ -38,22 +40,23 @@ namespace storm {
             virtual std::unique_ptr<CheckResult> computeProbabilities(CheckTask<storm::logic::Formula> const& checkTask);
             virtual std::unique_ptr<CheckResult> computeConditionalProbabilities(CheckTask<storm::logic::ConditionalFormula> const& checkTask);
             virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(CheckTask<storm::logic::BoundedUntilFormula> const& checkTask);
-            virtual std::unique_ptr<CheckResult> computeEventuallyProbabilities(CheckTask<storm::logic::EventuallyFormula> const& checkTask);
+            virtual std::unique_ptr<CheckResult> computeReachabilityProbabilities(CheckTask<storm::logic::EventuallyFormula> const& checkTask);
             virtual std::unique_ptr<CheckResult> computeGloballyProbabilities(CheckTask<storm::logic::GloballyFormula> const& checkTask);
             virtual std::unique_ptr<CheckResult> computeNextProbabilities(CheckTask<storm::logic::NextFormula> const& checkTask);
             virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask);
             
             // The methods to compute the rewards for path formulas.
-            virtual std::unique_ptr<CheckResult> computeRewards(CheckTask<storm::logic::Formula> const& checkTask);
-            virtual std::unique_ptr<CheckResult> computeConditionalRewards(CheckTask<storm::logic::ConditionalFormula> const& checkTask);
-            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask);
-            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask);
-            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask);
-            virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask);
+            virtual std::unique_ptr<CheckResult> computeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::Formula> const& checkTask);
+            virtual std::unique_ptr<CheckResult> computeConditionalRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::ConditionalFormula> const& checkTask);
+            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask);
+            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask);
+            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask);
+            virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask);
             
-            // The methods to compute the long-run average and expected time.
+            // The methods to compute the long-run average probabilities and timing measures.
             virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask);
-            virtual std::unique_ptr<CheckResult> computeExpectedTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask);
+            virtual std::unique_ptr<CheckResult> computeTimes(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::Formula> const& checkTask);
+            virtual std::unique_ptr<CheckResult> computeReachabilityTimes(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask);
             
             // The methods to check state formulas.
             virtual std::unique_ptr<CheckResult> checkStateFormula(CheckTask<storm::logic::StateFormula> const& stateFormula);
@@ -63,7 +66,7 @@ namespace storm {
             virtual std::unique_ptr<CheckResult> checkBooleanLiteralFormula(CheckTask<storm::logic::BooleanLiteralFormula> const& checkTask);
             virtual std::unique_ptr<CheckResult> checkProbabilityOperatorFormula(CheckTask<storm::logic::ProbabilityOperatorFormula> const& checkTask);
             virtual std::unique_ptr<CheckResult> checkRewardOperatorFormula(CheckTask<storm::logic::RewardOperatorFormula> const& checkTask);
-            virtual std::unique_ptr<CheckResult> checkExpectedTimeOperatorFormula(CheckTask<storm::logic::ExpectedTimeOperatorFormula> const& checkTask);
+            virtual std::unique_ptr<CheckResult> checkTimeOperatorFormula(CheckTask<storm::logic::TimeOperatorFormula> const& checkTask);
             virtual std::unique_ptr<CheckResult> checkLongRunAverageOperatorFormula(CheckTask<storm::logic::LongRunAverageOperatorFormula> const& checkTask);
             virtual std::unique_ptr<CheckResult> checkUnaryBooleanStateFormula(CheckTask<storm::logic::UnaryBooleanStateFormula> const& checkTask);
         };
diff --git a/src/modelchecker/csl/HybridCtmcCslModelChecker.cpp b/src/modelchecker/csl/HybridCtmcCslModelChecker.cpp
index a08d7a6b1..81bbbd00e 100644
--- a/src/modelchecker/csl/HybridCtmcCslModelChecker.cpp
+++ b/src/modelchecker/csl/HybridCtmcCslModelChecker.cpp
@@ -56,7 +56,7 @@ namespace storm {
         }
         
         template<storm::dd::DdType DdType, class ValueType>
-        std::unique_ptr<CheckResult> HybridCtmcCslModelChecker<DdType, ValueType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> HybridCtmcCslModelChecker<DdType, ValueType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
             storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula();
             std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula());
             SymbolicQualitativeCheckResult<DdType> const& subResult = subResultPointer->asSymbolicQualitativeCheckResult<DdType>();
@@ -85,13 +85,13 @@ namespace storm {
         }
         
         template<storm::dd::DdType DdType, class ValueType>
-        std::unique_ptr<CheckResult> HybridCtmcCslModelChecker<DdType, ValueType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> HybridCtmcCslModelChecker<DdType, ValueType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
             storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula();
             return storm::modelchecker::helper::HybridCtmcCslHelper<DdType, ValueType>::computeInstantaneousRewards(this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getContinuousTimeBound(), *linearEquationSolverFactory);
         }
 
         template<storm::dd::DdType DdType, class ValueType>
-        std::unique_ptr<CheckResult> HybridCtmcCslModelChecker<DdType, ValueType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> HybridCtmcCslModelChecker<DdType, ValueType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
             storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula();
             return storm::modelchecker::helper::HybridCtmcCslHelper<DdType, ValueType>::computeCumulativeRewards(this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getContinuousTimeBound(), *linearEquationSolverFactory);
         }
diff --git a/src/modelchecker/csl/HybridCtmcCslModelChecker.h b/src/modelchecker/csl/HybridCtmcCslModelChecker.h
index d1e26bcb2..5bfe49405 100644
--- a/src/modelchecker/csl/HybridCtmcCslModelChecker.h
+++ b/src/modelchecker/csl/HybridCtmcCslModelChecker.h
@@ -21,9 +21,9 @@ namespace storm {
             virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(CheckTask<storm::logic::BoundedUntilFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeNextProbabilities(CheckTask<storm::logic::NextFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override;
 
         protected:
diff --git a/src/modelchecker/csl/SparseCtmcCslModelChecker.cpp b/src/modelchecker/csl/SparseCtmcCslModelChecker.cpp
index f1fd22d4f..e3cea0fb6 100644
--- a/src/modelchecker/csl/SparseCtmcCslModelChecker.cpp
+++ b/src/modelchecker/csl/SparseCtmcCslModelChecker.cpp
@@ -79,21 +79,21 @@ namespace storm {
         }
         
         template <typename SparseCtmcModelType>
-        std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
             storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula();
             std::vector<ValueType> numericResult = storm::modelchecker::helper::SparseCtmcCslHelper<ValueType>::computeInstantaneousRewards(this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getContinuousTimeBound(), *linearEquationSolverFactory);
             return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult)));
         }
                 
         template <typename SparseCtmcModelType>
-        std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
             storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula();
             std::vector<ValueType> numericResult = storm::modelchecker::helper::SparseCtmcCslHelper<ValueType>::computeCumulativeRewards(this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getContinuousTimeBound(), *linearEquationSolverFactory);
             return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult)));
         }
                 
         template <typename SparseCtmcModelType>
-        std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
             storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula();
             std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula());
             ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult();
diff --git a/src/modelchecker/csl/SparseCtmcCslModelChecker.h b/src/modelchecker/csl/SparseCtmcCslModelChecker.h
index bd62da7a1..4d838d4d8 100644
--- a/src/modelchecker/csl/SparseCtmcCslModelChecker.h
+++ b/src/modelchecker/csl/SparseCtmcCslModelChecker.h
@@ -24,9 +24,9 @@ namespace storm {
             virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(CheckTask<storm::logic::BoundedUntilFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeNextProbabilities(CheckTask<storm::logic::NextFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeExpectedTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
 
diff --git a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp
index 05e2cf823..10236bdcd 100644
--- a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp
+++ b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp
@@ -33,7 +33,7 @@ namespace storm {
         bool SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::canHandle(CheckTask<storm::logic::Formula> const& checkTask) const {
             storm::logic::Formula const& formula = checkTask.getFormula();
             storm::logic::FragmentSpecification fragment = storm::logic::csl().setGloballyFormulasAllowed(false).setNextFormulasAllowed(false).setReachabilityRewardFormulasAllowed(true);
-            fragment.setExpectedTimeAllowed(true).setLongRunAverageProbabilitiesAllowed(true);
+            fragment.setTimeAllowed(true).setLongRunAverageProbabilitiesAllowed(true);
             return formula.isInFragment(fragment);
         }
         
@@ -71,7 +71,7 @@ namespace storm {
         }
                 
         template<typename SparseMarkovAutomatonModelType>
-        std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
             storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula();
             STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
             STORM_LOG_THROW(this->getModel().isClosed(), storm::exceptions::InvalidPropertyException, "Unable to compute reachability rewards in non-closed Markov automaton.");
@@ -96,14 +96,14 @@ namespace storm {
         }
                 
         template<typename SparseMarkovAutomatonModelType>
-        std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeExpectedTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeReachabilityTimes(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
             storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula();
             STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
             STORM_LOG_THROW(this->getModel().isClosed(), storm::exceptions::InvalidPropertyException, "Unable to compute expected times in non-closed Markov automaton.");
             std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula());
             ExplicitQualitativeCheckResult& subResult = subResultPointer->asExplicitQualitativeCheckResult();
 
-            std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper<ValueType>::computeExpectedTimes(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *minMaxLinearEquationSolverFactory);
+            std::vector<ValueType> result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper<ValueType>::computeTimes(checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *minMaxLinearEquationSolverFactory);
             return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(result)));
         }
                 
diff --git a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h
index 4e4f60850..8509d5f17 100644
--- a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h
+++ b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h
@@ -23,9 +23,9 @@ namespace storm {
             virtual bool canHandle(CheckTask<storm::logic::Formula> const& checkTask) const override;
             virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(CheckTask<storm::logic::BoundedUntilFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeExpectedTimes(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeReachabilityTimes(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
             
         private:
             // An object that is used for retrieving solvers for systems of linear equations that are the result of nondeterministic choices.
diff --git a/src/modelchecker/csl/helper/SparseCtmcCslHelper.cpp b/src/modelchecker/csl/helper/SparseCtmcCslHelper.cpp
index 18a56f5ab..ff04148aa 100644
--- a/src/modelchecker/csl/helper/SparseCtmcCslHelper.cpp
+++ b/src/modelchecker/csl/helper/SparseCtmcCslHelper.cpp
@@ -363,7 +363,7 @@ namespace storm {
                 STORM_LOG_THROW(uniformizationRate > 0, storm::exceptions::InvalidStateException, "The uniformization rate must be positive.");
                 
                 storm::storage::SparseMatrix<ValueType> uniformizedMatrix = computeUniformizedMatrix(rateMatrix, storm::storage::BitVector(numberOfStates, true), uniformizationRate, exitRateVector);
-                
+
                 // Compute the total state reward vector.
                 std::vector<ValueType> totalRewardVector = rewardModel.getTotalRewardVector(rateMatrix, exitRateVector);
                 
diff --git a/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp
index 00a4e57c0..01fba2762 100644
--- a/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp
+++ b/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp
@@ -345,7 +345,7 @@ namespace storm {
             }
             
             template <typename ValueType>
-            std::vector<ValueType> SparseMarkovAutomatonCslHelper<ValueType>::computeExpectedTimes(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
+            std::vector<ValueType> SparseMarkovAutomatonCslHelper<ValueType>::computeTimes(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
                  uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount();
                 std::vector<ValueType> rewardValues(numberOfStates, storm::utility::zero<ValueType>());
                 storm::utility::vector::setVectorValues(rewardValues, markovianStates, storm::utility::one<ValueType>());
diff --git a/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h
index 764eb542c..96429d727 100644
--- a/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h
+++ b/src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h
@@ -24,7 +24,7 @@ namespace storm {
                 
                 static std::vector<ValueType> computeLongRunAverageProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
                 
-                static std::vector<ValueType> computeExpectedTimes(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
+                static std::vector<ValueType> computeTimes(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
                 
             private:
                 static void computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRates, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector<ValueType>& markovianNonGoalValues, std::vector<ValueType>& probabilisticNonGoalValues, ValueType delta, uint_fast64_t numberOfSteps, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
diff --git a/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp b/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp
index 31628f4ed..4f8c38285 100644
--- a/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp
+++ b/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp
@@ -79,21 +79,21 @@ namespace storm {
         }
                 
         template<storm::dd::DdType DdType, typename ValueType>
-        std::unique_ptr<CheckResult> HybridDtmcPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> HybridDtmcPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
             storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula();
             STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidArgumentException, "Formula needs to have a discrete time bound.");
             return storm::modelchecker::helper::HybridDtmcPrctlHelper<DdType, ValueType>::computeCumulativeRewards(this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getDiscreteTimeBound(), *this->linearEquationSolverFactory);
         }
                 
         template<storm::dd::DdType DdType, typename ValueType>
-        std::unique_ptr<CheckResult> HybridDtmcPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> HybridDtmcPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
             storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula();
             STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidArgumentException, "Formula needs to have a discrete time bound.");
             return storm::modelchecker::helper::HybridDtmcPrctlHelper<DdType, ValueType>::computeInstantaneousRewards(this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getDiscreteTimeBound(), *this->linearEquationSolverFactory);
         }
         
         template<storm::dd::DdType DdType, typename ValueType>
-        std::unique_ptr<CheckResult> HybridDtmcPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> HybridDtmcPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
             storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula();
             std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula());
             SymbolicQualitativeCheckResult<DdType> const& subResult = subResultPointer->asSymbolicQualitativeCheckResult<DdType>();
diff --git a/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.h b/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.h
index b723ea699..3489e74e8 100644
--- a/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.h
+++ b/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.h
@@ -22,9 +22,9 @@ namespace storm {
             virtual std::unique_ptr<CheckResult> computeNextProbabilities(CheckTask<storm::logic::NextFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeGloballyProbabilities(CheckTask<storm::logic::GloballyFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override;
 
         protected:
diff --git a/src/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp b/src/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp
index f79bbb933..4d4d8f400 100644
--- a/src/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp
+++ b/src/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp
@@ -77,7 +77,7 @@ namespace storm {
         }
         
         template<storm::dd::DdType DdType, typename ValueType>
-        std::unique_ptr<CheckResult> HybridMdpPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> HybridMdpPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
             storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula();
             STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
             STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound.");
@@ -85,7 +85,7 @@ namespace storm {
         }
                 
         template<storm::dd::DdType DdType, typename ValueType>
-        std::unique_ptr<CheckResult> HybridMdpPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> HybridMdpPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
             storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula();
             STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
             STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound.");
@@ -93,7 +93,7 @@ namespace storm {
         }
                 
         template<storm::dd::DdType DdType, typename ValueType>
-        std::unique_ptr<CheckResult> HybridMdpPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> HybridMdpPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
             storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula();
             STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
             std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula());
diff --git a/src/modelchecker/prctl/HybridMdpPrctlModelChecker.h b/src/modelchecker/prctl/HybridMdpPrctlModelChecker.h
index ec3ef2955..3fa7f3d13 100644
--- a/src/modelchecker/prctl/HybridMdpPrctlModelChecker.h
+++ b/src/modelchecker/prctl/HybridMdpPrctlModelChecker.h
@@ -29,9 +29,9 @@ namespace storm {
             virtual std::unique_ptr<CheckResult> computeNextProbabilities(CheckTask<storm::logic::NextFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeGloballyProbabilities(CheckTask<storm::logic::GloballyFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
             
         protected:
             storm::models::symbolic::Mdp<DdType, ValueType> const& getModel() const override;
diff --git a/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp b/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp
index b21d509ec..d110f067d 100644
--- a/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp
+++ b/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp
@@ -82,7 +82,7 @@ namespace storm {
         }
         
         template<typename SparseDtmcModelType>
-        std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
             storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula();
             STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound.");
             std::vector<ValueType> numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper<ValueType>::computeCumulativeRewards(this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getDiscreteTimeBound(), *linearEquationSolverFactory);
@@ -90,7 +90,7 @@ namespace storm {
         }
         
         template<typename SparseDtmcModelType>
-        std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
             storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula();
             STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound.");
             std::vector<ValueType> numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper<ValueType>::computeInstantaneousRewards(this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getDiscreteTimeBound(), *linearEquationSolverFactory);
@@ -98,7 +98,7 @@ namespace storm {
         }
         
         template<typename SparseDtmcModelType>
-        std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
             storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula();
             std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula());
             ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult();
@@ -131,7 +131,7 @@ namespace storm {
         }
         
         template<typename SparseDtmcModelType>
-        std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeConditionalRewards(CheckTask<storm::logic::ConditionalFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeConditionalRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::ConditionalFormula> const& checkTask) {
             storm::logic::ConditionalFormula const& conditionalFormula = checkTask.getFormula();
             STORM_LOG_THROW(conditionalFormula.getSubformula().isReachabilityRewardFormula(), storm::exceptions::InvalidPropertyException, "Illegal conditional probability formula.");
             STORM_LOG_THROW(conditionalFormula.getConditionFormula().isEventuallyFormula(), storm::exceptions::InvalidPropertyException, "Illegal conditional probability formula.");
diff --git a/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h b/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h
index bdfbe5509..6b94f6642 100644
--- a/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h
+++ b/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h
@@ -27,10 +27,10 @@ namespace storm {
             virtual std::unique_ptr<CheckResult> computeConditionalProbabilities(CheckTask<storm::logic::ConditionalFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override;
 
-            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeConditionalRewards(CheckTask<storm::logic::ConditionalFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeConditionalRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::ConditionalFormula> const& checkTask) override;
 
         private:
             // An object that is used for retrieving linear equation solvers.
diff --git a/src/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp b/src/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp
index 614522e01..44a0223a0 100644
--- a/src/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp
+++ b/src/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp
@@ -109,7 +109,7 @@ namespace storm {
         }
         
         template<typename SparseMdpModelType>
-        std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
             storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula();
             STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
             STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidArgumentException, "Formula needs to have a discrete time bound.");
@@ -118,7 +118,7 @@ namespace storm {
         }
         
         template<typename SparseMdpModelType>
-        std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
             storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula();
             STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
             STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidArgumentException, "Formula needs to have a discrete time bound.");
@@ -127,7 +127,7 @@ namespace storm {
         }
                 
         template<typename SparseMdpModelType>
-        std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
             storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula();
             STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
             std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula());
diff --git a/src/modelchecker/prctl/SparseMdpPrctlModelChecker.h b/src/modelchecker/prctl/SparseMdpPrctlModelChecker.h
index b08c9abc5..2f862d631 100644
--- a/src/modelchecker/prctl/SparseMdpPrctlModelChecker.h
+++ b/src/modelchecker/prctl/SparseMdpPrctlModelChecker.h
@@ -23,9 +23,9 @@ namespace storm {
             virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeGloballyProbabilities(CheckTask<storm::logic::GloballyFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeConditionalProbabilities(CheckTask<storm::logic::ConditionalFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override;
             
         private:
diff --git a/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp b/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp
index 311ef7590..9612608df 100644
--- a/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp
+++ b/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp
@@ -80,7 +80,7 @@ namespace storm {
         }
         
         template<storm::dd::DdType DdType, typename ValueType>
-        std::unique_ptr<CheckResult> SymbolicDtmcPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SymbolicDtmcPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
             storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula();
             STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound.");
             storm::dd::Add<DdType> numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper<DdType, ValueType>::computeCumulativeRewards(this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getDiscreteTimeBound(), *this->linearEquationSolverFactory);
@@ -88,7 +88,7 @@ namespace storm {
         }
         
         template<storm::dd::DdType DdType, typename ValueType>
-        std::unique_ptr<CheckResult> SymbolicDtmcPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SymbolicDtmcPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
             storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula();
             STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound.");
             storm::dd::Add<DdType> numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper<DdType, ValueType>::computeInstantaneousRewards(this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getDiscreteTimeBound(), *this->linearEquationSolverFactory);
@@ -96,7 +96,7 @@ namespace storm {
         }
         
         template<storm::dd::DdType DdType, typename ValueType>
-        std::unique_ptr<CheckResult> SymbolicDtmcPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SymbolicDtmcPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
             storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula();
             std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula());
             SymbolicQualitativeCheckResult<DdType> const& subResult = subResultPointer->asSymbolicQualitativeCheckResult<DdType>();
diff --git a/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h b/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h
index 3472ee1b0..883af5ba5 100644
--- a/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h
+++ b/src/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h
@@ -19,9 +19,9 @@ namespace storm {
             virtual std::unique_ptr<CheckResult> computeNextProbabilities(CheckTask<storm::logic::NextFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeGloballyProbabilities(CheckTask<storm::logic::GloballyFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
             
         protected:
             storm::models::symbolic::Dtmc<DdType, ValueType> const& getModel() const override;
diff --git a/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp b/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp
index d6a3554e3..f9f2ca37b 100644
--- a/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp
+++ b/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp
@@ -79,7 +79,7 @@ namespace storm {
         }
         
         template<storm::dd::DdType DdType, typename ValueType>
-        std::unique_ptr<CheckResult> SymbolicMdpPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SymbolicMdpPrctlModelChecker<DdType, ValueType>::computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) {
             storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula();
             STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
             STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound.");
@@ -87,7 +87,7 @@ namespace storm {
         }
         
         template<storm::dd::DdType DdType, typename ValueType>
-        std::unique_ptr<CheckResult> SymbolicMdpPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SymbolicMdpPrctlModelChecker<DdType, ValueType>::computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) {
             storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula();
             STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
             STORM_LOG_THROW(rewardPathFormula.hasDiscreteTimeBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound.");
@@ -95,7 +95,7 @@ namespace storm {
         }
         
         template<storm::dd::DdType DdType, typename ValueType>
-        std::unique_ptr<CheckResult> SymbolicMdpPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SymbolicMdpPrctlModelChecker<DdType, ValueType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
             storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula();
             STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
             std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula());
diff --git a/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h b/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h
index 488971353..83cb17244 100644
--- a/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h
+++ b/src/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h
@@ -21,9 +21,9 @@ namespace storm {
             virtual std::unique_ptr<CheckResult> computeNextProbabilities(CheckTask<storm::logic::NextFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeGloballyProbabilities(CheckTask<storm::logic::GloballyFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeCumulativeRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::CumulativeRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
             
             protected:
             storm::models::symbolic::Mdp<DdType, ValueType> const& getModel() const override;
diff --git a/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp b/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp
index db972f49a..1290b43cb 100644
--- a/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp
+++ b/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp
@@ -153,7 +153,7 @@ namespace storm {
         }
         
         template<typename SparseDtmcModelType>
-        std::unique_ptr<CheckResult> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeLongRunAverageRewards(CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeLongRunAverageRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask) {
             // Do some sanity checks to establish some required properties.
             RewardModelType const& rewardModel = this->getModel().getRewardModel(checkTask.isRewardModelSet() ? checkTask.getRewardModel() : "");
             STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::IllegalArgumentException, "Input model does not have a reward model.");
@@ -535,7 +535,7 @@ namespace storm {
         }
         
         template<typename SparseDtmcModelType>
-        std::unique_ptr<CheckResult> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
+        std::unique_ptr<CheckResult> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
             storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula();
             
             // Retrieve the appropriate bitvectors by model checking the subformulas.
diff --git a/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h b/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h
index e1ec5034c..7359ac93f 100644
--- a/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h
+++ b/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h
@@ -41,8 +41,8 @@ namespace storm {
             virtual bool canHandle(CheckTask<storm::logic::Formula> const& checkTask) const override;
             virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(CheckTask<storm::logic::BoundedUntilFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeUntilProbabilities(CheckTask<storm::logic::UntilFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
-            virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
+            virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeConditionalProbabilities(CheckTask<storm::logic::ConditionalFormula> const& checkTask) override;
             virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override;
            
diff --git a/src/parser/FormulaParser.cpp b/src/parser/FormulaParser.cpp
index 0e8b530bc..97614507a 100644
--- a/src/parser/FormulaParser.cpp
+++ b/src/parser/FormulaParser.cpp
@@ -88,6 +88,17 @@ namespace storm {
             // A parser used for recognizing the optimality operators.
             optimalityOperatorStruct optimalityOperator_;
             
+            struct rewardMeasureTypeStruct : qi::symbols<char, storm::logic::RewardMeasureType> {
+                rewardMeasureTypeStruct() {
+                    add
+                    ("exp", storm::logic::RewardMeasureType::Expectation)
+                    ("var", storm::logic::RewardMeasureType::Variance);
+                }
+            };
+
+            // A parser used for recognizing the reward measure types.
+            rewardMeasureTypeStruct rewardMeasureType_;
+            
             // Parser and manager used for recognizing expressions.
             storm::parser::ExpressionParser expressionParser;
             
@@ -97,10 +108,11 @@ namespace storm {
             
             qi::rule<Iterator, std::vector<std::shared_ptr<storm::logic::Formula>>(), Skipper> start;
             
-            qi::rule<Iterator, std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>>(), qi::locals<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::ComparisonType>, boost::optional<double>>, Skipper> operatorInformation;
+            qi::rule<Iterator, storm::logic::OperatorInformation(), qi::locals<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::ComparisonType>, boost::optional<double>>, Skipper> operatorInformation;
+            qi::rule<Iterator, storm::logic::RewardMeasureType(), Skipper> rewardMeasureType;
             qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> probabilityOperator;
             qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> rewardOperator;
-            qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> expectedTimeOperator;
+            qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> timeOperator;
             qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> longRunAverageOperator;
             
             qi::rule<Iterator, std::shared_ptr<storm::logic::Formula>(), Skipper> simpleFormula;
@@ -147,11 +159,11 @@ namespace storm {
             std::shared_ptr<storm::logic::Formula> createNextFormula(std::shared_ptr<storm::logic::Formula> const& subformula) const;
             std::shared_ptr<storm::logic::Formula> createUntilFormula(std::shared_ptr<storm::logic::Formula> const& leftSubformula, boost::optional<boost::variant<std::pair<double, double>, uint_fast64_t>> const& timeBound, std::shared_ptr<storm::logic::Formula> const& rightSubformula);
             std::shared_ptr<storm::logic::Formula> createConditionalFormula(std::shared_ptr<storm::logic::Formula> const& leftSubformula, std::shared_ptr<storm::logic::Formula> const& rightSubformula, storm::logic::FormulaContext context) const;
-            std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> createOperatorInformation(boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<double> const& threshold) const;
-            std::shared_ptr<storm::logic::Formula> createLongRunAverageOperatorFormula(std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const;
-            std::shared_ptr<storm::logic::Formula> createRewardOperatorFormula(boost::optional<std::string> const& rewardModelName, std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const;
-            std::shared_ptr<storm::logic::Formula> createExpectedTimeOperatorFormula(std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const;
-            std::shared_ptr<storm::logic::Formula> createProbabilityOperatorFormula(std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula);
+            storm::logic::OperatorInformation createOperatorInformation(boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<double> const& threshold) const;
+            std::shared_ptr<storm::logic::Formula> createLongRunAverageOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const;
+            std::shared_ptr<storm::logic::Formula> createRewardOperatorFormula(boost::optional<storm::logic::RewardMeasureType> const& rewardMeasureType, boost::optional<std::string> const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const;
+            std::shared_ptr<storm::logic::Formula> createTimeOperatorFormula(boost::optional<storm::logic::RewardMeasureType> const& rewardMeasureType, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const;
+            std::shared_ptr<storm::logic::Formula> createProbabilityOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula);
             std::shared_ptr<storm::logic::Formula> createBinaryBooleanStateFormula(std::shared_ptr<storm::logic::Formula> const& leftSubformula, std::shared_ptr<storm::logic::Formula> const& rightSubformula, storm::logic::BinaryBooleanStateFormula::OperatorType operatorType);
             std::shared_ptr<storm::logic::Formula> createUnaryBooleanStateFormula(std::shared_ptr<storm::logic::Formula> const& subformula, boost::optional<storm::logic::UnaryBooleanStateFormula::OperatorType> const& operatorType);
             
@@ -301,6 +313,9 @@ namespace storm {
             pathFormula = conditionalFormula(qi::_r1);
             pathFormula.name("path formula");
             
+            rewardMeasureType = qi::lit("[") >> rewardMeasureType_ >> qi::lit("]");
+            rewardMeasureType.name("reward measure type");
+            
             operatorInformation = (-optimalityOperator_[qi::_a = qi::_1] >> ((relationalOperator_[qi::_b = qi::_1] > qi::double_[qi::_c = qi::_1]) | (qi::lit("=") > qi::lit("?"))))[qi::_val = phoenix::bind(&FormulaParserGrammar::createOperatorInformation, phoenix::ref(*this), qi::_a, qi::_b, qi::_c)];
             operatorInformation.name("operator information");
             
@@ -310,11 +325,11 @@ namespace storm {
             rewardModelName = qi::lit("{\"") > label > qi::lit("\"}");
             rewardModelName.name("reward model name");
             
-            rewardOperator = (qi::lit("R") > -rewardModelName > operatorInformation > qi::lit("[") > rewardPathFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createRewardOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2, qi::_3)];
+            rewardOperator = (qi::lit("R") > -rewardMeasureType > -rewardModelName > operatorInformation > qi::lit("[") > rewardPathFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createRewardOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_4)];
             rewardOperator.name("reward operator");
             
-            expectedTimeOperator = (qi::lit("ET") > operatorInformation > qi::lit("[") > eventuallyFormula(storm::logic::FormulaContext::ExpectedTime) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createExpectedTimeOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)];
-            expectedTimeOperator.name("expected time operator");
+            timeOperator = (qi::lit("T") > -rewardMeasureType > operatorInformation > qi::lit("[") > eventuallyFormula(storm::logic::FormulaContext::Time) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createTimeOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2, qi::_3)];
+            timeOperator.name("time operator");
             
             probabilityOperator = (qi::lit("P") > operatorInformation > qi::lit("[") > pathFormula(storm::logic::FormulaContext::Probability) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createProbabilityOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)];
             probabilityOperator.name("probability operator");
@@ -461,28 +476,36 @@ namespace storm {
             return std::shared_ptr<storm::logic::Formula>(new storm::logic::ConditionalFormula(leftSubformula, rightSubformula, context));
         }
         
-        std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> FormulaParserGrammar::createOperatorInformation(boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<double> const& threshold) const {
+        storm::logic::OperatorInformation FormulaParserGrammar::createOperatorInformation(boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<double> const& threshold) const {
             if (comparisonType && threshold) {
-                return std::make_pair(optimizationDirection, storm::logic::Bound<double>(comparisonType.get(), threshold.get()));
+                return storm::logic::OperatorInformation(optimizationDirection, storm::logic::Bound<double>(comparisonType.get(), threshold.get()));
             } else {
-                return std::make_pair(optimizationDirection, boost::none);
+                return storm::logic::OperatorInformation(optimizationDirection, boost::none);
             }
         }
         
-        std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createLongRunAverageOperatorFormula(std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const {
-            return std::shared_ptr<storm::logic::Formula>(new storm::logic::LongRunAverageOperatorFormula(operatorInformation.first, operatorInformation.second, subformula));
+        std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createLongRunAverageOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const {
+            return std::shared_ptr<storm::logic::Formula>(new storm::logic::LongRunAverageOperatorFormula(subformula, operatorInformation));
         }
         
-        std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createRewardOperatorFormula(boost::optional<std::string> const& rewardModelName, std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const {
-            return std::shared_ptr<storm::logic::Formula>(new storm::logic::RewardOperatorFormula(rewardModelName, operatorInformation.first, operatorInformation.second, subformula));
+        std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createRewardOperatorFormula(boost::optional<storm::logic::RewardMeasureType> const& rewardMeasureType, boost::optional<std::string> const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const {
+            storm::logic::RewardMeasureType measureType = storm::logic::RewardMeasureType::Expectation;
+            if (rewardMeasureType) {
+                measureType = rewardMeasureType.get();
+            }
+            return std::shared_ptr<storm::logic::Formula>(new storm::logic::RewardOperatorFormula(subformula, rewardModelName, operatorInformation, measureType));
         }
         
-        std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createExpectedTimeOperatorFormula(std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const {
-            return std::shared_ptr<storm::logic::Formula>(new storm::logic::ExpectedTimeOperatorFormula(operatorInformation.first, operatorInformation.second, subformula));
+        std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createTimeOperatorFormula(boost::optional<storm::logic::RewardMeasureType> const& rewardMeasureType, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) const {
+            storm::logic::RewardMeasureType measureType = storm::logic::RewardMeasureType::Expectation;
+            if (rewardMeasureType) {
+                measureType = rewardMeasureType.get();
+            }
+            return std::shared_ptr<storm::logic::Formula>(new storm::logic::TimeOperatorFormula(subformula, operatorInformation, measureType));
         }
         
-        std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createProbabilityOperatorFormula(std::pair<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::Bound<double>>> const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) {
-            return std::shared_ptr<storm::logic::Formula>(new storm::logic::ProbabilityOperatorFormula(operatorInformation.first, operatorInformation.second, subformula));
+        std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createProbabilityOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula> const& subformula) {
+            return std::shared_ptr<storm::logic::Formula>(new storm::logic::ProbabilityOperatorFormula(subformula, operatorInformation));
         }
         
         std::shared_ptr<storm::logic::Formula> FormulaParserGrammar::createBinaryBooleanStateFormula(std::shared_ptr<storm::logic::Formula> const& leftSubformula, std::shared_ptr<storm::logic::Formula> const& rightSubformula, storm::logic::BinaryBooleanStateFormula::OperatorType operatorType) {
diff --git a/src/parser/PrismParser.cpp b/src/parser/PrismParser.cpp
index 9040f3cf4..b2a153f99 100644
--- a/src/parser/PrismParser.cpp
+++ b/src/parser/PrismParser.cpp
@@ -11,7 +11,7 @@ namespace storm {
     namespace parser {
         storm::prism::Program PrismParser::parse(std::string const& filename) {
             // Open file and initialize result.
-            std::ifstream inputFileStream(filename, std::ios::in);
+            std::ifstream inputFileStream(filename);
             STORM_LOG_THROW(inputFileStream.good(), storm::exceptions::WrongFormatException, "Unable to read from file '" << filename << "'.");
             
             storm::prism::Program result;
@@ -35,7 +35,7 @@ namespace storm {
             PositionIteratorType first(input.begin());
             PositionIteratorType iter = first;
             PositionIteratorType last(input.end());
-            assert(first != last);
+            STORM_LOG_ASSERT(first != last, "Illegal input to PRISM parser.");
             
             // Create empty result;
             storm::prism::Program result;
diff --git a/src/settings/ArgumentValidators.h b/src/settings/ArgumentValidators.h
index 235ddd765..6e1b4aa02 100644
--- a/src/settings/ArgumentValidators.h
+++ b/src/settings/ArgumentValidators.h
@@ -18,6 +18,7 @@
 #include "src/exceptions/IllegalArgumentValueException.h"
 #include "src/exceptions/IllegalFunctionCallException.h"
 
+#include <sys/stat.h>
 
 namespace storm {
 	namespace settings {
@@ -97,11 +98,16 @@ namespace storm {
              */
 			static std::function<bool (std::string const&)> existingReadableFileValidator() {
 				return [] (std::string const fileName) -> bool {
-					std::ifstream targetFile(fileName);
-					bool isFileGood = targetFile.good();
-
-                    STORM_LOG_THROW(isFileGood, storm::exceptions::IllegalArgumentValueException, "The file " << fileName << " does not exist or is not readable.");
-					return isFileGood;
+                    // First check existence as ifstream::good apparently als returns true for directories.
+                    struct stat info;
+                    stat(fileName.c_str(), &info);
+                    STORM_LOG_THROW(info.st_mode & S_IFREG, storm::exceptions::IllegalArgumentValueException, "Unable to read from non-existing file '" << fileName << "'.");
+                    
+                    // Now that we know it's a file, we can check its readability.
+                    std::ifstream istream(fileName);
+                    STORM_LOG_THROW(istream.good(), storm::exceptions::IllegalArgumentValueException, "Unable to read from file '" << fileName << "'.");
+                    
+                    return true;
 				};
 			}
 
diff --git a/src/settings/modules/GeneralSettings.cpp b/src/settings/modules/GeneralSettings.cpp
index 95a48931b..9979c6824 100644
--- a/src/settings/modules/GeneralSettings.cpp
+++ b/src/settings/modules/GeneralSettings.cpp
@@ -32,6 +32,8 @@ namespace storm {
             const std::string GeneralSettings::explicitOptionShortName = "exp";
             const std::string GeneralSettings::symbolicOptionName = "symbolic";
             const std::string GeneralSettings::symbolicOptionShortName = "s";
+            const std::string GeneralSettings::explorationOrderOptionName = "explorder";
+            const std::string GeneralSettings::explorationOrderOptionShortName = "eo";
             const std::string GeneralSettings::propertyOptionName = "prop";
             const std::string GeneralSettings::propertyOptionShortName = "prop";
             const std::string GeneralSettings::transitionRewardsOptionName = "transrew";
@@ -83,6 +85,11 @@ namespace storm {
                                 .addArgument(storm::settings::ArgumentBuilder::createStringArgument("labeling filename", "The name of the file from which to read the state labeling.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, symbolicOptionName, false, "Parses the model given in a symbolic representation.").setShortName(symbolicOptionShortName)
                                 .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the symbolic model.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
+
+                std::vector<std::string> explorationOrders = {"dfs", "bfs"};
+                this->addOption(storm::settings::OptionBuilder(moduleName, explorationOrderOptionName, false, "Sets which exploration order to use.").setShortName(explorationOrderOptionShortName)
+                                .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the exploration order to choose. Available are: dfs and bfs.").addValidationFunctionString(storm::settings::ArgumentValidators::stringInListValidator(explorationOrders)).setDefaultValueString("bfs").build()).build());
+
                 this->addOption(storm::settings::OptionBuilder(moduleName, propertyOptionName, false, "Specifies the formulas to be checked on the model.").setShortName(propertyOptionShortName)
                                 .addArgument(storm::settings::ArgumentBuilder::createStringArgument("formula or filename", "The formula or the file containing the formulas.").build()).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, counterexampleOptionName, false, "Generates a counterexample for the given PRCTL formulas if not satisfied by the model")
@@ -186,6 +193,20 @@ namespace storm {
                 return this->getOption(symbolicOptionName).getArgumentByName("filename").getValueAsString();
             }
             
+            bool GeneralSettings::isExplorationOrderSet() const {
+                return this->getOption(explorationOrderOptionName).getHasOptionBeenSet();
+            }
+            
+            storm::builder::ExplorationOrder GeneralSettings::getExplorationOrder() const {
+                std::string explorationOrderAsString = this->getOption(explorationOrderOptionName).getArgumentByName("name").getValueAsString();
+                if (explorationOrderAsString == "dfs") {
+                    return storm::builder::ExplorationOrder::Dfs;
+                } else if (explorationOrderAsString == "bfs") {
+                    return storm::builder::ExplorationOrder::Bfs;
+                }
+                STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown exploration order '" << explorationOrderAsString << "'.");
+            }
+            
             bool GeneralSettings::isPropertySet() const {
                 return this->getOption(propertyOptionName).getHasOptionBeenSet();
             }
diff --git a/src/settings/modules/GeneralSettings.h b/src/settings/modules/GeneralSettings.h
index 8144c0a1f..ad268db93 100644
--- a/src/settings/modules/GeneralSettings.h
+++ b/src/settings/modules/GeneralSettings.h
@@ -4,6 +4,8 @@
 #include "storm-config.h"
 #include "src/settings/modules/ModuleSettings.h"
 
+#include "src/builder/ExplorationOrder.h"
+
 namespace storm {
     namespace solver {
         enum class EquationSolverType;
@@ -25,7 +27,6 @@ namespace storm {
             class GeneralSettings : public ModuleSettings {
             public:
                 // An enumeration of all engines.
-
                 enum class Engine {
                     Sparse, Hybrid, Dd, AbstractionRefinement
                 };
@@ -138,6 +139,20 @@ namespace storm {
                  * @return The name of the file that contains the symbolic model specification.
                  */
                 std::string getSymbolicModelFilename() const;
+                
+                /*!
+                 * Retrieves whether the model exploration order was set.
+                 *
+                 * @return True if the model exploration option was set.
+                 */
+                bool isExplorationOrderSet() const;
+                
+                /*!
+                 * Retrieves the exploration order if it was set.
+                 *
+                 * @return The chosen exploration order.
+                 */
+                storm::builder::ExplorationOrder getExplorationOrder() const;
 
                 /*!
                  * Retrieves whether the property option was set.
@@ -389,6 +404,8 @@ namespace storm {
                 static const std::string explicitOptionShortName;
                 static const std::string symbolicOptionName;
                 static const std::string symbolicOptionShortName;
+                static const std::string explorationOrderOptionName;
+                static const std::string explorationOrderOptionShortName;
                 static const std::string propertyOptionName;
                 static const std::string propertyOptionShortName;
                 static const std::string transitionRewardsOptionName;
diff --git a/src/storage/BitVector.cpp b/src/storage/BitVector.cpp
index 9ad566258..f5aea6370 100644
--- a/src/storage/BitVector.cpp
+++ b/src/storage/BitVector.cpp
@@ -66,11 +66,11 @@ namespace storm {
             return currentIndex == other.currentIndex;
         }
 
-        BitVector::BitVector() : bitCount(0), bucketVector() {
+        BitVector::BitVector() : bitCount(0), buckets(nullptr) {
             // Intentionally left empty.
         }
 
-        BitVector::BitVector(uint_fast64_t length, bool init) : bitCount(length) {
+        BitVector::BitVector(uint_fast64_t length, bool init) : bitCount(length), buckets(nullptr) {
             // Compute the correct number of buckets needed to store the given number of bits.
             uint_fast64_t bucketCount = length >> 6;
             if ((length & mod64mask) != 0) {
@@ -79,10 +79,17 @@ namespace storm {
 
             // Initialize the storage with the required values.
             if (init) {
-                bucketVector = std::vector<uint64_t>(bucketCount, -1ll);
+                buckets = new uint64_t[bucketCount];
+                std::fill_n(buckets, bucketCount, -1ull);
                 truncateLastBucket();
             } else {
-                bucketVector = std::vector<uint64_t>(bucketCount, 0);
+                buckets = new uint64_t[bucketCount]();
+            }
+        }
+        
+        BitVector::~BitVector() {
+            if (buckets != nullptr) {
+                delete buckets;
             }
             
         }
@@ -96,23 +103,22 @@ namespace storm {
             // Intentionally left empty.
         }
 
-        BitVector::BitVector(uint_fast64_t bucketCount, uint_fast64_t bitCount) : bitCount(bitCount), bucketVector(bucketCount) {
+        BitVector::BitVector(uint_fast64_t bucketCount, uint_fast64_t bitCount) : bitCount(bitCount), buckets(nullptr) {
             STORM_LOG_ASSERT((bucketCount << 6) == bitCount, "Bit count does not match number of buckets.");
+            buckets = new uint64_t[bucketCount]();
         }
 
-        BitVector::BitVector(BitVector const& other) : bitCount(other.bitCount), bucketVector(other.bucketVector) {
-            // Intentionally left empty.
+        BitVector::BitVector(BitVector const& other) : bitCount(other.bitCount), buckets(nullptr) {
+            buckets = new uint64_t[other.bucketCount()];
+            std::copy_n(other.buckets, other.bucketCount(), buckets);
         }
 
-        //BitVector::BitVector(BitVector&& other) : bitCount(other.bitCount), bucketVector(std::move(other.bucketVector)) {
-        // Intentionally left empty.
-        //}
-
         BitVector& BitVector::operator=(BitVector const& other) {
             // Only perform the assignment if the source and target are not identical.
             if (this != &other) {
                 bitCount = other.bitCount;
-                bucketVector = std::vector<uint64_t>(other.bucketVector);
+                buckets = new uint64_t[other.bucketCount()];
+                std::copy_n(other.buckets, other.bucketCount(), buckets);
             }
             return *this;
         }
@@ -124,9 +130,9 @@ namespace storm {
                 return false;
             }
 
-            std::vector<uint64_t>::const_iterator first1 = this->bucketVector.begin();
-            std::vector<uint64_t>::const_iterator last1 = this->bucketVector.end();
-            std::vector<uint64_t>::const_iterator first2 = other.bucketVector.begin();
+            uint64_t* first1 = this->buckets;
+            uint64_t* last1 = this->buckets + this->bucketCount();
+            uint64_t* first2 = other.buckets;
 
             for (; first1 != last1; ++first1, ++first2) {
                 if (*first1 < *first2) {
@@ -137,12 +143,18 @@ namespace storm {
             }
             return false;
         }
+        
+        BitVector::BitVector(BitVector&& other) : bitCount(other.bitCount), buckets(other.buckets) {
+            other.bitCount = 0;
+            other.buckets = nullptr;
+        }
 
         BitVector& BitVector::operator=(BitVector&& other) {
             // Only perform the assignment if the source and target are not identical.
             if (this != &other) {
                 bitCount = other.bitCount;
-                bucketVector = std::move(other.bucketVector);
+                this->buckets = other.buckets;
+                other.buckets = nullptr;
             }
 
             return *this;
@@ -153,14 +165,7 @@ namespace storm {
             if (this->bitCount != other.bitCount) return false;
 
             // If the lengths match, we compare the buckets one by one.
-            for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it1 != bucketVector.end(); ++it1, ++it2) {
-                if (*it1 != *it2) {
-                    return false;
-                }
-            }
-
-            // All buckets were equal, so the bit vectors are equal.
-            return true;
+            return std::equal(this->buckets, this->buckets + this->bucketCount(), other.buckets);
         }
 
         bool BitVector::operator!=(BitVector const& other) const {
@@ -173,9 +178,9 @@ namespace storm {
 
             uint64_t mask = 1ull << (63 - (index & mod64mask));
             if (value) {
-                bucketVector[bucket] |= mask;
+                buckets[bucket] |= mask;
             } else {
-                bucketVector[bucket] &= ~mask;
+                buckets[bucket] &= ~mask;
             }
         }
 
@@ -189,7 +194,7 @@ namespace storm {
         bool BitVector::operator[](uint_fast64_t index) const {
             uint64_t bucket = index >> 6;
             uint64_t mask = 1ull << (63 - (index & mod64mask));
-            return (this->bucketVector[bucket] & mask) == mask;
+            return (this->buckets[bucket] & mask) == mask;
         }
 
         bool BitVector::get(uint_fast64_t index) const {
@@ -204,89 +209,80 @@ namespace storm {
                     ++newBucketCount;
                 }
 
-                if (newBucketCount > bucketVector.size()) {
+                if (newBucketCount > this->bucketCount()) {
+                    uint64_t* newBuckets = new uint64_t[newBucketCount];
+                    std::copy_n(buckets, this->bucketCount(), newBuckets);
                     if (init) {
-                        bucketVector.back() |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull);
-                        bucketVector.resize(newBucketCount, -1ull);
+                        newBuckets[this->bucketCount() - 1] |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull);
+                        std::fill_n(newBuckets + this->bucketCount(), newBucketCount - this->bucketCount(), -1ull);
                     } else {
-                        bucketVector.resize(newBucketCount, 0);
+                        std::fill_n(newBuckets + this->bucketCount(), newBucketCount - this->bucketCount(), 0);
+                    }
+                    if (buckets != nullptr) {
+                        delete buckets;
                     }
+                    buckets = newBuckets;
                     bitCount = newLength;
                 } else {
                     // If the underlying storage does not need to grow, we have to insert the missing bits.
                     if (init) {
-                        bucketVector.back() |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull);
+                        buckets[this->bucketCount() - 1] |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull);
                     }
                     bitCount = newLength;
                 }
                 truncateLastBucket();
             } else {
-                bitCount = newLength;
                 uint_fast64_t newBucketCount = newLength >> 6;
                 if ((newLength & mod64mask) != 0) {
                     ++newBucketCount;
                 }
 
-                bucketVector.resize(newBucketCount);
+                // If the number of buckets needs to be reduced, we resize it now. Otherwise, we can just truncate the
+                // last bucket.
+                if (newBucketCount < this->bucketCount()) {
+                    uint64_t* newBuckets = new uint64_t[newBucketCount];
+                    std::copy_n(buckets, newBucketCount, newBuckets);
+                    if (buckets != nullptr) {
+                        delete buckets;
+                    }
+                    buckets = newBuckets;
+                    bitCount = newLength;
+                }
+                bitCount = newLength;
                 truncateLastBucket();
             }
         }
 
         BitVector BitVector::operator&(BitVector const& other) const {
             STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
-
             BitVector result(bitCount);
-            std::vector<uint64_t>::iterator it = result.bucketVector.begin();
-            for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it2, ++it) {
-                *it = *it1 & *it2;
-            }
-
+            std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets, [] (uint64_t const& a, uint64_t const& b) { return a & b; });
             return result;
         }
 
         BitVector& BitVector::operator&=(BitVector const& other) {
             STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
-
-            std::vector<uint64_t>::iterator it = bucketVector.begin();
-            for (std::vector<uint64_t>::const_iterator otherIt = other.bucketVector.begin(); it != bucketVector.end() && otherIt != other.bucketVector.end(); ++it, ++otherIt) {
-                *it &= *otherIt;
-            }
-
+            std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, this->buckets, [] (uint64_t const& a, uint64_t const& b) { return a & b; });
             return *this;
         }
 
         BitVector BitVector::operator|(BitVector const& other) const {
             STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
-
             BitVector result(bitCount);
-            std::vector<uint64_t>::iterator it = result.bucketVector.begin();
-            for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it2, ++it) {
-                *it = *it1 | *it2;
-            }
-
+            std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets, [] (uint64_t const& a, uint64_t const& b) { return a | b; });
             return result;
         }
 
         BitVector& BitVector::operator|=(BitVector const& other) {
             STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
-
-            std::vector<uint64_t>::iterator it = bucketVector.begin();
-            for (std::vector<uint64_t>::const_iterator otherIt = other.bucketVector.begin(); it != bucketVector.end() && otherIt != other.bucketVector.end(); ++it, ++otherIt) {
-                *it |= *otherIt;
-            }
-
+            std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, this->buckets, [] (uint64_t const& a, uint64_t const& b) { return a | b; });
             return *this;
         }
 
         BitVector BitVector::operator^(BitVector const& other) const {
             STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
-
             BitVector result(bitCount);
-            std::vector<uint64_t>::iterator it = result.bucketVector.begin();
-            for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it2, ++it) {
-                *it = *it1 ^ *it2;
-            }
-
+            std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets, [] (uint64_t const& a, uint64_t const& b) { return a ^ b; });
             result.truncateLastBucket();
             return result;
         }
@@ -321,19 +317,13 @@ namespace storm {
 
         BitVector BitVector::operator~() const {
             BitVector result(this->bitCount);
-            std::vector<uint64_t>::iterator it = result.bucketVector.begin();
-            for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it) {
-                *it = ~(*it1);
-            }
-
+            std::transform(this->buckets, this->buckets + this->bucketCount(), result.buckets, [] (uint64_t const& a) { return ~a; });
             result.truncateLastBucket();
             return result;
         }
 
         void BitVector::complement() {
-            for (auto& element : bucketVector) {
-                element = ~element;
-            }
+            std::transform(this->buckets, this->buckets + this->bucketCount(), this->buckets, [] (uint64_t const& a) { return ~a; });
             truncateLastBucket();
         }
 
@@ -341,11 +331,7 @@ namespace storm {
             STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
 
             BitVector result(bitCount);
-            std::vector<uint64_t>::iterator it = result.bucketVector.begin();
-            for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it2, ++it) {
-                *it = ~(*it1) | *it2;
-            }
-
+            std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets, [] (uint64_t const& a, uint64_t const& b) { return (~a | b); });
             result.truncateLastBucket();
             return result;
         }
@@ -353,7 +339,11 @@ namespace storm {
         bool BitVector::isSubsetOf(BitVector const& other) const {
             STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
 
-            for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it1 != bucketVector.end(); ++it1, ++it2) {
+            uint64_t const* it1 = buckets;
+            uint64_t const* ite1 = buckets + bucketCount();
+            uint64_t const* it2 = other.buckets;
+            
+            for (; it1 != ite1; ++it1, ++it2) {
                 if ((*it1 & *it2) != *it1) {
                     return false;
                 }
@@ -364,7 +354,11 @@ namespace storm {
         bool BitVector::isDisjointFrom(BitVector const& other) const {
             STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
 
-            for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it1 != bucketVector.end(); ++it1, ++it2) {
+            uint64_t const* it1 = buckets;
+            uint64_t const* ite1 = buckets + bucketCount();
+            uint64_t const* it2 = other.buckets;
+            
+            for (; it1 != ite1; ++it1, ++it2) {
                 if ((*it1 & *it2) != 0) {
                     return false;
                 }
@@ -379,9 +373,9 @@ namespace storm {
             // Compute the first bucket that needs to be checked and the number of buckets.
             uint64_t index = bitIndex >> 6;
 
-            std::vector<uint64_t>::const_iterator first1 = bucketVector.begin() + index;
-            std::vector<uint64_t>::const_iterator first2 = other.bucketVector.begin();
-            std::vector<uint64_t>::const_iterator last2 = other.bucketVector.end();
+            uint64_t const* first1 = buckets + index;
+            uint64_t const* first2 = other.buckets;
+            uint64_t const* last2 = other.buckets + other.bucketCount();
 
             for (; first2 != last2; ++first1, ++first2) {
                 if (*first1 != *first2) {
@@ -398,10 +392,10 @@ namespace storm {
             // Compute the first bucket that needs to be checked and the number of buckets.
             uint64_t index = bitIndex >> 6;
 
-            std::vector<uint64_t>::iterator first1 = bucketVector.begin() + index;
-            std::vector<uint64_t>::const_iterator first2 = other.bucketVector.begin();
-            std::vector<uint64_t>::const_iterator last2 = other.bucketVector.end();
-
+            uint64_t* first1 = buckets + index;
+            uint64_t const* first2 = other.buckets;
+            uint64_t const* last2 = other.buckets + other.bucketCount();
+            
             for (; first2 != last2; ++first1, ++first2) {
                 *first1 = *first2;
             }
@@ -413,8 +407,8 @@ namespace storm {
             STORM_LOG_ASSERT(index + numberOfBuckets <= this->bucketCount(), "Argument is out-of-range.");
 
             storm::storage::BitVector result(numberOfBuckets, numberOfBits);
-            std::copy(this->bucketVector.begin() + index, this->bucketVector.begin() + index + numberOfBuckets, result.bucketVector.begin());
-
+            std::copy(this->buckets + index, this->buckets + index + numberOfBuckets, result.buckets);
+            result.truncateLastBucket();
             return result;
         }
 
@@ -433,10 +427,10 @@ namespace storm {
             if (bitIndexInBucket + numberOfBits < 64) {
                 // If the value stops before the end of the bucket, we need to erase some lower bits.
                 mask &= ~((1ull << (64 - (bitIndexInBucket + numberOfBits))) - 1ull);
-                return (bucketVector[bucket] & mask) >> (64 - (bitIndexInBucket + numberOfBits));
+                return (buckets[bucket] & mask) >> (64 - (bitIndexInBucket + numberOfBits));
             } else if (bitIndexInBucket + numberOfBits > 64) {
                 // In this case, the integer "crosses" the bucket line.
-                uint64_t result = (bucketVector[bucket] & mask);
+                uint64_t result = (buckets[bucket] & mask);
                 ++bucket;
 
                 // Compute the remaining number of bits.
@@ -448,13 +442,13 @@ namespace storm {
                 // Strip away everything from the second bucket that is beyond the final index and add it to the
                 // intermediate result.
                 mask = ~((1ull << (64 - numberOfBits)) - 1ull);
-                uint64_t lowerBits = bucketVector[bucket] & mask;
+                uint64_t lowerBits = buckets[bucket] & mask;
                 result |= (lowerBits >> (64 - numberOfBits));
 
                 return result;
             } else {
                 // In this case, it suffices to take the current mask.
-                return bucketVector[bucket] & mask;
+                return buckets[bucket] & mask;
             }
         }
         
@@ -498,10 +492,10 @@ namespace storm {
             if (bitIndexInBucket + numberOfBits < 64) {
                 // If the value stops before the end of the bucket, we need to erase some lower bits.
                 mask &= ~((1ull << (64 - (bitIndexInBucket + numberOfBits))) - 1ull);
-                bucketVector[bucket] = (bucketVector[bucket] & ~mask) | (value << (64 - (bitIndexInBucket + numberOfBits)));
+                buckets[bucket] = (buckets[bucket] & ~mask) | (value << (64 - (bitIndexInBucket + numberOfBits)));
             } else if (bitIndexInBucket + numberOfBits > 64) {
                 // Write the part of the value that falls into the first bucket.
-                bucketVector[bucket] = (bucketVector[bucket] & ~mask) | (value >> (numberOfBits + (bitIndexInBucket - 64)));
+                buckets[bucket] = (buckets[bucket] & ~mask) | (value >> (numberOfBits + (bitIndexInBucket - 64)));
                 ++bucket;
 
                 // Compute the remaining number of bits.
@@ -512,45 +506,41 @@ namespace storm {
 
                 // Put the remaining bits in their place.
                 mask = ((1ull << (64 - numberOfBits)) - 1ull);
-                bucketVector[bucket] = (bucketVector[bucket] & mask) | value;
+                buckets[bucket] = (buckets[bucket] & mask) | value;
             } else {
-                bucketVector[bucket] = (bucketVector[bucket] & ~mask) | value;
+                buckets[bucket] = (buckets[bucket] & ~mask) | value;
             }
         }
 
         bool BitVector::empty() const {
-            for (auto& element : bucketVector) {
-                if (element != 0) {
-                    return false;
-                }
-            }
-            return true;
+            uint64_t* last = buckets + bucketCount();
+            uint64_t* it = std::find_if(buckets, last, [] (uint64_t const& a) { return a != 0; });
+            return it == last;
         }
 
         bool BitVector::full() const {
             // Check that all buckets except the last one have all bits set.
-            for (uint_fast64_t index = 0; index < bucketVector.size() - 1; ++index) {
-                if (bucketVector[index] != -1ull) {
+            uint64_t* last = buckets + bucketCount() - 1;
+            for (uint64_t const* it = buckets; it < last; ++it) {
+                if (*it != -1ull) {
                     return false;
                 }
             }
-
+            
             // Now check whether the relevant bits are set in the last bucket.
             uint64_t mask = ~((1ull << (64 - (bitCount & mod64mask))) - 1ull);
-            if ((bucketVector.back() & mask) != mask) {
+            if ((*last & mask) != mask) {
                 return false;
             }
             return true;
         }
 
         void BitVector::clear() {
-            for (auto& element : bucketVector) {
-                element = 0;
-            }
+            std::fill_n(buckets, this->bucketCount(), 0);
         }
 
         uint_fast64_t BitVector::getNumberOfSetBits() const {
-            return getNumberOfSetBitsBeforeIndex(bucketVector.size() << 6);
+            return getNumberOfSetBitsBeforeIndex(bitCount);
         }
 
         uint_fast64_t BitVector::getNumberOfSetBitsBeforeIndex(uint_fast64_t index) const {
@@ -561,14 +551,14 @@ namespace storm {
             for (uint_fast64_t i = 0; i < bucket; ++i) {
                 // Check if we are using g++ or clang++ and, if so, use the built-in function
 #if (defined (__GNUG__) || defined(__clang__))
-                result += __builtin_popcountll(bucketVector[i]);
+                result += __builtin_popcountll(buckets[i]);
 #elif defined WINDOWS
 #include <nmmintrin.h>
                 // If the target machine does not support SSE4, this will fail.
                 result += _mm_popcnt_u64(bucketVector[i]);
 #else
                 uint_fast32_t cnt;
-                uint_fast64_t bitset = bucketVector[i];
+                uint_fast64_t bitset = buckets[i];
                 for (cnt = 0; bitset; cnt++) {
                     bitset &= bitset - 1;
                 }
@@ -580,7 +570,7 @@ namespace storm {
             uint64_t tmp = index & mod64mask;
             if (tmp != 0) {
                 tmp = ~((1ll << (64 - (tmp & mod64mask))) - 1ll);
-                tmp &= bucketVector[bucket];
+                tmp &= buckets[bucket];
                 // Check if we are using g++ or clang++ and, if so, use the built-in function
 #if (defined (__GNUG__) || defined(__clang__))
                 result += __builtin_popcountll(tmp);
@@ -617,19 +607,19 @@ namespace storm {
         }
 
         std::size_t BitVector::getSizeInBytes() const {
-            return sizeof (*this) + sizeof (uint64_t) * bucketVector.size();
+            return sizeof (*this) + sizeof (uint64_t) * bucketCount();
         }
 
         BitVector::const_iterator BitVector::begin() const {
-            return const_iterator(bucketVector.data(), 0, bitCount);
+            return const_iterator(buckets, 0, bitCount);
         }
 
         BitVector::const_iterator BitVector::end() const {
-            return const_iterator(bucketVector.data(), bitCount, bitCount, false);
+            return const_iterator(buckets, bitCount, bitCount, false);
         }
 
         uint_fast64_t BitVector::getNextSetIndex(uint_fast64_t startingIndex) const {
-            return getNextSetIndex(bucketVector.data(), startingIndex, bitCount);
+            return getNextSetIndex(buckets, startingIndex, bitCount);
         }
 
         uint_fast64_t BitVector::getNextSetIndex(uint64_t const* dataPtr, uint_fast64_t startingIndex, uint_fast64_t endIndex) {
@@ -903,17 +893,21 @@ namespace storm {
 
         void BitVector::truncateLastBucket() {
             if ((bitCount & mod64mask) != 0) {
-                bucketVector.back() &= ~((1ll << (64 - (bitCount & mod64mask))) - 1ll);
+                buckets[bucketCount() - 1] &= ~((1ll << (64 - (bitCount & mod64mask))) - 1ll);
             }
         }
 
         size_t BitVector::bucketCount() const {
-            return bucketVector.size();
+            size_t result = (bitCount >> 6);
+            if ((bitCount & mod64mask) != 0) {
+                ++result;
+            }
+            return result;
         }
 
-        std::ostream& operator<<(std::ostream& out, BitVector const& bitVector) {
-            out << "bit vector(" << bitVector.getNumberOfSetBits() << "/" << bitVector.bitCount << ") [";
-            for (auto index : bitVector) {
+        std::ostream& operator<<(std::ostream& out, BitVector const& bitvector) {
+            out << "bit vector(" << bitvector.getNumberOfSetBits() << "/" << bitvector.bitCount << ") [";
+            for (auto index : bitvector) {
                 out << index << " ";
             }
             out << "]";
@@ -941,13 +935,13 @@ namespace storm {
             out << std::endl;
         }
 
-        std::size_t NonZeroBitVectorHash::operator()(storm::storage::BitVector const& bv) const {
-            STORM_LOG_ASSERT(bv.size() > 0, "Cannot hash bit vector of zero size.");
+        std::size_t NonZeroBitVectorHash::operator()(storm::storage::BitVector const& bitvector) const {
+            STORM_LOG_ASSERT(bitvector.size() > 0, "Cannot hash bit vector of zero size.");
             std::size_t result = 0;
 
-            for (uint_fast64_t index = 0; index < bv.bucketVector.size(); ++index) {
+            for (uint_fast64_t index = 0; index < bitvector.bucketCount(); ++index) {
                 result ^= result << 3;
-                result ^= result >> bv.getAsInt(index << 6, 5);
+                result ^= result >> bitvector.getAsInt(index << 6, 5);
             }
 
             // Erase the last bit and add one to definitely make this hash value non-zero.
@@ -971,7 +965,7 @@ namespace storm {
 
 namespace std {
 
-    std::size_t hash<storm::storage::BitVector>::operator()(storm::storage::BitVector const& bv) const {
-        return boost::hash_range(bv.bucketVector.begin(), bv.bucketVector.end());
+    std::size_t hash<storm::storage::BitVector>::operator()(storm::storage::BitVector const& bitvector) const {
+        return boost::hash_range(bitvector.buckets, bitvector.buckets + bitvector.bucketCount());
     }
 }
diff --git a/src/storage/BitVector.h b/src/storage/BitVector.h
index 2338faac6..62ae010be 100644
--- a/src/storage/BitVector.h
+++ b/src/storage/BitVector.h
@@ -104,6 +104,11 @@ namespace storm {
              */
             BitVector();
             
+            /*
+             * Deconstructs a bit vector by deleting the underlying storage.
+             */
+            ~BitVector();
+            
             /*!
              * Constructs a bit vector which can hold the given number of bits and initializes all bits with the
              * provided truth value.
@@ -141,7 +146,7 @@ namespace storm {
              *
              * @param other The bit vector from which to move-construct.
              */
-            BitVector(BitVector&& other) = default;
+            BitVector(BitVector&& other);
             
             /*!
              * Compares the given bit vector with the current one.
@@ -537,7 +542,7 @@ namespace storm {
             uint_fast64_t bitCount;
             
             // The underlying storage of 64-bit buckets for all bits of this bit vector.
-            std::vector<uint64_t> bucketVector;
+            uint64_t* buckets;
             
             // A bit mask that can be used to reduce a modulo 64 operation to a logical "and".
             static const uint_fast64_t mod64mask = (1 << 6) - 1;
diff --git a/src/storage/BitVectorHashMap.cpp b/src/storage/BitVectorHashMap.cpp
index b38e5caab..d094ca3b2 100644
--- a/src/storage/BitVectorHashMap.cpp
+++ b/src/storage/BitVectorHashMap.cpp
@@ -42,7 +42,7 @@ namespace storm {
         std::pair<storm::storage::BitVector, ValueType> BitVectorHashMap<ValueType, Hash1, Hash2>::BitVectorHashMapIterator::operator*() const {
             return map.getBucketAndValue(*indexIt);
         }
-        
+                
         template<class ValueType, class Hash1, class Hash2>
         BitVectorHashMap<ValueType, Hash1, Hash2>::BitVectorHashMap(uint64_t bucketSize, uint64_t initialSize, double loadFactor) : loadFactor(loadFactor), bucketSize(bucketSize), numberOfElements(0) {
             STORM_LOG_ASSERT(bucketSize % 64 == 0, "Bucket size must be a multiple of 64.");
@@ -264,6 +264,13 @@ namespace storm {
             return std::make_pair(buckets.get(bucket * bucketSize, bucketSize), values[bucket]);
         }
         
+        template<class ValueType, class Hash1, class Hash2>
+        void BitVectorHashMap<ValueType, Hash1, Hash2>::remap(std::function<ValueType(ValueType const&)> const& remapping) {
+            for (auto pos : occupied) {
+                values[pos] = remapping(values[pos]);
+            }
+        }
+        
         template class BitVectorHashMap<uint_fast64_t>;
         template class BitVectorHashMap<uint32_t>;
     }
diff --git a/src/storage/BitVectorHashMap.h b/src/storage/BitVectorHashMap.h
index 18ca52186..cda4a1fde 100644
--- a/src/storage/BitVectorHashMap.h
+++ b/src/storage/BitVectorHashMap.h
@@ -55,7 +55,7 @@ namespace storm {
              * @param loadFactor The load factor that determines at which point the size of the underlying storage is
              * increased.
              */
-            BitVectorHashMap(uint64_t bucketSize, uint64_t initialSize, double loadFactor = 0.75);
+            BitVectorHashMap(uint64_t bucketSize = 64, uint64_t initialSize = 1000, double loadFactor = 0.75);
             
             /*!
              * Searches for the given key in the map. If it is found, the mapped-to value is returned. Otherwise, the
@@ -150,6 +150,13 @@ namespace storm {
              */
             std::size_t capacity() const;
             
+            /*!
+             * Performs a remapping of all values stored by applying the given remapping.
+             *
+             * @param remapping The remapping to apply.
+             */
+            void remap(std::function<ValueType(ValueType const&)> const& remapping);
+            
         private:
             /*!
              * Retrieves whether the given bucket holds a value.
diff --git a/src/storage/Distribution.cpp b/src/storage/Distribution.cpp
index 50d794d01..5843e964b 100644
--- a/src/storage/Distribution.cpp
+++ b/src/storage/Distribution.cpp
@@ -14,13 +14,13 @@
 namespace storm {
     namespace storage {
         
-        template<typename ValueType>
-        Distribution<ValueType>::Distribution() {
+        template<typename ValueType, typename StateType>
+        Distribution<ValueType, StateType>::Distribution() {
             // Intentionally left empty.
         }
         
-        template<typename ValueType>
-        bool Distribution<ValueType>::equals(Distribution<ValueType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const {
+        template<typename ValueType, typename StateType>
+        bool Distribution<ValueType, StateType>::equals(Distribution<ValueType, StateType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const {
             // We need to check equality by ourselves, because we need to account for epsilon differences.
             if (this->distribution.size() != other.distribution.size()) {
                 return false;
@@ -42,8 +42,8 @@ namespace storm {
             return true;
         }
         
-        template<typename ValueType>
-        void Distribution<ValueType>::addProbability(storm::storage::sparse::state_type const& state, ValueType const& probability) {
+        template<typename ValueType, typename StateType>
+        void Distribution<ValueType, StateType>::addProbability(StateType const& state, ValueType const& probability) {
             auto it = this->distribution.find(state);
             if (it == this->distribution.end()) {
                 this->distribution.emplace_hint(it, state, probability);
@@ -52,8 +52,8 @@ namespace storm {
             }
         }
         
-        template<typename ValueType>
-        void Distribution<ValueType>::removeProbability(storm::storage::sparse::state_type const& state, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator) {
+        template<typename ValueType, typename StateType>
+        void Distribution<ValueType, StateType>::removeProbability(StateType const& state, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator) {
             auto it = this->distribution.find(state);
             STORM_LOG_ASSERT(it != this->distribution.end(), "Cannot remove probability, because the state is not in the support of the distribution.");
             it->second -= probability;
@@ -62,34 +62,44 @@ namespace storm {
             }
         }
         
-        template<typename ValueType>
-        void Distribution<ValueType>::shiftProbability(storm::storage::sparse::state_type const& fromState, storm::storage::sparse::state_type const& toState, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator) {
+        template<typename ValueType, typename StateType>
+        void Distribution<ValueType, StateType>::shiftProbability(StateType const& fromState, StateType const& toState, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator) {
             removeProbability(fromState, probability, comparator);
             addProbability(toState, probability);
         }
         
-        template<typename ValueType>
-        typename Distribution<ValueType>::iterator Distribution<ValueType>::begin() {
+        template<typename ValueType, typename StateType>
+        typename Distribution<ValueType, StateType>::iterator Distribution<ValueType, StateType>::begin() {
             return this->distribution.begin();
         }
 
-        template<typename ValueType>
-        typename Distribution<ValueType>::const_iterator Distribution<ValueType>::begin() const {
+        template<typename ValueType, typename StateType>
+        typename Distribution<ValueType, StateType>::const_iterator Distribution<ValueType, StateType>::begin() const {
             return this->distribution.begin();
         }
         
-        template<typename ValueType>
-        typename Distribution<ValueType>::iterator Distribution<ValueType>::end() {
+        template<typename ValueType, typename StateType>
+        typename Distribution<ValueType, StateType>::const_iterator Distribution<ValueType, StateType>::cbegin() const {
+            return this->begin();
+        }
+        
+        template<typename ValueType, typename StateType>
+        typename Distribution<ValueType, StateType>::iterator Distribution<ValueType, StateType>::end() {
             return this->distribution.end();
         }
         
-        template<typename ValueType>
-        typename Distribution<ValueType>::const_iterator Distribution<ValueType>::end() const {
+        template<typename ValueType, typename StateType>
+        typename Distribution<ValueType, StateType>::const_iterator Distribution<ValueType, StateType>::end() const {
             return this->distribution.end();
         }
+
+        template<typename ValueType, typename StateType>
+        typename Distribution<ValueType, StateType>::const_iterator Distribution<ValueType, StateType>::cend() const {
+            return this->end();
+        }
         
-        template<typename ValueType>
-        void Distribution<ValueType>::scale(storm::storage::sparse::state_type const& state) {
+        template<typename ValueType, typename StateType>
+        void Distribution<ValueType, StateType>::scale(StateType const& state) {
             auto probabilityIterator = this->distribution.find(state);
             if (probabilityIterator != this->distribution.end()) {
                 ValueType scaleValue = storm::utility::one<ValueType>() / probabilityIterator->second;
@@ -101,13 +111,13 @@ namespace storm {
             }
         }
                 
-        template<typename ValueType>
-        std::size_t Distribution<ValueType>::size() const {
+        template<typename ValueType, typename StateType>
+        std::size_t Distribution<ValueType, StateType>::size() const {
             return this->distribution.size();
         }
         
-        template<typename ValueType>
-        std::ostream& operator<<(std::ostream& out, Distribution<ValueType> const& distribution) {
+        template<typename ValueType, typename StateType>
+        std::ostream& operator<<(std::ostream& out, Distribution<ValueType, StateType> const& distribution) {
             out << "{";
             for (auto const& entry : distribution) {
                 out << "[" << entry.second << ": " << entry.first << "], ";
@@ -117,8 +127,8 @@ namespace storm {
             return out;
         }
         
-        template<typename ValueType>
-        bool Distribution<ValueType>::less(Distribution<ValueType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const {
+        template<typename ValueType, typename StateType>
+        bool Distribution<ValueType, StateType>::less(Distribution<ValueType, StateType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const {
             if (this->size() != other.size()) {
                 return this->size() < other.size();
             }
diff --git a/src/storage/Distribution.h b/src/storage/Distribution.h
index 9d3276941..ba61f0fbd 100644
--- a/src/storage/Distribution.h
+++ b/src/storage/Distribution.h
@@ -17,10 +17,10 @@ namespace storm {
     
     namespace storage {
         
-        template<typename ValueType>
+        template<typename ValueType, typename StateType = uint32_t>
         class Distribution {
         public:
-            typedef boost::container::flat_map<storm::storage::sparse::state_type, ValueType> container_type;
+            typedef boost::container::flat_map<StateType, ValueType> container_type;
             typedef typename container_type::iterator iterator;
             typedef typename container_type::const_iterator const_iterator;
             
@@ -43,7 +43,7 @@ namespace storm {
              * @param other The distribution with which the current distribution is to be compared.
              * @return True iff the two distributions are equal.
              */
-            bool equals(Distribution<ValueType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>()) const;
+            bool equals(Distribution<ValueType, StateType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>()) const;
             
             /*!
              * Assigns the given state the given probability under this distribution.
@@ -51,7 +51,7 @@ namespace storm {
              * @param state The state to which to assign the probability.
              * @param probability The probability to assign.
              */
-            void addProbability(storm::storage::sparse::state_type const& state, ValueType const& probability);
+            void addProbability(StateType const& state, ValueType const& probability);
             
             /*!
              * Removes the given probability mass of going to the given state.
@@ -61,7 +61,7 @@ namespace storm {
              * @param comparator A comparator that is used to determine if the remaining probability is zero. If so, the
              * entry is removed.
              */
-            void removeProbability(storm::storage::sparse::state_type const& state, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>());
+            void removeProbability(StateType const& state, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>());
             
             /*!
              * Removes the probability mass from one state and adds it to another.
@@ -72,8 +72,8 @@ namespace storm {
              * @param comparator A comparator that is used to determine if the remaining probability is zero. If so, the
              * entry is removed.
              */
-            void shiftProbability(storm::storage::sparse::state_type const& fromState, storm::storage::sparse::state_type const& toState, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>());
-            
+            void shiftProbability(StateType const& fromState, StateType const& toState, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>());
+                        
             /*!
              * Retrieves an iterator to the elements in this distribution.
              *
@@ -88,6 +88,13 @@ namespace storm {
              */
             const_iterator begin() const;
             
+            /*!
+             * Retrieves an iterator to the elements in this distribution.
+             *
+             * @return The iterator to the elements in this distribution.
+             */
+            const_iterator cbegin() const;
+            
             /*!
              * Retrieves an iterator past the elements in this distribution.
              *
@@ -102,6 +109,13 @@ namespace storm {
              */
             const_iterator end() const;
             
+            /*!
+             * Retrieves an iterator past the elements in this distribution.
+             *
+             * @return The iterator past the elements in this distribution.
+             */
+            const_iterator cend() const;
+            
             /*!
              * Scales the distribution by multiplying all the probabilities with 1/p where p is the probability of moving
              * to the given state and sets the probability of moving to the given state to zero. If the probability is
@@ -109,22 +123,22 @@ namespace storm {
              *
              * @param state The state whose associated probability is used to scale the distribution.
              */
-            void scale(storm::storage::sparse::state_type const& state);
+            void scale(StateType const& state);
             
             /*!
              * Retrieves the size of the distribution, i.e. the size of the support set.
              */
             std::size_t size() const;
             
-            bool less(Distribution<ValueType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const;
+            bool less(Distribution<ValueType, StateType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const;
             
         private:
             // A list of states and the probabilities that are assigned to them.
             container_type distribution;
         };
         
-        template<typename ValueType>
-        std::ostream& operator<<(std::ostream& out, Distribution<ValueType> const& distribution);
+        template<typename ValueType, typename StateType = uint32_t>
+        std::ostream& operator<<(std::ostream& out, Distribution<ValueType, StateType> const& distribution);
     }
 }
 
diff --git a/src/storage/SparseMatrix.cpp b/src/storage/SparseMatrix.cpp
index 7db3a0beb..69f12b696 100644
--- a/src/storage/SparseMatrix.cpp
+++ b/src/storage/SparseMatrix.cpp
@@ -80,20 +80,23 @@ namespace storm {
             if (initialEntryCountSet) {
                 columnsAndValues.reserve(initialEntryCount);
             }
-            if (initialRowGroupCountSet) {
-                rowGroupIndices.reserve(initialRowGroupCount + 1);
+            if (hasCustomRowGrouping) {
+                rowGroupIndices = std::vector<index_type>();
+            }
+            if (initialRowGroupCountSet && hasCustomRowGrouping) {
+                rowGroupIndices.get().reserve(initialRowGroupCount + 1);
             }
             rowIndications.push_back(0);
         }
         
         template<typename ValueType>
-        SparseMatrixBuilder<ValueType>::SparseMatrixBuilder(SparseMatrix<ValueType>&& matrix) :  initialRowCountSet(false), initialRowCount(0), initialColumnCountSet(false), initialColumnCount(0), initialEntryCountSet(false), initialEntryCount(0), forceInitialDimensions(false), hasCustomRowGrouping(matrix.nontrivialRowGrouping), initialRowGroupCountSet(false), initialRowGroupCount(0), rowGroupIndices(), columnsAndValues(std::move(matrix.columnsAndValues)), rowIndications(std::move(matrix.rowIndications)), currentEntryCount(matrix.entryCount), lastRow(matrix.rowCount - 1), lastColumn(columnsAndValues.back().getColumn()), highestColumn(matrix.getColumnCount() - 1), currentRowGroup() {
+        SparseMatrixBuilder<ValueType>::SparseMatrixBuilder(SparseMatrix<ValueType>&& matrix) :  initialRowCountSet(false), initialRowCount(0), initialColumnCountSet(false), initialColumnCount(0), initialEntryCountSet(false), initialEntryCount(0), forceInitialDimensions(false), hasCustomRowGrouping(!matrix.trivialRowGrouping), initialRowGroupCountSet(false), initialRowGroupCount(0), rowGroupIndices(), columnsAndValues(std::move(matrix.columnsAndValues)), rowIndications(std::move(matrix.rowIndications)), currentEntryCount(matrix.entryCount), lastRow(matrix.rowCount - 1), lastColumn(columnsAndValues.back().getColumn()), highestColumn(matrix.getColumnCount() - 1), currentRowGroup() {
             
             // If the matrix has a custom row grouping, we move it and remove the last element to make it 'open' again.
             if (hasCustomRowGrouping) {
                 rowGroupIndices = std::move(matrix.rowGroupIndices);
-                rowGroupIndices.pop_back();
-                currentRowGroup = rowGroupIndices.size() - 1;
+                rowGroupIndices.get().pop_back();
+                currentRowGroup = rowGroupIndices.get().size() - 1;
             }
             
             // Likewise, we need to 'open' the row indications again.
@@ -141,14 +144,14 @@ namespace storm {
         void SparseMatrixBuilder<ValueType>::newRowGroup(index_type startingRow) {
             STORM_LOG_THROW(hasCustomRowGrouping, storm::exceptions::InvalidStateException, "Matrix was not created to have a custom row grouping.");
             STORM_LOG_THROW(startingRow >= lastRow, storm::exceptions::InvalidStateException, "Illegal row group with negative size.");
-            rowGroupIndices.push_back(startingRow);
+            rowGroupIndices.get().push_back(startingRow);
             ++currentRowGroup;
-
+            
             // Close all rows from the most recent one to the starting row.
             for (index_type i = lastRow + 1; i <= startingRow; ++i) {
                 rowIndications.push_back(currentEntryCount);
             }
-
+            
             // Reset the most recently seen row/column to allow for proper insertion of the following elements.
             lastRow = startingRow;
             lastColumn = 0;
@@ -162,7 +165,7 @@ namespace storm {
                 rowCount = std::max(rowCount, initialRowCount);
             }
             rowCount = std::max(rowCount, overriddenRowCount);
-
+            
             // If the current row count was overridden, we may need to add empty rows.
             for (index_type i = lastRow + 1; i < rowCount; ++i) {
                 rowIndications.push_back(currentEntryCount);
@@ -186,11 +189,7 @@ namespace storm {
             }
             
             // Check whether row groups are missing some entries.
-            if (!hasCustomRowGrouping) {
-                for (index_type i = 0; i <= rowCount; ++i) {
-                    rowGroupIndices.push_back(i);
-                }
-            } else {
+            if (hasCustomRowGrouping) {
                 uint_fast64_t rowGroupCount = currentRowGroup;
                 if (initialRowGroupCountSet && forceInitialDimensions) {
                     STORM_LOG_THROW(rowGroupCount <= initialRowGroupCount, storm::exceptions::InvalidStateException, "Expected not more than " << initialRowGroupCount << " row groups, but got " << rowGroupCount << ".");
@@ -199,11 +198,11 @@ namespace storm {
                 rowGroupCount = std::max(rowGroupCount, overriddenRowGroupCount);
                 
                 for (index_type i = currentRowGroup; i <= rowGroupCount; ++i) {
-                    rowGroupIndices.push_back(rowCount);
+                    rowGroupIndices.get().push_back(rowCount);
                 }
             }
-
-            return SparseMatrix<ValueType>(columnCount, std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), hasCustomRowGrouping);
+            
+            return SparseMatrix<ValueType>(columnCount, std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices));
         }
         
         template<typename ValueType>
@@ -283,6 +282,44 @@ namespace storm {
             }
         }
         
+        template<typename ValueType>
+        bool SparseMatrixBuilder<ValueType>::replaceColumns(std::vector<index_type> const& replacements, index_type offset) {
+            bool matrixChanged = false;
+            
+            // Walk through all rows.
+            for (index_type row = 0; row < rowIndications.size(); ++row) {
+                bool rowChanged = false;
+                index_type rowEnd = row < rowIndications.size()-1 ? rowIndications[row+1] : columnsAndValues.size();
+                
+                for (auto it = columnsAndValues.begin() + rowIndications[row], ite = columnsAndValues.begin() + rowEnd; it != ite; ++it) {
+                    if (it->getColumn() >= offset && it->getColumn() != replacements[it->getColumn() - offset]) {
+                        it->setColumn(replacements[it->getColumn() - offset]);
+                        rowChanged = true;
+                    }
+                    // Update highest column in a way that only works if the highest appearing index does not become
+                    // lower during performing the replacement.
+                    highestColumn = std::max(highestColumn, it->getColumn());
+                }
+                
+                if (rowChanged) {
+                    matrixChanged = true;
+                    
+                    // Sort the row.
+                    std::sort(columnsAndValues.begin() + rowIndications[row], columnsAndValues.begin() + rowEnd,
+                              [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) {
+                                  return a.getColumn() < b.getColumn();
+                              });
+                    // Assert no equal elements
+                    STORM_LOG_ASSERT(std::is_sorted(columnsAndValues.begin() + rowIndications[row], columnsAndValues.begin() + rowEnd,
+                                                    [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) {
+                                                        return a.getColumn() <= b.getColumn();
+                                                    }), "Must not have different elements with the same column in a row.");
+                }
+            }
+            
+            return matrixChanged;
+        }
+        
         template<typename ValueType>
         SparseMatrix<ValueType>::rows::rows(iterator begin, index_type entryCount) : beginIterator(begin), entryCount(entryCount) {
             // Intentionally left empty.
@@ -324,12 +361,12 @@ namespace storm {
         }
         
         template<typename ValueType>
-        SparseMatrix<ValueType>::SparseMatrix() : rowCount(0), columnCount(0), entryCount(0), nonzeroEntryCount(0), columnsAndValues(), rowIndications(), nontrivialRowGrouping(false), rowGroupIndices() {
+        SparseMatrix<ValueType>::SparseMatrix() : rowCount(0), columnCount(0), entryCount(0), nonzeroEntryCount(0), columnsAndValues(), rowIndications(), rowGroupIndices() {
             // Intentionally left empty.
         }
         
         template<typename ValueType>
-        SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType> const& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(other.columnsAndValues), rowIndications(other.rowIndications), nontrivialRowGrouping(other.nontrivialRowGrouping), rowGroupIndices(other.rowGroupIndices) {
+        SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType> const& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(other.columnsAndValues), rowIndications(other.rowIndications), trivialRowGrouping(other.trivialRowGrouping), rowGroupIndices(other.rowGroupIndices) {
             // Intentionally left empty.
         }
         
@@ -341,7 +378,7 @@ namespace storm {
         }
         
         template<typename ValueType>
-        SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType>&& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(std::move(other.columnsAndValues)), rowIndications(std::move(other.rowIndications)), nontrivialRowGrouping(other.nontrivialRowGrouping), rowGroupIndices(std::move(other.rowGroupIndices)) {
+        SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType>&& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(std::move(other.columnsAndValues)), rowIndications(std::move(other.rowIndications)), trivialRowGrouping(other.trivialRowGrouping), rowGroupIndices(std::move(other.rowGroupIndices)) {
             // Now update the source matrix
             other.rowCount = 0;
             other.columnCount = 0;
@@ -349,12 +386,12 @@ namespace storm {
         }
         
         template<typename ValueType>
-        SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type> const& rowIndications, std::vector<MatrixEntry<index_type, ValueType>> const& columnsAndValues, std::vector<index_type> const& rowGroupIndices, bool nontrivialRowGrouping) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(columnsAndValues), rowIndications(rowIndications), nontrivialRowGrouping(nontrivialRowGrouping), rowGroupIndices(rowGroupIndices) {
+        SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type> const& rowIndications, std::vector<MatrixEntry<index_type, ValueType>> const& columnsAndValues, boost::optional<std::vector<index_type>> const& rowGroupIndices) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(columnsAndValues), rowIndications(rowIndications), trivialRowGrouping(!rowGroupIndices), rowGroupIndices(rowGroupIndices) {
             this->updateNonzeroEntryCount();
         }
         
         template<typename ValueType>
-        SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications, std::vector<MatrixEntry<index_type, ValueType>>&& columnsAndValues, std::vector<index_type>&& rowGroupIndices, bool nontrivialRowGrouping) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(std::move(columnsAndValues)), rowIndications(std::move(rowIndications)), nontrivialRowGrouping(nontrivialRowGrouping), rowGroupIndices(std::move(rowGroupIndices)) {
+        SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications, std::vector<MatrixEntry<index_type, ValueType>>&& columnsAndValues, boost::optional<std::vector<index_type>>&& rowGroupIndices) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(std::move(columnsAndValues)), rowIndications(std::move(rowIndications)), trivialRowGrouping(!rowGroupIndices), rowGroupIndices(std::move(rowGroupIndices)) {
             this->updateNonzeroEntryCount();
         }
         
@@ -370,7 +407,7 @@ namespace storm {
                 columnsAndValues = other.columnsAndValues;
                 rowIndications = other.rowIndications;
                 rowGroupIndices = other.rowGroupIndices;
-                nontrivialRowGrouping = other.nontrivialRowGrouping;
+                trivialRowGrouping = other.trivialRowGrouping;
             }
             
             return *this;
@@ -388,7 +425,7 @@ namespace storm {
                 columnsAndValues = std::move(other.columnsAndValues);
                 rowIndications = std::move(other.rowIndications);
                 rowGroupIndices = std::move(other.rowGroupIndices);
-                nontrivialRowGrouping = other.nontrivialRowGrouping;
+                trivialRowGrouping = other.trivialRowGrouping;
             }
             
             return *this;
@@ -410,7 +447,11 @@ namespace storm {
             if (!equalityResult) {
                 return false;
             }
-            equalityResult &= this->getRowGroupIndices() == other.getRowGroupIndices();
+            if (!this->hasTrivialRowGrouping() && !other.hasTrivialRowGrouping()) {
+                equalityResult &= this->getRowGroupIndices() == other.getRowGroupIndices();
+            } else {
+                equalityResult &= this->hasTrivialRowGrouping() && other.hasTrivialRowGrouping();
+            }
             if (!equalityResult) {
                 return false;
             }
@@ -462,8 +503,12 @@ namespace storm {
         template<typename T>
         uint_fast64_t SparseMatrix<T>::getRowGroupEntryCount(uint_fast64_t const group) const {
             uint_fast64_t result = 0;
-            for (uint_fast64_t row = this->getRowGroupIndices()[group]; row < this->getRowGroupIndices()[group + 1]; ++row) {
-                result += (this->rowIndications[row + 1] - this->rowIndications[row]);
+            if (!this->hasTrivialRowGrouping()) {
+                for (uint_fast64_t row = this->getRowGroupIndices()[group]; row < this->getRowGroupIndices()[group + 1]; ++row) {
+                    result += (this->rowIndications[row + 1] - this->rowIndications[row]);
+                }
+            } else {
+                result += (this->rowIndications[group + 1] - this->rowIndications[group]);
             }
             return result;
         }
@@ -502,7 +547,11 @@ namespace storm {
         
         template<typename ValueType>
         typename SparseMatrix<ValueType>::index_type SparseMatrix<ValueType>::getRowGroupCount() const {
-            return rowGroupIndices.size() - 1;
+            if (!this->hasTrivialRowGrouping()) {
+                return rowGroupIndices.get().size() - 1;
+            } else {
+                return rowCount;
+            }
         }
         
         template<typename ValueType>
@@ -512,7 +561,15 @@ namespace storm {
         
         template<typename ValueType>
         std::vector<typename SparseMatrix<ValueType>::index_type> const& SparseMatrix<ValueType>::getRowGroupIndices() const {
-            return rowGroupIndices;
+            // If there is no current row grouping, we need to create it.
+            if (!this->rowGroupIndices) {
+                STORM_LOG_ASSERT(trivialRowGrouping, "Only trivial row-groupings can be constructed on-the-fly.");
+                this->rowGroupIndices = std::vector<index_type>(this->getRowCount() + 1);
+                for (uint_fast64_t group = 0; group <= this->getRowCount(); ++group) {
+                    this->rowGroupIndices.get()[group] = group;
+                }
+            }
+            return rowGroupIndices.get();
         }
 
         template<typename ValueType>
@@ -524,9 +581,15 @@ namespace storm {
         
         template<typename ValueType>
         void SparseMatrix<ValueType>::makeRowGroupsAbsorbing(storm::storage::BitVector const& rowGroupConstraint) {
-            for (auto rowGroup : rowGroupConstraint) {
-                for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) {
-                    makeRowDirac(row, rowGroup);
+            if (!this->hasTrivialRowGrouping()) {
+                for (auto rowGroup : rowGroupConstraint) {
+                    for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) {
+                        makeRowDirac(row, rowGroup);
+                    }
+                }
+            } else {
+                for (auto rowGroup : rowGroupConstraint) {
+                    makeRowDirac(rowGroup, rowGroup);
                 }
             }
         }
@@ -579,9 +642,15 @@ namespace storm {
         std::vector<ValueType> SparseMatrix<ValueType>::getConstrainedRowGroupSumVector(storm::storage::BitVector const& rowGroupConstraint, storm::storage::BitVector const& columnConstraint) const {
             std::vector<ValueType> result;
             result.reserve(rowGroupConstraint.getNumberOfSetBits());
-            for (auto rowGroup : rowGroupConstraint) {
-                for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) {
-                    result.push_back(getConstrainedRowSum(row, columnConstraint));
+            if (!this->hasTrivialRowGrouping()) {
+                for (auto rowGroup : rowGroupConstraint) {
+                    for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) {
+                        result.push_back(getConstrainedRowSum(row, columnConstraint));
+                    }
+                }
+            } else {
+                for (auto rowGroup : rowGroupConstraint) {
+                    result.push_back(getConstrainedRowSum(rowGroup, columnConstraint));
                 }
             }
             return result;
@@ -599,25 +668,30 @@ namespace storm {
                     *it = i;
                 }
                 auto res = getSubmatrix(rowConstraint, columnConstraint, fakeRowGroupIndices, insertDiagonalElements);
-
-                // Create a new row grouping that reflects the new sizes of the row groups.
-                std::vector<uint_fast64_t> newRowGroupIndices;
-                newRowGroupIndices.push_back(0);
-                auto selectedRowIt = rowConstraint.begin();
-
-                // For this, we need to count how many rows were preserved in every group.
-                for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) {
-                    uint_fast64_t newRowCount = 0;
-                    while (*selectedRowIt < this->getRowGroupIndices()[group + 1]) {
-                        ++selectedRowIt;
-                        ++newRowCount;
-                    }
-                    if (newRowCount > 0) {
-                        newRowGroupIndices.push_back(newRowGroupIndices.back() + newRowCount);
+                
+                // Create a new row grouping that reflects the new sizes of the row groups if the current matrix has a
+                // non trivial row-grouping.
+                if (!this->hasTrivialRowGrouping()) {
+                    std::vector<uint_fast64_t> newRowGroupIndices;
+                    newRowGroupIndices.push_back(0);
+                    auto selectedRowIt = rowConstraint.begin();
+                    
+                    // For this, we need to count how many rows were preserved in every group.
+                    for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) {
+                        uint_fast64_t newRowCount = 0;
+                        while (*selectedRowIt < this->getRowGroupIndices()[group + 1]) {
+                            ++selectedRowIt;
+                            ++newRowCount;
+                        }
+                        if (newRowCount > 0) {
+                            newRowGroupIndices.push_back(newRowGroupIndices.back() + newRowCount);
+                        }
                     }
+                    
+                    res.trivialRowGrouping = false;
+                    res.rowGroupIndices = newRowGroupIndices;
                 }
                 
-                res.rowGroupIndices = newRowGroupIndices;
                 return res;
             }
         }
@@ -664,13 +738,13 @@ namespace storm {
             }
             
             // Create and initialize resulting matrix.
-            SparseMatrixBuilder<ValueType> matrixBuilder(subRows, submatrixColumnCount, subEntries, true, this->hasNontrivialRowGrouping());
+            SparseMatrixBuilder<ValueType> matrixBuilder(subRows, submatrixColumnCount, subEntries, true, !this->hasTrivialRowGrouping());
             
             // Copy over selected entries.
             rowGroupCount = 0;
             index_type rowCount = 0;
             for (auto index : rowGroupConstraint) {
-                if (this->hasNontrivialRowGrouping()) {
+                if (!this->hasTrivialRowGrouping()) {
                     matrixBuilder.newRowGroup(rowCount);
                 }
                 for (index_type i = rowGroupIndices[index]; i < rowGroupIndices[index + 1]; ++i) {
@@ -706,12 +780,12 @@ namespace storm {
         template<typename ValueType>
         SparseMatrix<ValueType> SparseMatrix<ValueType>::restrictRows(storm::storage::BitVector const& rowsToKeep) const {
             // For now, we use the expensive call to submatrix.
-            assert(rowsToKeep.size() == getRowCount());
-            assert(rowsToKeep.getNumberOfSetBits() >= getRowGroupCount());
+            STORM_LOG_ASSERT(rowsToKeep.size() == this->getRowCount(), "Dimensions mismatch.");
+            STORM_LOG_ASSERT(rowsToKeep.getNumberOfSetBits() >= this->getRowGroupCount(), "Invalid dimensions.");
             SparseMatrix<ValueType> res(getSubmatrix(false, rowsToKeep, storm::storage::BitVector(getColumnCount(), true), false));
-            assert(res.getRowCount() == rowsToKeep.getNumberOfSetBits());
-            assert(res.getColumnCount() == getColumnCount());
-            assert(getRowGroupCount() == res.getRowGroupCount());
+            STORM_LOG_ASSERT(res.getRowCount() == rowsToKeep.getNumberOfSetBits(), "Invalid dimensions");
+            STORM_LOG_ASSERT(res.getColumnCount() == this->getColumnCount(), "Invalid dimensions");
+            STORM_LOG_ASSERT(this->getRowGroupCount() == res.getRowGroupCount(), "Invalid dimensions");
             return res;
         }
         
@@ -722,7 +796,7 @@ namespace storm {
             index_type subEntries = 0;
             for (index_type rowGroupIndex = 0, rowGroupIndexEnd = rowGroupToRowIndexMapping.size(); rowGroupIndex < rowGroupIndexEnd; ++rowGroupIndex) {
                 // Determine which row we need to select from the current row group.
-                index_type rowToCopy = rowGroupIndices[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex];
+                index_type rowToCopy = this->getRowGroupIndices()[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex];
                 
                 // Iterate through that row and count the number of slots we have to reserve for copying.
                 bool foundDiagonalElement = false;
@@ -738,12 +812,12 @@ namespace storm {
             }
             
             // Now create the matrix to be returned with the appropriate size.
-            SparseMatrixBuilder<ValueType> matrixBuilder(rowGroupIndices.size() - 1, columnCount, subEntries);
+            SparseMatrixBuilder<ValueType> matrixBuilder(rowGroupIndices.get().size() - 1, columnCount, subEntries);
             
             // Copy over the selected lines from the source matrix.
             for (index_type rowGroupIndex = 0, rowGroupIndexEnd = rowGroupToRowIndexMapping.size(); rowGroupIndex < rowGroupIndexEnd; ++rowGroupIndex) {
                 // Determine which row we need to select from the current row group.
-                index_type rowToCopy = rowGroupIndices[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex];
+                index_type rowToCopy = this->getRowGroupIndices()[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex];
                 
                 // Iterate through that row and copy the entries. This also inserts a zero element on the diagonal if
                 // there is no entry yet.
@@ -810,12 +884,7 @@ namespace storm {
                 }
             }
             
-            std::vector<index_type> rowGroupIndices(rowCount + 1);
-            for (index_type i = 0; i <= rowCount; ++i) {
-                rowGroupIndices[i] = i;
-            }
-            
-            storm::storage::SparseMatrix<ValueType> transposedMatrix(columnCount, std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), false);
+            storm::storage::SparseMatrix<ValueType> transposedMatrix(columnCount, std::move(rowIndications), std::move(columnsAndValues), boost::none);
             
             return transposedMatrix;
         }
@@ -1065,50 +1134,66 @@ namespace storm {
         
         template<typename ValueType>
         typename SparseMatrix<ValueType>::const_rows SparseMatrix<ValueType>::getRows(index_type startRow, index_type endRow) const {
-            return const_rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow + 1] - this->rowIndications[startRow]);
+            return const_rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow] - this->rowIndications[startRow]);
         }
         
         template<typename ValueType>
         typename SparseMatrix<ValueType>::rows SparseMatrix<ValueType>::getRows(index_type startRow, index_type endRow) {
-            return rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow + 1] - this->rowIndications[startRow]);
+            return rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow] - this->rowIndications[startRow]);
         }
         
         template<typename ValueType>
         typename SparseMatrix<ValueType>::const_rows SparseMatrix<ValueType>::getRow(index_type row) const {
-            return getRows(row, row);
+            return getRows(row, row + 1);
         }
         
         template<typename ValueType>
         typename SparseMatrix<ValueType>::rows SparseMatrix<ValueType>::getRow(index_type row) {
-            return getRows(row, row);
+            return getRows(row, row + 1);
         }
         
         template<typename ValueType>
         typename SparseMatrix<ValueType>::const_rows SparseMatrix<ValueType>::getRow(index_type rowGroup, index_type offset) const {
-            assert(rowGroup < this->getRowGroupCount());
-            assert(offset < this->getRowGroupEntryCount(rowGroup));
-            return getRow(rowGroupIndices[rowGroup] + offset);
+            STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds.");
+            STORM_LOG_ASSERT(offset < this->getRowGroupEntryCount(rowGroup), "Row offset in row-group is out-of-bounds.");
+            if (!this->hasTrivialRowGrouping()) {
+                return getRow(this->getRowGroupIndices()[rowGroup] + offset);
+            } else {
+                return getRow(this->getRowGroupIndices()[rowGroup] + offset);
+            }
         }
         
-        
         template<typename ValueType>
         typename SparseMatrix<ValueType>::rows SparseMatrix<ValueType>::getRow(index_type rowGroup, index_type offset) {
-            assert(rowGroup < this->getRowGroupCount());
-            assert(offset < this->getRowGroupEntryCount(rowGroup));
-            return getRow(rowGroupIndices[rowGroup] + offset);
+            STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds.");
+            STORM_LOG_ASSERT(offset < this->getRowGroupEntryCount(rowGroup), "Row offset in row-group is out-of-bounds.");
+            if (!this->hasTrivialRowGrouping()) {
+                return getRow(this->getRowGroupIndices()[rowGroup] + offset);
+            } else {
+                STORM_LOG_ASSERT(offset == 0, "Invalid offset.");
+                return getRow(rowGroup + offset);
+            }
         }
         
         
         template<typename ValueType>
         typename SparseMatrix<ValueType>::const_rows SparseMatrix<ValueType>::getRowGroup(index_type rowGroup) const {
-            assert(rowGroup < this->getRowGroupCount());
-            return getRows(rowGroupIndices[rowGroup], rowGroupIndices[rowGroup + 1] - 1);
+            STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds.");
+            if (!this->hasTrivialRowGrouping()) {
+                return getRows(this->getRowGroupIndices()[rowGroup], this->getRowGroupIndices()[rowGroup + 1]);
+            } else {
+                return getRows(rowGroup, rowGroup + 1);
+            }
         }
         
         template<typename ValueType>
         typename SparseMatrix<ValueType>::rows SparseMatrix<ValueType>::getRowGroup(index_type rowGroup) {
-            assert(rowGroup < this->getRowGroupCount());
-            return getRows(rowGroupIndices[rowGroup], rowGroupIndices[rowGroup + 1] - 1);
+            STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds.");
+            if (!this->hasTrivialRowGrouping()) {
+                return getRows(this->getRowGroupIndices()[rowGroup], this->getRowGroupIndices()[rowGroup + 1]);
+            } else {
+                return getRows(rowGroup, rowGroup + 1);
+            }
         }
         
         template<typename ValueType>
@@ -1142,8 +1227,8 @@ namespace storm {
         }
         
         template<typename ValueType>
-        bool SparseMatrix<ValueType>::hasNontrivialRowGrouping() const {
-            return nontrivialRowGrouping;
+        bool SparseMatrix<ValueType>::hasTrivialRowGrouping() const {
+            return trivialRowGrouping;
         }
         
         template<typename ValueType>
@@ -1172,6 +1257,9 @@ namespace storm {
             // Check for matching sizes.
             if (this->getRowCount() != matrix.getRowCount()) return false;
             if (this->getColumnCount() != matrix.getColumnCount()) return false;
+            if (this->hasTrivialRowGrouping() && !matrix.hasTrivialRowGrouping()) return false;
+            if (!this->hasTrivialRowGrouping() && matrix.hasTrivialRowGrouping()) return false;
+            if (!this->hasTrivialRowGrouping() && !matrix.hasTrivialRowGrouping() && this->getRowGroupIndices() != matrix.getRowGroupIndices()) return false;
             if (this->getRowGroupIndices() != matrix.getRowGroupIndices()) return false;
             
             // Check the subset property for all rows individually.
@@ -1203,7 +1291,10 @@ namespace storm {
             // Iterate over all row groups.
             for (typename SparseMatrix<ValueType>::index_type group = 0; group < matrix.getRowGroupCount(); ++group) {
                 out << "\t---- group " << group << "/" << (matrix.getRowGroupCount() - 1) << " ---- " << std::endl;
-                for (typename SparseMatrix<ValueType>::index_type i = matrix.getRowGroupIndices()[group]; i < matrix.getRowGroupIndices()[group + 1]; ++i) {
+                typename SparseMatrix<ValueType>::index_type start = matrix.hasTrivialRowGrouping() ? group : matrix.getRowGroupIndices()[group];
+                typename SparseMatrix<ValueType>::index_type end = matrix.hasTrivialRowGrouping() ? group + 1 : matrix.getRowGroupIndices()[group + 1];
+                
+                for (typename SparseMatrix<ValueType>::index_type i = start; i < end; ++i) {
                     typename SparseMatrix<ValueType>::index_type nextIndex = matrix.rowIndications[i];
                     
                     // Print the actual row.
@@ -1239,7 +1330,7 @@ namespace storm {
                 assert(this->getRowGroupSize(group) == 1);
                 for (typename SparseMatrix<ValueType>::index_type i = this->getRowGroupIndices()[group]; i < this->getRowGroupIndices()[group + 1]; ++i) {
                     typename SparseMatrix<ValueType>::index_type nextIndex = this->rowIndications[i];
-
+                    
                     // Print the actual row.
                     out << i << "\t(";
                     typename SparseMatrix<ValueType>::index_type currentRealIndex = 0;
@@ -1266,7 +1357,9 @@ namespace storm {
             boost::hash_combine(result, this->getEntryCount());
             boost::hash_combine(result, boost::hash_range(columnsAndValues.begin(), columnsAndValues.end()));
             boost::hash_combine(result, boost::hash_range(rowIndications.begin(), rowIndications.end()));
-            boost::hash_combine(result, boost::hash_range(rowGroupIndices.begin(), rowGroupIndices.end()));
+            if (!this->hasTrivialRowGrouping()) {
+                boost::hash_combine(result, boost::hash_range(rowGroupIndices.get().begin(), rowGroupIndices.get().end()));
+            }
             
             return result;
         }
@@ -1293,7 +1386,7 @@ namespace storm {
         template std::ostream& operator<<(std::ostream& out, SparseMatrix<double> const& matrix);
         template std::vector<double> SparseMatrix<double>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<double> const& otherMatrix) const;
         template bool SparseMatrix<double>::isSubmatrixOf(SparseMatrix<double> const& matrix) const;
-
+        
         // float
         template class MatrixEntry<typename SparseMatrix<float>::index_type, float>;
         template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<float>::index_type, float> const& entry);
@@ -1302,7 +1395,7 @@ namespace storm {
         template std::ostream& operator<<(std::ostream& out, SparseMatrix<float> const& matrix);
         template std::vector<float> SparseMatrix<float>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<float> const& otherMatrix) const;
         template bool SparseMatrix<float>::isSubmatrixOf(SparseMatrix<float> const& matrix) const;
-
+        
         // int
         template class MatrixEntry<typename SparseMatrix<int>::index_type, int>;
         template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<int>::index_type, int> const& entry);
@@ -1310,7 +1403,7 @@ namespace storm {
         template class SparseMatrix<int>;
         template std::ostream& operator<<(std::ostream& out, SparseMatrix<int> const& matrix);
         template bool SparseMatrix<int>::isSubmatrixOf(SparseMatrix<int> const& matrix) const;
-
+        
         // state_type
         template class MatrixEntry<typename SparseMatrix<storm::storage::sparse::state_type>::index_type, storm::storage::sparse::state_type>;
         template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<storm::storage::sparse::state_type>::index_type, storm::storage::sparse::state_type> const& entry);
@@ -1318,7 +1411,7 @@ namespace storm {
         template class SparseMatrix<storm::storage::sparse::state_type>;
         template std::ostream& operator<<(std::ostream& out, SparseMatrix<storm::storage::sparse::state_type> const& matrix);
         template bool SparseMatrix<int>::isSubmatrixOf(SparseMatrix<storm::storage::sparse::state_type> const& matrix) const;
-
+        
 #ifdef STORM_HAVE_CARL
         // Rat Function
         template class MatrixEntry<typename SparseMatrix<CarlRationalNumber>::index_type, CarlRationalNumber>;
@@ -1340,7 +1433,7 @@ namespace storm {
         template std::vector<storm::RationalFunction> SparseMatrix<float>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<storm::RationalFunction> const& otherMatrix) const;
         template std::vector<storm::RationalFunction> SparseMatrix<int>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<storm::RationalFunction> const& otherMatrix) const;
         template bool SparseMatrix<storm::RationalFunction>::isSubmatrixOf(SparseMatrix<storm::RationalFunction> const& matrix) const;
-
+        
         // Intervals
         template std::vector<storm::Interval> SparseMatrix<double>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<storm::Interval> const& otherMatrix) const;
         template class MatrixEntry<typename SparseMatrix<Interval>::index_type, Interval>;
@@ -1350,7 +1443,7 @@ namespace storm {
         template std::ostream& operator<<(std::ostream& out, SparseMatrix<Interval> const& matrix);
         template std::vector<storm::Interval> SparseMatrix<Interval>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<storm::Interval> const& otherMatrix) const;
         template bool SparseMatrix<storm::Interval>::isSubmatrixOf(SparseMatrix<storm::Interval> const& matrix) const;
-
+        
         template bool SparseMatrix<storm::Interval>::isSubmatrixOf(SparseMatrix<double> const& matrix) const;
 #endif
         
diff --git a/src/storage/SparseMatrix.h b/src/storage/SparseMatrix.h
index 4892dbe32..99a876d7d 100644
--- a/src/storage/SparseMatrix.h
+++ b/src/storage/SparseMatrix.h
@@ -7,9 +7,11 @@
 #include <vector>
 #include <iterator>
 
+#include <boost/functional/hash.hpp>
+#include <boost/optional.hpp>
+
 #include "src/utility/OsDetection.h"
 #include "src/adapters/CarlAdapter.h"
-#include <boost/functional/hash.hpp>
 
 // Forward declaration for adapter classes.
 namespace storm {
@@ -259,7 +261,8 @@ namespace storm {
             // The number of row groups in the matrix.
             index_type initialRowGroupCount;
             
-            std::vector<index_type> rowGroupIndices;
+            // The vector that stores the row-group indices (if they are non-trivial).
+            boost::optional<std::vector<index_type>> rowGroupIndices;
             
             // The storage for the columns and values of all entries in the matrix.
             std::vector<MatrixEntry<index_type, value_type>> columnsAndValues;
@@ -452,9 +455,8 @@ namespace storm {
              * @param rowIndications The row indications vector of the matrix to be constructed.
              * @param columnsAndValues The vector containing the columns and values of the entries in the matrix.
              * @param rowGroupIndices The vector representing the row groups in the matrix.
-             * @param hasNontrivialRowGrouping If set to true, this indicates that the row grouping is non-trivial.
              */
-            SparseMatrix(index_type columnCount, std::vector<index_type> const& rowIndications, std::vector<MatrixEntry<index_type, value_type>> const& columnsAndValues, std::vector<index_type> const& rowGroupIndices, bool hasNontrivialRowGrouping);
+            SparseMatrix(index_type columnCount, std::vector<index_type> const& rowIndications, std::vector<MatrixEntry<index_type, value_type>> const& columnsAndValues, boost::optional<std::vector<index_type>> const& rowGroupIndices);
             
             /*!
              * Constructs a sparse matrix by moving the given contents.
@@ -463,9 +465,8 @@ namespace storm {
              * @param rowIndications The row indications vector of the matrix to be constructed.
              * @param columnsAndValues The vector containing the columns and values of the entries in the matrix.
              * @param rowGroupIndices The vector representing the row groups in the matrix.
-             * @param hasNontrivialRowGrouping If set to true, this indicates that the row grouping is non-trivial.
              */
-            SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications, std::vector<MatrixEntry<index_type, value_type>>&& columnsAndValues, std::vector<index_type>&& rowGroupIndices, bool hasNontrivialRowGrouping);
+            SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications, std::vector<MatrixEntry<index_type, value_type>>&& columnsAndValues, boost::optional<std::vector<index_type>>&& rowGroupIndices);
 
             /*!
              * Assigns the contents of the given matrix to the current one by deep-copying its contents.
@@ -809,7 +810,7 @@ namespace storm {
              * Returns an object representing the consecutive rows given by the parameters.
              *
              * @param startRow The starting row.
-             * @param endRow The ending row (which is included in the result).
+             * @param endRow The ending row (which is *not* included in the result).
              * @return An object representing the consecutive rows given by the parameters.
              */
             const_rows getRows(index_type startRow, index_type endRow) const;
@@ -818,7 +819,7 @@ namespace storm {
              * Returns an object representing the consecutive rows given by the parameters.
              *
              * @param startRow The starting row.
-             * @param endRow The ending row (which is included in the result).
+             * @param endRow The ending row (which is *not* included in the result).
              * @return An object representing the consecutive rows given by the parameters.
              */
             rows getRows(index_type startRow, index_type endRow);
@@ -918,27 +919,28 @@ namespace storm {
             iterator end();
             
             /*!
-             * Retrieves whether the matrix has a (possibly) non-trivial row grouping.
+             * Retrieves whether the matrix has a trivial row grouping.
              *
-             * @return True iff the matrix has a (possibly) non-trivial row grouping.
+             * @return True iff the matrix has a trivial row grouping.
              */
-            bool hasNontrivialRowGrouping() const;
+            bool hasTrivialRowGrouping() const;
 
 			/*!
 			* Returns a copy of the matrix with the chosen internal data type
 			*/
 			template<typename NewValueType>
 			SparseMatrix<NewValueType> toValueType() const {
-				std::vector<MatrixEntry<SparseMatrix::index_type, NewValueType>> new_columnsAndValues;
-				std::vector<SparseMatrix::index_type> new_rowIndications(rowIndications);
-				std::vector<SparseMatrix::index_type> new_rowGroupIndices(rowGroupIndices);
+				std::vector<MatrixEntry<SparseMatrix::index_type, NewValueType>> newColumnsAndValues;
+				std::vector<SparseMatrix::index_type> newRowIndications(rowIndications);
+                boost::optional<std::vector<SparseMatrix::index_type>> newRowGroupIndices(rowGroupIndices);
 
-				new_columnsAndValues.resize(columnsAndValues.size());
-				for (size_t i = 0, size = columnsAndValues.size(); i < size; ++i) {
-					new_columnsAndValues.at(i) = MatrixEntry<SparseMatrix::index_type, NewValueType>(columnsAndValues.at(i).getColumn(), static_cast<NewValueType>(columnsAndValues.at(i).getValue()));
-				}
+				newColumnsAndValues.resize(columnsAndValues.size());
+                std::transform(columnsAndValues.begin(), columnsAndValues.end(), newColumnsAndValues.begin(),
+                               [] (MatrixEntry<SparseMatrix::index_type, ValueType> const& a) {
+                                   return MatrixEntry<SparseMatrix::index_type, NewValueType>(a.getColumn(), static_cast<NewValueType>(a.getValue()));
+                               });
 
-				return SparseMatrix<NewValueType>(columnCount, std::move(new_rowIndications), std::move(new_columnsAndValues), std::move(new_rowGroupIndices), nontrivialRowGrouping);
+				return SparseMatrix<NewValueType>(columnCount, std::move(newRowIndications), std::move(newColumnsAndValues), std::move(newRowGroupIndices));
 			}
             
         private:
@@ -977,12 +979,12 @@ namespace storm {
             // entry is not included anymore.
             std::vector<index_type> rowIndications;
             
-            // A flag that indicates whether the matrix has a non-trivial row-grouping, i.e. (possibly) more than one
-            // row per row group.
-            bool nontrivialRowGrouping;
+            // A flag indicating whether the matrix has a trivial row grouping. Note that this may be true and yet
+            // there may be row group indices, because they were requested from the outside.
+            bool trivialRowGrouping;
             
-            // A vector indicating the row groups of the matrix.
-            std::vector<index_type> rowGroupIndices;
+            // A vector indicating the row groups of the matrix. This needs to be mutible in case we create it on-the-fly.
+            mutable boost::optional<std::vector<index_type>> rowGroupIndices;
             
         };
         
diff --git a/src/storage/dd/Add.cpp b/src/storage/dd/Add.cpp
index ecd98c2d9..40223da75 100644
--- a/src/storage/dd/Add.cpp
+++ b/src/storage/dd/Add.cpp
@@ -459,7 +459,7 @@ namespace storm {
             rowIndications[0] = 0;
             
             // Construct matrix and return result.
-            return storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(trivialRowGroupIndices), false);
+            return storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), boost::none);
         }
         
         template<DdType LibraryType, typename ValueType>
@@ -583,7 +583,7 @@ namespace storm {
             }
             rowIndications[0] = 0;
             
-            return storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), true);
+            return storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices));
         }
 
         template<DdType LibraryType, typename ValueType>
@@ -708,7 +708,7 @@ namespace storm {
             }
             rowIndications[0] = 0;
             
-            return std::make_pair(storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), true), std::move(explicitVector));
+            return std::make_pair(storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices)), std::move(explicitVector));
         }
 
         template<DdType LibraryType, typename ValueType>
diff --git a/src/storage/prism/Program.cpp b/src/storage/prism/Program.cpp
index bf8caf4a8..999cf2f30 100644
--- a/src/storage/prism/Program.cpp
+++ b/src/storage/prism/Program.cpp
@@ -77,6 +77,14 @@ namespace storm {
             return modelType;
         }
         
+        bool Program::isDiscreteTimeModel() const {
+            return modelType == ModelType::DTMC || modelType == ModelType::MDP;
+        }
+        
+        bool Program::isDeterministicModel() const {
+            return modelType == ModelType::DTMC || modelType == ModelType::CTMC;
+        }
+        
         bool Program::hasUndefinedConstants() const {
             for (auto const& constant : this->getConstants()) {
                 if (!constant.isDefined()) {
diff --git a/src/storage/prism/Program.h b/src/storage/prism/Program.h
index 45ac16b62..1d091c294 100644
--- a/src/storage/prism/Program.h
+++ b/src/storage/prism/Program.h
@@ -66,6 +66,18 @@ namespace storm {
              * @return The type of the model.
              */
             ModelType getModelType() const;
+            
+            /*!
+             * Retrieves whether the model is a discrete-time model, i.e. a DTMC or an MDP.
+             *
+             * @return True iff the model is a discrete-time model.
+             */
+            bool isDiscreteTimeModel() const;
+            
+            /*!
+             * Retrieves whether the model is one without nondeterministic choices, i.e. a DTMC or a CTMC.
+             */
+            bool isDeterministicModel() const;
 
             /*!
              * Retrieves whether there are undefined constants of any type in the program.
diff --git a/src/storage/prism/RewardModel.cpp b/src/storage/prism/RewardModel.cpp
index 3f38f7bd8..30c43728c 100644
--- a/src/storage/prism/RewardModel.cpp
+++ b/src/storage/prism/RewardModel.cpp
@@ -84,7 +84,7 @@ namespace storm {
         std::ostream& operator<<(std::ostream& stream, RewardModel const& rewardModel) {
             stream << "rewards";
             if (rewardModel.getName() != "") {
-                std::cout << " \"" << rewardModel.getName() << "\"";
+                stream << " \"" << rewardModel.getName() << "\"";
             }
             stream << std::endl;
             for (auto const& reward : rewardModel.getStateRewards()) {
diff --git a/src/utility/constants.cpp b/src/utility/constants.cpp
index 06c934864..8e0d6742e 100644
--- a/src/utility/constants.cpp
+++ b/src/utility/constants.cpp
@@ -215,6 +215,10 @@ namespace storm {
         template bool isZero(storm::storage::sparse::state_type const& value);
         template bool isConstant(storm::storage::sparse::state_type const& value);
 
+        template uint32_t one();
+        template uint32_t zero();
+        template uint32_t infinity();
+                
         template storm::storage::sparse::state_type one();
         template storm::storage::sparse::state_type zero();
         template storm::storage::sparse::state_type infinity();
diff --git a/src/utility/storm.h b/src/utility/storm.h
index a3cb98e2f..96087e30a 100644
--- a/src/utility/storm.h
+++ b/src/utility/storm.h
@@ -110,8 +110,8 @@ namespace storm {
                 options.buildCommandLabels = true;
             }
 
-            storm::builder::ExplicitPrismModelBuilder<ValueType> builder;
-            result.model = builder.translateProgram(program, options);
+            storm::builder::ExplicitPrismModelBuilder<ValueType> builder(program, options);
+            result.model = builder.translate();
             translatedProgram = builder.getTranslatedProgram();
         } else if (settings.getEngine() == storm::settings::modules::GeneralSettings::Engine::Dd || settings.getEngine() == storm::settings::modules::GeneralSettings::Engine::Hybrid) {
             typename storm::builder::DdPrismModelBuilder<LibraryType>::Options options;
diff --git a/test/functional/builder/ExplicitPrismModelBuilderTest.cpp b/test/functional/builder/ExplicitPrismModelBuilderTest.cpp
index 080b6c16f..c2151c74c 100644
--- a/test/functional/builder/ExplicitPrismModelBuilderTest.cpp
+++ b/test/functional/builder/ExplicitPrismModelBuilderTest.cpp
@@ -10,27 +10,27 @@
 TEST(ExplicitPrismModelBuilderTest, Dtmc) {
     storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/die.pm");
     
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(13ul, model->getNumberOfStates());
     EXPECT_EQ(20ul, model->getNumberOfTransitions());
     
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/brp-16-2.pm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(677ul, model->getNumberOfStates());
     EXPECT_EQ(867ul, model->getNumberOfTransitions());
     
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/crowds-5-5.pm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(8607ul, model->getNumberOfStates());
     EXPECT_EQ(15113ul, model->getNumberOfTransitions());
     
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader-3-5.pm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(273ul, model->getNumberOfStates());
     EXPECT_EQ(397ul, model->getNumberOfTransitions());
     
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/nand-5-2.pm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(1728ul, model->getNumberOfStates());
     EXPECT_EQ(2505ul, model->getNumberOfTransitions());
 }
@@ -41,27 +41,27 @@ TEST(ExplicitPrismModelBuilderTest, Ctmc) {
 
     storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/cluster2.sm");
 
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(276ul, model->getNumberOfStates());
     EXPECT_EQ(1120ul, model->getNumberOfTransitions());
     
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/embedded2.sm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(3478ul, model->getNumberOfStates());
     EXPECT_EQ(14639ul, model->getNumberOfTransitions());
     
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/polling2.sm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(12ul, model->getNumberOfStates());
     EXPECT_EQ(22ul, model->getNumberOfTransitions());
     
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/fms2.sm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(810ul, model->getNumberOfStates());
     EXPECT_EQ(3699ul, model->getNumberOfTransitions());
     
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/tandem5.sm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(66ul, model->getNumberOfStates());
     EXPECT_EQ(189ul, model->getNumberOfTransitions());
 }
@@ -69,32 +69,32 @@ TEST(ExplicitPrismModelBuilderTest, Ctmc) {
 TEST(ExplicitPrismModelBuilderTest, Mdp) {
     storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/two_dice.nm");
     
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(169ul, model->getNumberOfStates());
     EXPECT_EQ(436ul, model->getNumberOfTransitions());
     
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader3.nm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(364ul, model->getNumberOfStates());
     EXPECT_EQ(654ul, model->getNumberOfTransitions());
     
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/coin2-2.nm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(272ul, model->getNumberOfStates());
     EXPECT_EQ(492ul, model->getNumberOfTransitions());
 
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/csma2-2.nm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(1038ul, model->getNumberOfStates());
     EXPECT_EQ(1282ul, model->getNumberOfTransitions());
     
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/firewire3-0.5.nm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(4093ul, model->getNumberOfStates());
     EXPECT_EQ(5585ul, model->getNumberOfTransitions());
     
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/wlan0-2-2.nm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(37ul, model->getNumberOfStates());
     EXPECT_EQ(59ul, model->getNumberOfTransitions());
 }
\ No newline at end of file
diff --git a/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp
index b36983962..dc9512a38 100644
--- a/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp
+++ b/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp
@@ -34,7 +34,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Cluster) {
 #endif
     options.buildAllRewardModels = false;
     options.rewardModelsToBuild.insert("num_repairs");
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate();
     ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
     std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
     uint_fast64_t initialState = *ctmc->getInitialStates().begin();
@@ -117,7 +117,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Embedded) {
 #endif
     options.buildAllRewardModels = false;
     options.rewardModelsToBuild.insert("up");
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate();
     ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
     std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
     uint_fast64_t initialState = *ctmc->getInitialStates().begin();
@@ -179,7 +179,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Polling) {
     std::shared_ptr<const storm::logic::Formula> formula(nullptr);
     
     // Build the model.
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
     std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
     uint_fast64_t initialState = *ctmc->getInitialStates().begin();
@@ -226,7 +226,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Tandem) {
 	typename storm::builder::ExplicitPrismModelBuilder<double>::Options options;
 #endif
     options.rewardModelsToBuild.insert("customers");
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate();
     ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
     std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
     uint_fast64_t initialState = *ctmc->getInitialStates().begin();
diff --git a/test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp
index 1e131c335..36a139b9c 100644
--- a/test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp
+++ b/test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp
@@ -284,7 +284,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, LRA) {
 TEST(GmmxxDtmcPrctlModelCheckerTest, Conditional) {
     storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/modelchecker/test_conditional.pm");
     
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     ASSERT_TRUE(model->getType() == storm::models::ModelType::Dtmc);
     ASSERT_EQ(4ul, model->getNumberOfStates());
     ASSERT_EQ(5ul, model->getNumberOfTransitions());
diff --git a/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp
index 725e1376d..93643fd52 100644
--- a/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp
+++ b/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp
@@ -197,7 +197,7 @@ TEST(GmmxxMdpPrctlModelCheckerTest, SchedulerGeneration) {
     // A parser that we use for conveniently constructing the formulas.
     storm::parser::FormulaParser formulaParser;
     
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     EXPECT_EQ(4ul, model->getNumberOfStates());
     EXPECT_EQ(11ul, model->getNumberOfTransitions());
     
diff --git a/test/functional/modelchecker/NativeCtmcCslModelCheckerTest.cpp b/test/functional/modelchecker/NativeCtmcCslModelCheckerTest.cpp
index 72788de80..0a1d8ee4c 100644
--- a/test/functional/modelchecker/NativeCtmcCslModelCheckerTest.cpp
+++ b/test/functional/modelchecker/NativeCtmcCslModelCheckerTest.cpp
@@ -32,7 +32,7 @@ TEST(NativeCtmcCslModelCheckerTest, Cluster) {
 #endif
     options.buildAllRewardModels = false;
     options.rewardModelsToBuild.insert("num_repairs");
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate();
     ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
     std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
     uint_fast64_t initialState = *ctmc->getInitialStates().begin();
@@ -108,7 +108,7 @@ TEST(NativeCtmcCslModelCheckerTest, Embedded) {
 #endif
     options.buildAllRewardModels = false;
     options.rewardModelsToBuild.insert("up");
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate();
     ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
     std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
     uint_fast64_t initialState = *ctmc->getInitialStates().begin();
@@ -163,7 +163,7 @@ TEST(NativeCtmcCslModelCheckerTest, Polling) {
     std::shared_ptr<const storm::logic::Formula> formula(nullptr);
     
     // Build the model.
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
     std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
     uint_fast64_t initialState = *ctmc->getInitialStates().begin();
@@ -204,7 +204,7 @@ TEST(NativeCtmcCslModelCheckerTest, Tandem) {
 #endif
     options.buildAllRewardModels = false;
     options.rewardModelsToBuild.insert("customers");
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate();
     ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
     std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
     uint_fast64_t initialState = *ctmc->getInitialStates().begin();
diff --git a/test/functional/permissiveschedulers/MilpPermissiveSchedulerTest.cpp b/test/functional/permissiveschedulers/MilpPermissiveSchedulerTest.cpp
index 75bea3570..657d36575 100644
--- a/test/functional/permissiveschedulers/MilpPermissiveSchedulerTest.cpp
+++ b/test/functional/permissiveschedulers/MilpPermissiveSchedulerTest.cpp
@@ -28,7 +28,7 @@ TEST(MilpPermissiveSchedulerTest, DieSelection) {
     options.addConstantDefinitionsFromString(program, "");
     options.buildCommandLabels = true;
     
-    std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options)->as<storm::models::sparse::Mdp<double>>();
+    std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate()->as<storm::models::sparse::Mdp<double>>();
     
     boost::optional<storm::ps::SubMDPPermissiveScheduler<>> perms = storm::ps::computePermissiveSchedulerViaMILP<>(*mdp, formula02);
     EXPECT_NE(perms, boost::none);
diff --git a/test/functional/permissiveschedulers/SmtPermissiveSchedulerTest.cpp b/test/functional/permissiveschedulers/SmtPermissiveSchedulerTest.cpp
index 4d87796b8..2790cd86a 100644
--- a/test/functional/permissiveschedulers/SmtPermissiveSchedulerTest.cpp
+++ b/test/functional/permissiveschedulers/SmtPermissiveSchedulerTest.cpp
@@ -31,7 +31,7 @@ TEST(SmtPermissiveSchedulerTest, DieSelection) {
     options.addConstantDefinitionsFromString(program, "");
     options.buildCommandLabels = true;
     
-    std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options)->as<storm::models::sparse::Mdp<double>>();
+    std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate()->as<storm::models::sparse::Mdp<double>>();
     
 //    boost::optional<storm::ps::SubMDPPermissiveScheduler<>> perms = storm::ps::computePermissiveSchedulerViaSMT<>(*mdp, formula02);
 //    EXPECT_NE(perms, boost::none);
diff --git a/test/functional/storage/BitVectorHashMapTest.cpp b/test/functional/storage/BitVectorHashMapTest.cpp
index 616941f21..1149433fd 100644
--- a/test/functional/storage/BitVectorHashMapTest.cpp
+++ b/test/functional/storage/BitVectorHashMapTest.cpp
@@ -19,25 +19,41 @@ TEST(BitVectorHashMapTest, FindOrAdd) {
     ASSERT_NO_THROW(map.findOrAdd(second, 2));
     
     EXPECT_EQ(1ul, map.findOrAdd(first, 3));
-    
+    EXPECT_EQ(2ul, map.findOrAdd(second, 3));
+
     storm::storage::BitVector third(64);
     third.set(10);
     third.set(63);
     
     ASSERT_NO_THROW(map.findOrAdd(third, 3));
 
+    EXPECT_EQ(1ul, map.findOrAdd(first, 2));
+    EXPECT_EQ(2ul, map.findOrAdd(second, 1));
+    EXPECT_EQ(3ul, map.findOrAdd(third, 1));
+    
     storm::storage::BitVector fourth(64);
     fourth.set(12);
     fourth.set(14);
 
     ASSERT_NO_THROW(map.findOrAdd(fourth, 4));
 
+    EXPECT_EQ(1ul, map.findOrAdd(first, 2));
+    EXPECT_EQ(2ul, map.findOrAdd(second, 1));
+    EXPECT_EQ(3ul, map.findOrAdd(third, 1));
+    EXPECT_EQ(4ul, map.findOrAdd(fourth, 1));
+    
     storm::storage::BitVector fifth(64);
     fifth.set(44);
     fifth.set(55);
     
     ASSERT_NO_THROW(map.findOrAdd(fifth, 5));
 
+    EXPECT_EQ(1ul, map.findOrAdd(first, 2));
+    EXPECT_EQ(2ul, map.findOrAdd(second, 1));
+    EXPECT_EQ(3ul, map.findOrAdd(third, 1));
+    EXPECT_EQ(4ul, map.findOrAdd(fourth, 1));
+    EXPECT_EQ(5ul, map.findOrAdd(fifth, 1));
+    
     storm::storage::BitVector sixth(64);
     sixth.set(45);
     sixth.set(55);
diff --git a/test/functional/storage/BitVectorTest.cpp b/test/functional/storage/BitVectorTest.cpp
index 3e4d53235..cea9cb4e7 100644
--- a/test/functional/storage/BitVectorTest.cpp
+++ b/test/functional/storage/BitVectorTest.cpp
@@ -321,24 +321,6 @@ TEST(BitVectorTest, OperatorModulo) {
             ASSERT_FALSE(moduloResult.get(i));
         }
     }
-    
-    storm::storage::BitVector vector3(31);
-    
-    for (uint_fast64_t i = 0; i < 15; ++i) {
-		vector3.set(i, i % 2 == 0);
-    }
-    
-
-#ifndef NDEBUG
-#ifdef WINDOWS
-	EXPECT_EXIT(vector1 % vector3, ::testing::ExitedWithCode(0), ".*");
-#else
-	EXPECT_DEATH_IF_SUPPORTED(vector1 % vector3, "");
-#endif
-#else
-	std::cerr << "WARNING: Not testing OperatorModulo size check, as assertions are disabled in release mode." << std::endl;
-	SUCCEED();
-#endif
 }
 
 TEST(BitVectorTest, OperatorNot) {
diff --git a/test/functional/storage/NondeterministicModelBisimulationDecompositionTest.cpp b/test/functional/storage/NondeterministicModelBisimulationDecompositionTest.cpp
index 3754b03fd..fe0a199b7 100644
--- a/test/functional/storage/NondeterministicModelBisimulationDecompositionTest.cpp
+++ b/test/functional/storage/NondeterministicModelBisimulationDecompositionTest.cpp
@@ -14,7 +14,7 @@ TEST(NondeterministicModelBisimulationDecomposition, TwoDice) {
     storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/two_dice.nm");
 
     // Build the die model without its reward model.
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
 
     ASSERT_EQ(model->getType(), storm::models::ModelType::Mdp);
     std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = model->as<storm::models::sparse::Mdp<double>>();
diff --git a/test/functional/storage/SparseMatrixTest.cpp b/test/functional/storage/SparseMatrixTest.cpp
index 1fe0041f7..321fc7b91 100644
--- a/test/functional/storage/SparseMatrixTest.cpp
+++ b/test/functional/storage/SparseMatrixTest.cpp
@@ -155,8 +155,8 @@ TEST(SparseMatrix, CreationWithMovingContents) {
     columnsAndValues.emplace_back(1, 0.7);
     columnsAndValues.emplace_back(3, 0.2);
     
-    ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, columnsAndValues, {0, 1, 2, 3}, false));
-    storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, columnsAndValues, {0, 1, 2, 3}, false);
+    ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, columnsAndValues, boost::optional<std::vector<uint_fast64_t>>({0, 1, 2, 3})));
+    storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, columnsAndValues, boost::optional<std::vector<uint_fast64_t>>({0, 1, 2, 3}));
     ASSERT_EQ(3ul, matrix.getRowCount());
     ASSERT_EQ(4ul, matrix.getColumnCount());
     ASSERT_EQ(5ul, matrix.getEntryCount());
diff --git a/test/functional/utility/GraphTest.cpp b/test/functional/utility/GraphTest.cpp
index d209998d7..4c6bf0d50 100644
--- a/test/functional/utility/GraphTest.cpp
+++ b/test/functional/utility/GraphTest.cpp
@@ -181,7 +181,7 @@ TEST(GraphTest, SymbolicProb01MinMax_Sylvan) {
 
 TEST(GraphTest, ExplicitProb01) {
     storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/crowds-5-5.pm");
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     
     ASSERT_TRUE(model->getType() == storm::models::ModelType::Dtmc);
     
@@ -202,7 +202,7 @@ TEST(GraphTest, ExplicitProb01) {
 
 TEST(GraphTest, ExplicitProb01MinMax) {
     storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader3.nm");
-    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     
     ASSERT_TRUE(model->getType() == storm::models::ModelType::Mdp);
     
@@ -217,7 +217,7 @@ TEST(GraphTest, ExplicitProb01MinMax) {
     EXPECT_EQ(364ul, statesWithProbability01.second.getNumberOfSetBits());
     
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/coin2-2.nm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     
     ASSERT_TRUE(model->getType() == storm::models::ModelType::Mdp);
     
@@ -238,7 +238,7 @@ TEST(GraphTest, ExplicitProb01MinMax) {
     EXPECT_EQ(35ul, statesWithProbability01.second.getNumberOfSetBits());
     
     program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/csma2-2.nm");
-    model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
+    model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
     
     ASSERT_TRUE(model->getType() == storm::models::ModelType::Mdp);
     
diff --git a/test/functional/utility/ModelInstantiatorTest.cpp b/test/functional/utility/ModelInstantiatorTest.cpp
index 0bf692a60..9602a3e86 100644
--- a/test/functional/utility/ModelInstantiatorTest.cpp
+++ b/test/functional/utility/ModelInstantiatorTest.cpp
@@ -17,12 +17,12 @@
 #include "src/models/sparse/Dtmc.h"
 #include "src/models/sparse/Mdp.h"
 
-TEST(ModelInstantiatorTest, Brp_Prob) {
+TEST(ModelInstantiatorTest, BrpProb) {
     carl::VariablePool::getInstance().clear();
     
-    std::string const& programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/brp16_2.pm";
-    std::string const& formulaAsString = "P=? [F s=5 ]";
-    std::string const& constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
+    std::string programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/brp16_2.pm";
+    std::string formulaAsString = "P=? [F s=5 ]";
+    std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
     
     // Program and formula
     storm::prism::Program program = storm::parseProgram(programFile);
@@ -33,7 +33,7 @@ TEST(ModelInstantiatorTest, Brp_Prob) {
     typename storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options options = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options(*formulas[0]);
     options.addConstantDefinitionsFromString(program, constantsAsString); 
     options.preserveFormula(*formulas[0]);
-    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>().translateProgram(program, options)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
+    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>(program, options).translate()->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
     
     storm::utility::ModelInstantiator<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::models::sparse::Dtmc<double>> modelInstantiator(*dtmc);
     EXPECT_FALSE(dtmc->hasRewardModel());
@@ -141,9 +141,9 @@ TEST(ModelInstantiatorTest, Brp_Prob) {
 TEST(ModelInstantiatorTest, Brp_Rew) {
     carl::VariablePool::getInstance().clear();
     
-    std::string const& programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/brp16_2.pm";
-    std::string const& formulaAsString = "R=? [F ((s=5) | (s=0&srep=3)) ]";
-    std::string const& constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
+    std::string programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/brp16_2.pm";
+    std::string formulaAsString = "R=? [F ((s=5) | (s=0&srep=3)) ]";
+    std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
     
     // Program and formula
     storm::prism::Program program = storm::parseProgram(programFile);
@@ -154,7 +154,7 @@ TEST(ModelInstantiatorTest, Brp_Rew) {
     typename storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options options = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options(*formulas[0]);
     options.addConstantDefinitionsFromString(program, constantsAsString); 
     options.preserveFormula(*formulas[0]);
-    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>().translateProgram(program, options)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
+    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>(program, options).translate()->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
 
     storm::utility::ModelInstantiator<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::models::sparse::Dtmc<double>> modelInstantiator(*dtmc);
     
@@ -211,12 +211,12 @@ TEST(ModelInstantiatorTest, Brp_Rew) {
 }
     
 
-TEST(ModelInstantiatorTest, consensus) {
+TEST(ModelInstantiatorTest, Consensus) {
     carl::VariablePool::getInstance().clear();
     
-    std::string const& programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/coin2_2.pm";
-    std::string const& formulaAsString = "Pmin=? [F \"finished\"&\"all_coins_equal_1\" ]";
-    std::string const& constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
+    std::string programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/coin2_2.pm";
+    std::string formulaAsString = "Pmin=? [F \"finished\"&\"all_coins_equal_1\" ]";
+    std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
     
     // Program and formula
     storm::prism::Program program = storm::parseProgram(programFile);
@@ -227,7 +227,7 @@ TEST(ModelInstantiatorTest, consensus) {
     typename storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options options = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options(*formulas[0]);
     options.addConstantDefinitionsFromString(program, constantsAsString); 
     options.preserveFormula(*formulas[0]);
-    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> mdp = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>().translateProgram(program, options)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
+    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> mdp = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>(program, options).translate()->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
 
     storm::utility::ModelInstantiator<storm::models::sparse::Mdp<storm::RationalFunction>, storm::models::sparse::Mdp<double>> modelInstantiator(*mdp);
     
@@ -260,7 +260,6 @@ TEST(ModelInstantiatorTest, consensus) {
     std::unique_ptr<storm::modelchecker::CheckResult> chkResult = modelchecker.check(*formulas[0]);
     storm::modelchecker::ExplicitQuantitativeCheckResult<double>& quantitativeChkResult = chkResult->asExplicitQuantitativeCheckResult<double>();
     EXPECT_NEAR(0.3526577219, quantitativeChkResult[*instantiated.getInitialStates().begin()], storm::settings::generalSettings().getPrecision());
-    
 }
 
 #endif
\ No newline at end of file