diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index bd0f67e7f..e9059930d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -9,6 +9,9 @@ add_subdirectory(storm-gspn)
 add_subdirectory(storm-gspn-cli)
 add_subdirectory(storm-dft)
 add_subdirectory(storm-dft-cli)
+add_subdirectory(storm-pars)
+add_subdirectory(storm-pars-cli)
+
 add_subdirectory(test)
 
-set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE)
\ No newline at end of file
+set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE)
diff --git a/src/storm-pars-cli/CMakeLists.txt b/src/storm-pars-cli/CMakeLists.txt
new file mode 100644
index 000000000..9cd155e35
--- /dev/null
+++ b/src/storm-pars-cli/CMakeLists.txt
@@ -0,0 +1,7 @@
+# Create storm-pars.
+add_executable(storm-pars-cli ${PROJECT_SOURCE_DIR}/src/storm-pars-cli/storm-pars.cpp)
+target_link_libraries(storm-pars-cli storm-pars) # Adding headers for xcode
+set_target_properties(storm-pars-cli PROPERTIES OUTPUT_NAME "storm-pars")
+
+# installation
+install(TARGETS storm-pars-cli RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)
diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp
new file mode 100644
index 000000000..eba86792d
--- /dev/null
+++ b/src/storm-pars-cli/storm-pars.cpp
@@ -0,0 +1,346 @@
+
+#include "storm-pars/api/storm-pars.h"
+#include "storm-pars/settings/ParsSettings.h"
+#include "storm-pars/settings/modules/ParametricSettings.h"
+#include "storm-pars/settings/modules/RegionSettings.h"
+
+#include "storm/settings/SettingsManager.h"
+#include "storm/api/storm.h"
+#include "storm/cli/cli.h"
+#include "storm/models/ModelBase.h"
+#include "storm/storage/SymbolicModelDescription.h"
+#include "storm/utility/file.h"
+#include "storm/utility/initialize.h"
+#include "storm/utility/Stopwatch.h"
+#include "storm/utility/macros.h"
+
+#include "storm/settings/modules/GeneralSettings.h"
+#include "storm/settings/modules/CoreSettings.h"
+#include "storm/settings/modules/IOSettings.h"
+#include "storm/settings/modules/BisimulationSettings.h"
+
+#include "storm/exceptions/BaseException.h"
+#include "storm/exceptions/InvalidSettingsException.h"
+#include "storm/exceptions/NotSupportedException.h"
+
+#include "storm/cli/cli.cpp"
+
+namespace storm {
+    namespace pars {
+    
+        typedef typename storm::cli::SymbolicInput SymbolicInput;
+        
+        template <typename ValueType>
+        std::shared_ptr<storm::models::ModelBase> buildModelSparse(SymbolicInput const& input, storm::settings::modules::IOSettings const& ioSettings) {
+            return storm::api::buildSparseModel<ValueType>(input.model.get(), storm::api::extractFormulasFromProperties(input.properties), ioSettings.isBuildChoiceLabelsSet());
+        }
+
+        template <storm::dd::DdType DdType, typename ValueType>
+        std::shared_ptr<storm::models::ModelBase> buildModel(storm::settings::modules::CoreSettings::Engine const& engine, SymbolicInput const& input, storm::settings::modules::IOSettings const& ioSettings) {
+            storm::utility::Stopwatch modelBuildingWatch(true);
+
+            std::shared_ptr<storm::models::ModelBase> result;
+            if (input.model) {
+                if (engine == storm::settings::modules::CoreSettings::Engine::Dd || engine == storm::settings::modules::CoreSettings::Engine::Hybrid) {
+                    result = storm::cli::buildModelDd<DdType, ValueType>(input);
+                } else if (engine == storm::settings::modules::CoreSettings::Engine::Sparse) {
+                    result = storm::pars::buildModelSparse<ValueType>(input, ioSettings);
+                }
+            } else if (ioSettings.isExplicitSet() || ioSettings.isExplicitDRNSet()) {
+                STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Can only use sparse engine with explicit input.");
+                result = storm::cli::buildModelExplicit<ValueType>(ioSettings);
+            }
+            
+            modelBuildingWatch.stop();
+            if (result) {
+                STORM_PRINT_AND_LOG("Time for model construction: " << modelBuildingWatch << "." << std::endl << std::endl);
+            }
+
+            return result;
+        }
+
+        
+        template <typename ValueType>
+        std::vector<storm::storage::ParameterRegion<ValueType>> parseRegions(std::shared_ptr<storm::models::ModelBase> const& model) {
+            std::vector<storm::storage::ParameterRegion<ValueType>> result;
+            auto regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>();
+            if (regionSettings.isRegionSet()) {
+                result = storm::api::parseRegions<ValueType>(regionSettings.getRegionString(), *model);
+            }
+            return result;
+        }
+        
+        template <typename ValueType>
+        std::pair<std::shared_ptr<storm::models::ModelBase>, bool> preprocessSparseModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input) {
+            auto generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>();
+            auto bisimulationSettings = storm::settings::getModule<storm::settings::modules::BisimulationSettings>();
+            auto parametricSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>();
+            
+            std::pair<std::shared_ptr<storm::models::ModelBase>, bool> result = std::make_pair(model, false);
+            
+            if (result.first->isOfType(storm::models::ModelType::MarkovAutomaton)) {
+                result.first = storm::cli::preprocessSparseMarkovAutomaton(result.first->template as<storm::models::sparse::MarkovAutomaton<ValueType>>());
+                result.second = true;
+            }
+            
+            if (generalSettings.isBisimulationSet()) {
+                result.first = storm::cli::preprocessSparseModelBisimulation(result.first->template as<storm::models::sparse::Model<ValueType>>(), input, bisimulationSettings);
+                result.second = true;
+            }
+            
+            if (parametricSettings.transformContinuousModel() && (result.first->isOfType(storm::models::ModelType::Ctmc) || result.first->isOfType(storm::models::ModelType::MarkovAutomaton))) {
+                result.first = storm::api::transformContinuousToDiscreteTimeSparseModel(std::move(*result.first->template as<storm::models::sparse::Model<ValueType>>()), storm::api::extractFormulasFromProperties(input.properties));
+                result.second = true;
+            }
+            
+            return result;
+        }
+        
+        template <storm::dd::DdType DdType, typename ValueType>
+        std::pair<std::shared_ptr<storm::models::ModelBase>, bool> preprocessDdModel(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, SymbolicInput const& input) {
+            
+            std::pair<std::shared_ptr<storm::models::ModelBase>, bool> result = std::make_pair(model, false);
+        
+            auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>();
+            if (coreSettings.getEngine() == storm::settings::modules::CoreSettings::Engine::Hybrid) {
+                // Currently, hybrid engine for parametric models just referrs to building the model symbolically.
+                STORM_LOG_INFO("Translating symbolic model to sparse model...");
+                result.first = storm::api::transformSymbolicToSparseModel(model);
+                result.second = true;
+                // Invoke preprocessing on the sparse model
+                auto sparsePreprocessingResult = storm::pars::preprocessSparseModel<ValueType>(result.first->as<storm::models::sparse::Model<ValueType>>(), input);
+                if (sparsePreprocessingResult.second) {
+                    result.first = sparsePreprocessingResult.first;
+                }
+            }
+            return result;
+        }
+        
+        template <storm::dd::DdType DdType, typename ValueType>
+        std::pair<std::shared_ptr<storm::models::ModelBase>, bool> preprocessModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input) {
+            storm::utility::Stopwatch preprocessingWatch(true);
+            
+            std::pair<std::shared_ptr<storm::models::ModelBase>, bool> result = std::make_pair(model, false);
+            if (model->isSparseModel()) {
+                result = storm::pars::preprocessSparseModel<ValueType>(result.first->as<storm::models::sparse::Model<ValueType>>(), input);
+            } else {
+                STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type.");
+                result = storm::pars::preprocessDdModel<DdType, ValueType>(result.first->as<storm::models::symbolic::Model<DdType, ValueType>>(), input);
+            }
+            
+            if (result.second) {
+                STORM_PRINT_AND_LOG(std::endl << "Time for model preprocessing: " << preprocessingWatch << "." << std::endl << std::endl);
+            }
+            return result;
+        }
+        
+        template<typename ValueType>
+        void printInitialStatesResult(std::unique_ptr<storm::modelchecker::CheckResult> const& result, storm::jani::Property const& property, storm::utility::Stopwatch* watch = nullptr) {
+            if (result) {
+                STORM_PRINT_AND_LOG("Result (initial states): " << std::endl);
+                
+                auto const* regionCheckResult = dynamic_cast<storm::modelchecker::RegionCheckResult<ValueType> const*>(result.get());
+                if (regionCheckResult != nullptr) {
+                    auto regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>();
+                    std::stringstream outStream;
+                    if (regionSettings.isPrintFullResultSet()) {
+                        regionCheckResult->writeToStream(outStream);
+                    } else {
+                        regionCheckResult->writeCondensedToStream(outStream);
+                    }
+                    outStream << std::endl;
+                    if (!regionSettings.isPrintNoIllustrationSet()) {
+                        auto const* regionRefinementCheckResult = dynamic_cast<storm::modelchecker::RegionRefinementCheckResult<ValueType> const*>(regionCheckResult);
+                        if (regionRefinementCheckResult != nullptr) {
+                            regionRefinementCheckResult->writeIllustrationToStream(outStream);
+                        }
+                    }
+                    STORM_PRINT_AND_LOG(outStream.str());
+                } else {
+                    STORM_PRINT_AND_LOG(*result);
+                }
+                if (watch) {
+                    STORM_PRINT_AND_LOG("Time for model checking: " << *watch << "." << std::endl);
+                }
+            } else {
+                STORM_PRINT_AND_LOG(" failed, property is unsupported by selected engine/settings." << std::endl);
+            }
+        }
+        
+        template<typename ValueType>
+        void verifyProperties(std::vector<storm::jani::Property> const& properties, std::function<std::unique_ptr<storm::modelchecker::CheckResult>(std::shared_ptr<storm::logic::Formula const> const& formula)> const& verificationCallback, std::function<void(std::unique_ptr<storm::modelchecker::CheckResult> const&)> const& postprocessingCallback) {
+            for (auto const& property : properties) {
+                storm::cli::printModelCheckingProperty(property);
+                storm::utility::Stopwatch watch(true);
+                std::unique_ptr<storm::modelchecker::CheckResult> result = verificationCallback(property.getRawFormula());
+                watch.stop();
+                printInitialStatesResult<ValueType>(result, property, &watch);
+                postprocessingCallback(result);
+            }
+        }
+        
+        template <typename ValueType>
+        void verifyPropertiesWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input) {
+            verifyProperties<ValueType>(input.properties,
+                                        [&model] (std::shared_ptr<storm::logic::Formula const> const& formula) {
+                                            std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithSparseEngine<ValueType>(model, storm::api::createTask<ValueType>(formula, true));
+                                            result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
+                                            return result;
+                                        },
+                                        [&model] (std::unique_ptr<storm::modelchecker::CheckResult> const& result) {
+                                            auto parametricSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>();
+                                            if (parametricSettings.exportResultToFile() && model->isOfType(storm::models::ModelType::Dtmc)) {
+                                                auto dtmc = model->template as<storm::models::sparse::Dtmc<ValueType>>();
+                                                storm::api::exportParametricResultToFile(result->asExplicitQuantitativeCheckResult<ValueType>()[*model->getInitialStates().begin()],storm::analysis::ConstraintCollector<ValueType>(*dtmc), parametricSettings.exportResultPath());
+                                            }
+                                        });
+        }
+        
+        template <typename ValueType>
+        void verifyRegionsWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, std::vector<storm::storage::ParameterRegion<ValueType>> const& regions) {
+            STORM_LOG_ASSERT(!regions.empty(), "Can not analyze an empty set of regions.");
+            
+            auto parametricSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>();
+            auto regionSettings = storm::settings::getModule<storm::settings::modules::RegionSettings>();
+            
+            std::function<std::unique_ptr<storm::modelchecker::CheckResult>(std::shared_ptr<storm::logic::Formula const> const& formula)> verificationCallback;
+            std::function<void(std::unique_ptr<storm::modelchecker::CheckResult> const&)> postprocessingCallback;
+            
+            if (regions.size() == 1) {
+                STORM_PRINT_AND_LOG(std::endl << "Analyzing parameter region " << regions.front());
+            } else {
+                STORM_PRINT_AND_LOG(std::endl << "Analyzing " << regions.size() << " parameter regions");
+            }
+                
+            auto engine = regionSettings.getRegionCheckEngine();
+            STORM_PRINT_AND_LOG(" using " << engine);
+        
+            // Check the given set of regions with or without refinement
+            if (regionSettings.isRefineSet()) {
+                STORM_LOG_THROW(regions.size() == 1, storm::exceptions::NotSupportedException, "Region refinement is not supported for multiple initial regions.");
+                STORM_PRINT_AND_LOG(" with iterative refinement until " << (1.0 - regionSettings.getRefinementThreshold()) * 100.0 << "% is covered." << std::endl);
+                verificationCallback = [&] (std::shared_ptr<storm::logic::Formula const> const& formula) {
+                                        ValueType refinementThreshold = storm::utility::convertNumber<ValueType>(regionSettings.getRefinementThreshold());
+                                        std::unique_ptr<storm::modelchecker::RegionRefinementCheckResult<ValueType>> result = storm::api::checkAndRefineRegionWithSparseEngine<ValueType>(model, storm::api::createTask<ValueType>(formula, true), regions.front(), refinementThreshold, engine);
+                                        return result;
+                                    };
+            } else {
+                STORM_PRINT_AND_LOG("." << std::endl);
+                verificationCallback = [&] (std::shared_ptr<storm::logic::Formula const> const& formula) {
+                                        std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::checkRegionsWithSparseEngine<ValueType>(model, storm::api::createTask<ValueType>(formula, true), regions, engine);
+                                        return result;
+                                    };
+            }
+            
+            postprocessingCallback = [&] (std::unique_ptr<storm::modelchecker::CheckResult> const& result) {
+                                        if (parametricSettings.exportResultToFile()) {
+                                            storm::api::exportRegionCheckResultToFile<ValueType>(result, parametricSettings.exportResultPath());
+                                        }
+                                    };
+            
+            verifyProperties<ValueType>(input.properties, verificationCallback, postprocessingCallback);
+        }
+        
+        template <typename ValueType>
+        void verifyWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, SymbolicInput const& input, std::vector<storm::storage::ParameterRegion<ValueType>> const& regions) {
+            if (regions.empty()) {
+                storm::pars::verifyPropertiesWithSparseEngine(model, input);
+            } else {
+                storm::pars::verifyRegionsWithSparseEngine(model, input, regions);
+            }
+        }
+        
+        template <storm::dd::DdType DdType, typename ValueType>
+        void verifyParametricModel(std::shared_ptr<storm::models::ModelBase> const& model, SymbolicInput const& input, std::vector<storm::storage::ParameterRegion<ValueType>> const& regions) {
+            STORM_LOG_ASSERT(model->isSparseModel(), "Unexpected model type.");
+            storm::pars::verifyWithSparseEngine<ValueType>(model->as<storm::models::sparse::Model<ValueType>>(), input, regions);
+        }
+        
+        template <storm::dd::DdType DdType, typename ValueType>
+        void processInputWithValueTypeAndDdlib(SymbolicInput& input) {
+            auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>();
+            auto ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
+            
+            auto engine = coreSettings.getEngine();
+            STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse || engine == storm::settings::modules::CoreSettings::Engine::Hybrid || engine == storm::settings::modules::CoreSettings::Engine::Dd, storm::exceptions::InvalidSettingsException, "The selected engine is not supported for parametric models.");
+            
+            std::shared_ptr<storm::models::ModelBase> model;
+            if (!ioSettings.isNoBuildModelSet()) {
+                model = storm::pars::buildModel<DdType, ValueType>(engine, input, ioSettings);
+            }
+            
+            if (model) {
+                model->printModelInformationToStream(std::cout);
+            }
+            
+            STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model.");
+            
+            if (model) {
+                auto preprocessingResult = storm::pars::preprocessModel<DdType, ValueType>(model, input);
+                if (preprocessingResult.second) {
+                    model = preprocessingResult.first;
+                    model->printModelInformationToStream(std::cout);
+                }
+            }
+            
+            std::vector<storm::storage::ParameterRegion<ValueType>> regions = parseRegions<ValueType>(model);
+            
+            if (model) {
+                storm::cli::exportModel<DdType, ValueType>(model, input);
+                verifyParametricModel<DdType, ValueType>(model, input, regions);
+            }
+        }
+        
+        void processOptions() {
+            // Start by setting some urgent options (log levels, resources, etc.)
+            storm::cli::setUrgentOptions();
+            
+            // Parse and preprocess symbolic input (PRISM, JANI, properties, etc.)
+            SymbolicInput symbolicInput = storm::cli::parseAndPreprocessSymbolicInput();
+            
+            auto coreSettings = storm::settings::getModule<storm::settings::modules::CoreSettings>();
+            auto engine = coreSettings.getEngine();
+            STORM_LOG_WARN_COND(engine != storm::settings::modules::CoreSettings::Engine::Dd || engine != storm::settings::modules::CoreSettings::Engine::Hybrid || coreSettings.getDdLibraryType() == storm::dd::DdType::Sylvan, "The selected DD library does not support parametric models. Switching to Sylvan...");
+        
+            processInputWithValueTypeAndDdlib<storm::dd::DdType::Sylvan, storm::RationalFunction>(symbolicInput);
+        }
+        
+        int64_t process(const int argc, const char** argv) {
+            storm::utility::setUp();
+            storm::cli::printHeader("Storm-pars", argc, argv);
+            storm::settings::initializeParsSettings("Storm-pars", "storm-pars");
+            
+            storm::utility::Stopwatch totalTimer(true);
+            if (!storm::cli::parseOptions(argc, argv)) {
+                return -1;
+            }
+            
+            processOptions();
+        
+            totalTimer.stop();
+            if (storm::settings::getModule<storm::settings::modules::ResourceSettings>().isPrintTimeAndMemorySet()) {
+                storm::cli::printTimeAndMemoryStatistics(totalTimer.getTimeInMilliseconds());
+            }
+        
+            storm::utility::cleanUp();
+            return 0;
+        }
+    }
+}
+
+
+/*!
+ * Main entry point of the executable storm-pars.
+ */
+int main(const int argc, const char** argv) {
+
+    try {
+        return storm::pars::process(argc, argv);
+    } catch (storm::exceptions::BaseException const& exception) {
+        STORM_LOG_ERROR("An exception caused Storm-pars to terminate. The message of the exception is: " << exception.what());
+        return 1;
+    } catch (std::exception const& exception) {
+        STORM_LOG_ERROR("An unexpected exception occurred and caused Storm-pars to terminate. The message of this exception is: " << exception.what());
+        return 2;
+    }
+}
diff --git a/src/storm-pars/CMakeLists.txt b/src/storm-pars/CMakeLists.txt
new file mode 100644
index 000000000..4e2ec1e0f
--- /dev/null
+++ b/src/storm-pars/CMakeLists.txt
@@ -0,0 +1,40 @@
+file(GLOB_RECURSE ALL_FILES ${PROJECT_SOURCE_DIR}/src/storm-pars/*.h ${PROJECT_SOURCE_DIR}/src/storm-pars/*.cpp)
+
+register_source_groups_from_filestructure("${ALL_FILES}" storm-pars)
+
+
+
+file(GLOB_RECURSE STORM_PARS_SOURCES ${PROJECT_SOURCE_DIR}/src/storm-pars/*/*.cpp)
+file(GLOB_RECURSE STORM_PARS_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-pars/*/*.h)
+
+
+# Create storm-pars.
+add_library(storm-pars SHARED ${STORM_PARS_SOURCES} ${STORM_PARS_HEADERS})
+
+# Remove define symbol for shared libstorm.
+set_target_properties(storm-pars PROPERTIES DEFINE_SYMBOL "")
+#add_dependencies(storm resources)
+list(APPEND STORM_TARGETS storm-pars)
+set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE)
+
+target_link_libraries(storm-pars PUBLIC storm ${STORM_PARS_LINK_LIBRARIES})
+
+# Install storm headers to include directory.
+foreach(HEADER ${STORM_PARS_HEADERS})
+	string(REGEX REPLACE "${PROJECT_SOURCE_DIR}/src/?" "" RELATIVE_HEADER_PATH ${HEADER})
+	string(REGEX MATCH "(.*)[/\\]" RELATIVE_DIRECTORY ${RELATIVE_HEADER_PATH})
+	string(REGEX REPLACE "${RELATIVE_DIRECTORY}/?" "" HEADER_FILENAME ${RELATIVE_HEADER_PATH})
+	add_custom_command(
+		OUTPUT ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME}
+		COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}
+		COMMAND ${CMAKE_COMMAND} -E copy ${HEADER} ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME}
+		DEPENDS ${HEADER}
+	)
+	list(APPEND STORM_PARS_OUTPUT_HEADERS "${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME}")
+endforeach()
+add_custom_target(copy_storm_pars_headers DEPENDS ${STORM_PARS_OUTPUT_HEADERS} ${STORM_PARS_HEADERS})
+add_dependencies(storm-pars copy_storm_pars_headers)
+
+# installation
+install(TARGETS storm-pars RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL)
+
diff --git a/src/storm-pars/api/region.h b/src/storm-pars/api/region.h
new file mode 100644
index 000000000..043f461b0
--- /dev/null
+++ b/src/storm-pars/api/region.h
@@ -0,0 +1,183 @@
+#pragma once
+
+#include <string>
+#include <set>
+#include <vector>
+#include <memory>
+#include <boost/optional.hpp>
+
+#include "storm-pars/modelchecker/results/RegionCheckResult.h"
+#include "storm-pars/modelchecker/results/RegionRefinementCheckResult.h"
+#include "storm-pars/modelchecker/region/RegionCheckEngine.h"
+#include "storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h"
+#include "storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.h"
+#include "storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.h"
+#include "storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.h"
+#include "storm-pars/parser/ParameterRegionParser.h"
+#include "storm-pars/storage/ParameterRegion.h"
+#include "storm-pars/utility/parameterlifting.h"
+
+#include "storm/api/transformation.h"
+#include "storm/utility/file.h"
+#include "storm/models/sparse/Model.h"
+#include "storm/exceptions/UnexpectedException.h"
+#include "storm/exceptions/InvalidOperationException.h"
+#include "storm/exceptions/NotSupportedException.h"
+
+namespace storm {
+    
+    namespace api {
+        
+        template <typename ValueType>
+        std::vector<storm::storage::ParameterRegion<ValueType>> parseRegions(std::string const& inputString, std::set<typename storm::storage::ParameterRegion<ValueType>::VariableType> const& consideredVariables) {
+            // If the given input string looks like a file (containing a dot and there exists a file with that name),
+            // we try to parse it as a file, otherwise we assume it's a region string.
+            if (inputString.find(".") != std::string::npos && std::ifstream(inputString).good()) {
+                return storm::parser::ParameterRegionParser<ValueType>().parseMultipleRegionsFromFile(inputString, consideredVariables);
+            } else {
+                return storm::parser::ParameterRegionParser<ValueType>().parseMultipleRegions(inputString, consideredVariables);
+            }
+        }
+        
+        template <typename ValueType>
+        std::vector<storm::storage::ParameterRegion<ValueType>> parseRegions(std::string const& inputString, storm::models::ModelBase const& model) {
+            std::set<typename storm::storage::ParameterRegion<ValueType>::VariableType> modelParameters;
+            if (model.isSparseModel()) {
+                auto const& sparseModel = dynamic_cast<storm::models::sparse::Model<ValueType> const&>(model);
+                modelParameters = storm::models::sparse::getProbabilityParameters(sparseModel);
+                auto rewParameters = storm::models::sparse::getRewardParameters(sparseModel);
+                modelParameters.insert(rewParameters.begin(), rewParameters.end());
+            } else {
+                STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Retrieving model parameters is not supported for the given model type.");
+            }
+            return parseRegions<ValueType>(inputString, modelParameters);
+        }
+        
+        template <typename ValueType>
+        storm::storage::ParameterRegion<ValueType> parseRegion(std::string const& inputString, std::set<typename storm::storage::ParameterRegion<ValueType>::VariableType> const& consideredVariables) {
+            // Handle the "empty region" case
+            if (inputString == "" && consideredVariables.empty()) {
+                return storm::storage::ParameterRegion<ValueType>();
+            }
+            
+            auto res = parseRegions<ValueType>(inputString, consideredVariables);
+            STORM_LOG_THROW(res.size() == 1, storm::exceptions::InvalidOperationException, "Parsed " << res.size() << " regions but exactly one was expected.");
+            return res.front();
+        }
+        
+        template <typename ValueType>
+        storm::storage::ParameterRegion<ValueType> parseRegion(std::string const& inputString, storm::models::ModelBase const& model) {
+            // Handle the "empty region" case
+            if (inputString == "" && !model.hasParameters()) {
+                return storm::storage::ParameterRegion<ValueType>();
+            }
+            
+            auto res = parseRegions<ValueType>(inputString, model);
+            STORM_LOG_THROW(res.size() == 1, storm::exceptions::InvalidOperationException, "Parsed " << res.size() << " regions but exactly one was expected.");
+            return res.front();
+        }
+        
+        template <typename ParametricType, typename ConstantType>
+        std::unique_ptr<storm::modelchecker::RegionModelChecker<ParametricType>> initializeParameterLiftingRegionModelChecker(std::shared_ptr<storm::models::sparse::Model<ParametricType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ParametricType> const& task) {
+            
+            STORM_LOG_WARN_COND(storm::utility::parameterlifting::validateParameterLiftingSound(*model, task.getFormula()), "Could not validate whether parameter lifting is applicable. Please validate manually...");
+
+            std::shared_ptr<storm::models::sparse::Model<ParametricType>> consideredModel = model;
+            
+            // Treat continuous time models
+            if (consideredModel->isOfType(storm::models::ModelType::Ctmc) || consideredModel->isOfType(storm::models::ModelType::MarkovAutomaton)) {
+                    STORM_LOG_WARN("Parameter lifting not supported for continuous time models. Transforming continuous model to discrete model...");
+                    std::vector<std::shared_ptr<storm::logic::Formula const>> taskFormulaAsVector { task.getFormula().asSharedPointer() };
+                    consideredModel = storm::api::transformContinuousToDiscreteTimeSparseModel(consideredModel, taskFormulaAsVector);
+                    STORM_LOG_THROW(consideredModel->isOfType(storm::models::ModelType::Dtmc) || consideredModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::UnexpectedException, "Transformation to discrete time model has failed.");
+            }
+            
+            // Obtain the region model checker
+            std::unique_ptr<storm::modelchecker::RegionModelChecker<ParametricType>> result;
+            if (consideredModel->isOfType(storm::models::ModelType::Dtmc)) {
+                result = std::make_unique<storm::modelchecker::SparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<ParametricType>, ConstantType>>();
+            } else if (consideredModel->isOfType(storm::models::ModelType::Mdp)) {
+                result = std::make_unique<storm::modelchecker::SparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<ParametricType>, ConstantType>>();
+            } else {
+                STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform parameterLifting on the provided model type.");
+            }
+            
+            result->specify(consideredModel, task);
+            
+            return result;
+        }
+        
+        template <typename ParametricType, typename ImpreciseType, typename PreciseType>
+        std::unique_ptr<storm::modelchecker::RegionModelChecker<ParametricType>> initializeValidatingRegionModelChecker(std::shared_ptr<storm::models::sparse::Model<ParametricType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ParametricType> const& task) {
+            
+            STORM_LOG_WARN_COND(storm::utility::parameterlifting::validateParameterLiftingSound(*model, task.getFormula()), "Could not validate whether parameter lifting is applicable. Please validate manually...");
+
+            std::shared_ptr<storm::models::sparse::Model<ParametricType>> consideredModel = model;
+            
+            // Treat continuous time models
+            if (consideredModel->isOfType(storm::models::ModelType::Ctmc) || consideredModel->isOfType(storm::models::ModelType::MarkovAutomaton)) {
+                    STORM_LOG_WARN("Parameter lifting not supported for continuous time models. Transforming continuous model to discrete model...");
+                    std::vector<std::shared_ptr<storm::logic::Formula const>> taskFormulaAsVector { task.getFormula().asSharedPointer() };
+                    consideredModel = storm::api::transformContinuousToDiscreteTimeSparseModel(consideredModel, taskFormulaAsVector);
+                    STORM_LOG_THROW(consideredModel->isOfType(storm::models::ModelType::Dtmc) || consideredModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::UnexpectedException, "Transformation to discrete time model has failed.");
+            }
+            
+            // Obtain the region model checker
+            std::unique_ptr<storm::modelchecker::RegionModelChecker<ParametricType>> result;
+            if (consideredModel->isOfType(storm::models::ModelType::Dtmc)) {
+                result = std::make_unique<storm::modelchecker::ValidatingSparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<ParametricType>, ImpreciseType, PreciseType>>();
+            } else if (consideredModel->isOfType(storm::models::ModelType::Mdp)) {
+                result = std::make_unique<storm::modelchecker::ValidatingSparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<ParametricType>, ImpreciseType, PreciseType>>();
+            } else {
+                STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform parameterLifting on the provided model type.");
+            }
+            
+            result->specify(consideredModel, task);
+            
+            return result;
+        }
+        
+        template <typename ValueType>
+        std::unique_ptr<storm::modelchecker::RegionModelChecker<ValueType>> initializeRegionModelChecker(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task, storm::modelchecker::RegionCheckEngine engine) {
+            switch (engine) {
+                    case storm::modelchecker::RegionCheckEngine::ParameterLifting:
+                            return initializeParameterLiftingRegionModelChecker<ValueType, double>(model, task);
+                    case storm::modelchecker::RegionCheckEngine::ExactParameterLifting:
+                            return initializeParameterLiftingRegionModelChecker<ValueType, storm::RationalNumber>(model, task);
+                    case storm::modelchecker::RegionCheckEngine::ValidatingParameterLifting:
+                            return initializeValidatingRegionModelChecker<ValueType, double, storm::RationalNumber>(model, task);
+                    default:
+                            STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unexpected region model checker type.");
+            }
+            return nullptr;
+        }
+        
+        template <typename ValueType>
+        std::unique_ptr<storm::modelchecker::RegionCheckResult<ValueType>> checkRegionsWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task, std::vector<storm::storage::ParameterRegion<ValueType>> const& regions, storm::modelchecker::RegionCheckEngine engine) {
+            auto regionChecker = initializeRegionModelChecker(model, task, engine);
+            return regionChecker->analyzeRegions(regions, true);
+        }
+    
+        
+        template <typename ValueType>
+        std::unique_ptr<storm::modelchecker::RegionRefinementCheckResult<ValueType>> checkAndRefineRegionWithSparseEngine(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task, storm::storage::ParameterRegion<ValueType> const& region, ValueType const& refinementThreshold, storm::modelchecker::RegionCheckEngine engine) {
+            auto regionChecker = initializeRegionModelChecker(model, task, engine);
+            return regionChecker->performRegionRefinement(region, refinementThreshold);
+        }
+        
+
+        template <typename ValueType>
+        void exportRegionCheckResultToFile(std::unique_ptr<storm::modelchecker::CheckResult> const& checkResult, std::string const& filename) {
+
+            auto const* regionCheckResult = dynamic_cast<storm::modelchecker::RegionCheckResult<ValueType> const*>(checkResult.get());
+            STORM_LOG_THROW(regionCheckResult != nullptr, storm::exceptions::UnexpectedException, "Can not export region check result: The given checkresult does not have the expected type.");
+            
+            std::ofstream filestream;
+            storm::utility::openFile(filename, filestream);
+            for (auto const& res : regionCheckResult->getRegionResults()) {
+                    filestream << res.second << ": " << res.first << std::endl;
+            }
+        }
+    
+    }
+}
diff --git a/src/storm-pars/api/storm-pars.h b/src/storm-pars/api/storm-pars.h
new file mode 100644
index 000000000..42ac7dc79
--- /dev/null
+++ b/src/storm-pars/api/storm-pars.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include "storm-pars/api/region.h"
diff --git a/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp b/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp
new file mode 100644
index 000000000..14d433e58
--- /dev/null
+++ b/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp
@@ -0,0 +1,147 @@
+#include "storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.h"
+
+#include "storm/logic/FragmentSpecification.h"
+#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
+#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
+#include "storm/modelchecker/hints/ExplicitModelCheckerHint.h"
+#include "storm/utility/vector.h"
+
+#include "storm/exceptions/InvalidArgumentException.h"
+#include "storm/exceptions/InvalidStateException.h"
+namespace storm {
+    namespace modelchecker {
+        
+        template <typename SparseModelType, typename ConstantType>
+        SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::SparseDtmcInstantiationModelChecker(SparseModelType const& parametricModel) : SparseInstantiationModelChecker<SparseModelType, ConstantType>(parametricModel), modelInstantiator(parametricModel) {
+            //Intentionally left empty
+        }
+
+        template <typename SparseModelType, typename ConstantType>
+        std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) {
+            STORM_LOG_THROW(this->currentCheckTask, storm::exceptions::InvalidStateException, "Checking has been invoked but no property has been specified before.");
+            auto const& instantiatedModel = modelInstantiator.instantiate(valuation);
+            STORM_LOG_ASSERT(instantiatedModel.getTransitionMatrix().isProbabilistic(), "Instantiated matrix is not probabilistic!");
+            storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>> modelChecker(instantiatedModel);
+
+            // Check if there are some optimizations implemented for the specified property
+            if(this->currentCheckTask->getFormula().isInFragment(storm::logic::reachability())) {
+                return checkReachabilityProbabilityFormula(modelChecker);
+            } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) {
+                return checkReachabilityRewardFormula(modelChecker);
+            } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setProbabilityOperatorsAllowed(true).setBoundedUntilFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) {
+                return checkBoundedUntilFormula(modelChecker);
+            } else {
+                return modelChecker.check(*this->currentCheckTask);
+            }
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityProbabilityFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker) {
+            
+            if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) {
+                this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>());
+            }
+            ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>();
+            std::unique_ptr<CheckResult> result;
+            
+            // Check the formula and store the result as a hint for the next call.
+            // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula
+            if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) {
+                result = modelChecker.check(*this->currentCheckTask);
+                hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector());
+            } else {
+                auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false);
+                std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask);
+                result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
+                hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()));
+            }
+            
+            if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) {
+                // Extract the maybe states from the current result.
+                assert(hint.hasResultHint());
+                storm::storage::BitVector maybeStates = ~storm::utility::vector::filter<ConstantType>(hint.getResultHint(),
+                                [] (ConstantType const& value) -> bool { return storm::utility::isZero<ConstantType>(value) || storm::utility::isOne<ConstantType>(value); });
+                hint.setMaybeStates(std::move(maybeStates));
+                hint.setComputeOnlyMaybeStates(true);
+            }
+            
+            return result;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityRewardFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker) {
+            
+            if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) {
+                this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>());
+            }
+            ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>();
+            std::unique_ptr<CheckResult> result;
+            
+            // Check the formula and store the result as a hint for the next call.
+            // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula
+            if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) {
+                result = modelChecker.check(*this->currentCheckTask);
+                this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>().setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector());
+            } else {
+                auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false);
+                std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeRewards(this->currentCheckTask->getFormula().asRewardOperatorFormula().getMeasureType(), newCheckTask);
+                result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
+                this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>().setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()));
+            }
+            
+            if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) {
+                // Extract the maybe states from the current result.
+                assert(hint.hasResultHint());
+                storm::storage::BitVector maybeStates = ~storm::utility::vector::filterInfinity(hint.getResultHint());
+                // We need to exclude the target states from the maybe states.
+                // Note that we can not consider the states with reward zero since a valuation might set a reward to zero
+                std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asEventuallyFormula().getSubformula());
+                maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector());
+                hint.setMaybeStates(std::move(maybeStates));
+                hint.setComputeOnlyMaybeStates(true);
+            }
+            
+            return result;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::checkBoundedUntilFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker) {
+            
+            if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) {
+                this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>());
+            }
+            std::unique_ptr<CheckResult> result;
+            ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>();
+            
+            if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) {
+                // We extract the maybestates from the quantitative result
+                // For qualitative properties, we still need a quantitative result. Hence we perform the check on the subformula
+                if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) {
+                    result = modelChecker.check(*this->currentCheckTask);
+                    hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector());
+                } else {
+                    auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false);
+                    std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask);
+                    result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
+                    hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()));
+                }
+                
+                storm::storage::BitVector maybeStates = storm::utility::vector::filterGreaterZero(hint.getResultHint());
+                // We need to exclude the target states from the maybe states.
+                // Note that we can not consider the states with probability one since a state might reach a target state with prob 1 within >0 steps
+                std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asBoundedUntilFormula().getRightSubformula());
+                maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector());
+                hint.setMaybeStates(std::move(maybeStates));
+                hint.setComputeOnlyMaybeStates(true);
+            } else {
+                result = modelChecker.check(*this->currentCheckTask);
+            }
+            
+            return result;
+        }
+        
+        template class SparseDtmcInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>;
+        template class SparseDtmcInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>;
+
+    }
+}
\ No newline at end of file
diff --git a/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.h b/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.h
new file mode 100644
index 000000000..ad1ffead4
--- /dev/null
+++ b/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <memory>
+#include <boost/optional.hpp>
+
+#include "storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h"
+#include "storm-pars/utility/ModelInstantiator.h"
+#include "storm/models/sparse/Dtmc.h"
+#include "storm/models/sparse/StandardRewardModel.h"
+#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h"
+
+namespace storm {
+    namespace modelchecker {
+        
+        /*!
+         * Class to efficiently check a formula on a parametric model with different parameter instantiations
+         */
+        template <typename SparseModelType, typename ConstantType>
+        class SparseDtmcInstantiationModelChecker : public SparseInstantiationModelChecker<SparseModelType, ConstantType> {
+        public:
+            SparseDtmcInstantiationModelChecker(SparseModelType const& parametricModel);
+            
+            virtual std::unique_ptr<CheckResult> check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) override;
+
+        protected:
+            
+            // Optimizations for the different formula types
+            std::unique_ptr<CheckResult> checkReachabilityProbabilityFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker);
+            std::unique_ptr<CheckResult> checkReachabilityRewardFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker);
+            std::unique_ptr<CheckResult> checkBoundedUntilFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker);
+            
+            storm::utility::ModelInstantiator<SparseModelType, storm::models::sparse::Dtmc<ConstantType>> modelInstantiator;
+        };
+    }
+}
diff --git a/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp b/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp
new file mode 100644
index 000000000..d81d5b9a6
--- /dev/null
+++ b/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp
@@ -0,0 +1,42 @@
+#include "storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h"
+
+#include "storm/adapters/RationalFunctionAdapter.h"
+#include "storm/models/sparse/Dtmc.h"
+#include "storm/models/sparse/Mdp.h"
+#include "storm/models/sparse/StandardRewardModel.h"
+
+#include "storm/exceptions/InvalidArgumentException.h"
+
+namespace storm {
+    namespace modelchecker {
+        
+        template <typename SparseModelType, typename ConstantType>
+        SparseInstantiationModelChecker<SparseModelType, ConstantType>::SparseInstantiationModelChecker(SparseModelType const& parametricModel) : parametricModel(parametricModel), instantiationsAreGraphPreserving(false) {
+            //Intentionally left empty
+        }
+        
+        
+        template <typename SparseModelType, typename ConstantType>
+        void SparseInstantiationModelChecker<SparseModelType, ConstantType>::specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) {
+            currentFormula = checkTask.getFormula().asSharedPointer();
+            currentCheckTask = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, ConstantType>>(checkTask.substituteFormula(*currentFormula).template convertValueType<ConstantType>());
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        void SparseInstantiationModelChecker<SparseModelType, ConstantType>::setInstantiationsAreGraphPreserving(bool value) {
+            instantiationsAreGraphPreserving = value;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        bool SparseInstantiationModelChecker<SparseModelType, ConstantType>::getInstantiationsAreGraphPreserving() const {
+            return instantiationsAreGraphPreserving;
+        }
+        
+        template class SparseInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>;
+        template class SparseInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>;
+        
+        template class SparseInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>;
+        template class SparseInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>;
+
+    }
+}
diff --git a/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h b/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h
new file mode 100644
index 000000000..43ed587ec
--- /dev/null
+++ b/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "storm-pars/utility/parametric.h"
+#include "storm/logic/Formulas.h"
+#include "storm/modelchecker/CheckTask.h"
+#include "storm/modelchecker/results/CheckResult.h"
+#include "storm/modelchecker/hints/ModelCheckerHint.h"
+
+namespace storm {
+    namespace modelchecker {
+        
+        /*!
+         * Class to efficiently check a formula on a parametric model with different parameter instantiations
+         */
+        template <typename SparseModelType, typename ConstantType>
+        class SparseInstantiationModelChecker {
+        public:
+            SparseInstantiationModelChecker(SparseModelType const& parametricModel);
+            virtual ~SparseInstantiationModelChecker() = default;
+            
+            void specifyFormula(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask);
+            
+            virtual std::unique_ptr<CheckResult> check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) = 0;
+            
+            // If set, it is assumed that all considered model instantiations have the same underlying graph structure.
+            // This bypasses the graph analysis for the different instantiations.
+            void setInstantiationsAreGraphPreserving(bool value);
+            bool getInstantiationsAreGraphPreserving() const;
+            
+        protected:
+            
+            SparseModelType const& parametricModel;
+            std::unique_ptr<CheckTask<storm::logic::Formula, ConstantType>> currentCheckTask;
+            
+        private:
+            // store the current formula. Note that currentCheckTask only stores a reference to the formula.
+            std::shared_ptr<storm::logic::Formula const> currentFormula;
+
+            bool instantiationsAreGraphPreserving;
+        };
+    }
+}
diff --git a/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp b/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp
new file mode 100644
index 000000000..887d3b7bf
--- /dev/null
+++ b/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp
@@ -0,0 +1,171 @@
+#include "storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.h"
+
+#include "storm/logic/FragmentSpecification.h"
+#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
+#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
+#include "storm/modelchecker/hints/ExplicitModelCheckerHint.h"
+#include "storm/storage/Scheduler.h"
+#include "storm/utility/graph.h"
+#include "storm/utility/vector.h"
+
+#include "storm/exceptions/InvalidArgumentException.h"
+#include "storm/exceptions/InvalidStateException.h"
+
+namespace storm {
+    namespace modelchecker {
+        
+        template <typename SparseModelType, typename ConstantType>
+        SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::SparseMdpInstantiationModelChecker(SparseModelType const& parametricModel) : SparseInstantiationModelChecker<SparseModelType, ConstantType>(parametricModel), modelInstantiator(parametricModel) {
+            //Intentionally left empty
+        }
+
+       template <typename SparseModelType, typename ConstantType>
+        std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) {
+            STORM_LOG_THROW(this->currentCheckTask, storm::exceptions::InvalidStateException, "Checking has been invoked but no property has been specified before.");
+            auto const& instantiatedModel = modelInstantiator.instantiate(valuation);
+            STORM_LOG_ASSERT(instantiatedModel.getTransitionMatrix().isProbabilistic(), "Instantiated matrix is not probabilistic!");
+            storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>> modelChecker(instantiatedModel);
+
+            // Check if there are some optimizations implemented for the specified property
+            if(this->currentCheckTask->getFormula().isInFragment(storm::logic::reachability())) {
+                return checkReachabilityProbabilityFormula(modelChecker, instantiatedModel);
+            } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) {
+                return checkReachabilityRewardFormula(modelChecker, instantiatedModel);
+            } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setProbabilityOperatorsAllowed(true).setBoundedUntilFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) {
+                return checkBoundedUntilFormula(modelChecker);
+            } else {
+                return modelChecker.check(*this->currentCheckTask);
+            }
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityProbabilityFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel) {
+            
+            this->currentCheckTask->setProduceSchedulers(true);
+            
+            if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) {
+                this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>());
+            }
+            ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>();
+            std::unique_ptr<CheckResult> result;
+            
+            // Check the formula and store the result as a hint for the next call.
+            // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula
+            if(this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) {
+                result = modelChecker.check(*this->currentCheckTask);
+                storm::storage::Scheduler<ConstantType> const& scheduler = result->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
+                hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector());
+                hint.setSchedulerHint(dynamic_cast<storm::storage::Scheduler<ConstantType> const&>(scheduler));
+            } else {
+                auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false);
+                std::unique_ptr<storm::modelchecker::CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask);
+                result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
+                storm::storage::Scheduler<ConstantType>& scheduler = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
+                hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()));
+                hint.setSchedulerHint(std::move(dynamic_cast<storm::storage::Scheduler<ConstantType>&>(scheduler)));
+            }
+            
+            if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) {
+                // Extract the maybe states from the current result.
+                assert(hint.hasResultHint());
+                storm::storage::BitVector maybeStates = ~storm::utility::vector::filter<ConstantType>(hint.getResultHint(),
+                                [] (ConstantType const& value) -> bool { return storm::utility::isZero<ConstantType>(value) || storm::utility::isOne<ConstantType>(value); });
+                hint.setMaybeStates(std::move(maybeStates));
+                hint.setComputeOnlyMaybeStates(true);
+                
+                // Check if there can be end components within the maybestates
+                if (storm::solver::minimize(this->currentCheckTask->getOptimizationDirection()) ||
+                storm::utility::graph::performProb1A(instantiatedModel.getTransitionMatrix(), instantiatedModel.getTransitionMatrix().getRowGroupIndices(), instantiatedModel.getBackwardTransitions(), hint.getMaybeStates(), ~hint.getMaybeStates()).full()) {
+                    hint.setNoEndComponentsInMaybeStates(true);
+                }
+            }
+            
+            return result;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityRewardFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel) {
+            
+            this->currentCheckTask->setProduceSchedulers(true);
+            
+            if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) {
+                this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>());
+            }
+            ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>();
+            std::unique_ptr<CheckResult> result;
+            
+            // Check the formula and store the result as a hint for the next call.
+            // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula
+            if(this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) {
+                std::unique_ptr<storm::modelchecker::CheckResult> result = modelChecker.check(*this->currentCheckTask);
+                storm::storage::Scheduler<ConstantType> const& scheduler = result->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
+                hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector());
+                hint.setSchedulerHint(dynamic_cast<storm::storage::Scheduler<ConstantType> const&>(scheduler));
+            } else {
+                auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false);
+                std::unique_ptr<storm::modelchecker::CheckResult> quantitativeResult = modelChecker.computeRewards(this->currentCheckTask->getFormula().asRewardOperatorFormula().getMeasureType(), newCheckTask);
+                result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
+                storm::storage::Scheduler<ConstantType>& scheduler = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
+                hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()));
+                hint.setSchedulerHint(std::move(dynamic_cast<storm::storage::Scheduler<ConstantType>&>(scheduler)));
+            }
+            
+            if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) {
+                // Extract the maybe states from the current result.
+                assert(hint.hasResultHint());
+                storm::storage::BitVector maybeStates = ~storm::utility::vector::filterInfinity(hint.getResultHint());
+                // We need to exclude the target states from the maybe states.
+                // Note that we can not consider the states with reward zero since a valuation might set a reward to zero
+                std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asEventuallyFormula().getSubformula());
+                maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector());
+                hint.setMaybeStates(std::move(maybeStates));
+                hint.setComputeOnlyMaybeStates(true);
+                
+                // Check if there can be end components within the maybestates
+                if (storm::solver::maximize(this->currentCheckTask->getOptimizationDirection()) ||
+                storm::utility::graph::performProb1A(instantiatedModel.getTransitionMatrix(), instantiatedModel.getTransitionMatrix().getRowGroupIndices(), instantiatedModel.getBackwardTransitions(), hint.getMaybeStates(), ~hint.getMaybeStates()).full()) {
+                    hint.setNoEndComponentsInMaybeStates(true);
+                }
+            }
+            return result;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::checkBoundedUntilFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker) {
+            
+            if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) {
+                this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>());
+            }
+            std::unique_ptr<CheckResult> result;
+            ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>();
+            
+            if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) {
+                // We extract the maybestates from the quantitative result
+                // For qualitative properties, we still need a quantitative result. Hence we perform the check on the subformula
+                if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) {
+                    result = modelChecker.check(*this->currentCheckTask);
+                    hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector());
+                } else {
+                    auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false);
+                    std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask);
+                    result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
+                    hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()));
+                }
+                storm::storage::BitVector maybeStates = storm::utility::vector::filterGreaterZero(hint.getResultHint());
+                // We need to exclude the target states from the maybe states.
+                // Note that we can not consider the states with probability one since a state might reach a target state with prob 1 within >0 steps
+                std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asBoundedUntilFormula().getRightSubformula());
+                maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector());
+                hint.setMaybeStates(std::move(maybeStates));
+                hint.setComputeOnlyMaybeStates(true);
+            } else {
+                result = modelChecker.check(*this->currentCheckTask);
+            }
+            return result;
+        }
+        
+        template class SparseMdpInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>;
+        template class SparseMdpInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>;
+
+    }
+}
diff --git a/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.h b/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.h
new file mode 100644
index 000000000..d8d5d46e8
--- /dev/null
+++ b/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <memory>
+
+#include "storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h"
+#include "storm-pars/utility/ModelInstantiator.h"
+#include "storm/models/sparse/Mdp.h"
+#include "storm/models/sparse/Dtmc.h"
+#include "storm/models/sparse/StandardRewardModel.h"
+#include "storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h"
+
+namespace storm {
+    namespace modelchecker {
+        
+        /*!
+         * Class to efficiently check a formula on a parametric model with different parameter instantiations
+         */
+        template <typename SparseModelType, typename ConstantType>
+        class SparseMdpInstantiationModelChecker : public SparseInstantiationModelChecker<SparseModelType, ConstantType> {
+        public:
+            SparseMdpInstantiationModelChecker(SparseModelType const& parametricModel);
+            
+            virtual std::unique_ptr<CheckResult> check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) override;
+
+        protected:
+            // Optimizations for the different formula types
+            std::unique_ptr<CheckResult> checkReachabilityProbabilityFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel);
+            std::unique_ptr<CheckResult> checkReachabilityRewardFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel);
+            std::unique_ptr<CheckResult> checkBoundedUntilFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker);
+            
+            storm::utility::ModelInstantiator<SparseModelType, storm::models::sparse::Mdp<ConstantType>> modelInstantiator;
+        };
+    }
+}
diff --git a/src/storm-pars/modelchecker/region/RegionCheckEngine.cpp b/src/storm-pars/modelchecker/region/RegionCheckEngine.cpp
new file mode 100644
index 000000000..e23be1eb1
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/RegionCheckEngine.cpp
@@ -0,0 +1,25 @@
+#include "storm-pars/modelchecker/region/RegionCheckEngine.h"
+
+#include "storm/utility/macros.h"
+#include "storm/exceptions/NotImplementedException.h"
+
+namespace storm {
+    namespace modelchecker {
+        std::ostream& operator<<(std::ostream& os, RegionCheckEngine const& e) {
+            switch (e) {
+                case RegionCheckEngine::ParameterLifting:
+                    os << "Parameter Lifting";
+                    break;
+                case RegionCheckEngine::ExactParameterLifting:
+                    os << "Exact Parameter Lifting";
+                    break;
+                case RegionCheckEngine::ValidatingParameterLifting:
+                    os << "Validating Parameter Lifting";
+                    break;
+                default:
+                    STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Could not get a string from the region check engine. The case has not been implemented");
+            }
+            return os;
+        }
+    }
+}
diff --git a/src/storm-pars/modelchecker/region/RegionCheckEngine.h b/src/storm-pars/modelchecker/region/RegionCheckEngine.h
new file mode 100644
index 000000000..5ff26d691
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/RegionCheckEngine.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <ostream>
+
+namespace storm {
+    namespace modelchecker {
+        /*!
+         * The considered engine for region checking
+         */
+        enum class RegionCheckEngine {
+            ParameterLifting, /*!< Parameter lifting approach */
+            ExactParameterLifting, /*!< Parameter lifting approach with exact arithmethics*/
+            ValidatingParameterLifting, /*!< Parameter lifting approach with a) inexact (and fast) computation first and b) exact validation of obtained results second */
+        };
+        
+        std::ostream& operator<<(std::ostream& os, RegionCheckEngine const& regionCheckResult);
+    }
+}
+
diff --git a/src/storm-pars/modelchecker/region/RegionModelChecker.cpp b/src/storm-pars/modelchecker/region/RegionModelChecker.cpp
new file mode 100644
index 000000000..a2a19451d
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/RegionModelChecker.cpp
@@ -0,0 +1,130 @@
+#include <sstream>
+#include <queue>
+
+#include "storm-pars/modelchecker/region/RegionModelChecker.h"
+
+#include "storm/adapters/RationalFunctionAdapter.h"
+
+
+#include "storm/utility/vector.h"
+#include "storm/models/sparse/StandardRewardModel.h"
+#include "storm/models/sparse/Dtmc.h"
+#include "storm/models/sparse/Mdp.h"
+
+#include "storm/exceptions/NotSupportedException.h"
+#include "storm/exceptions/InvalidStateException.h"
+#include "storm/exceptions/InvalidArgumentException.h"
+
+#include "storm/settings/SettingsManager.h"
+#include "storm/settings/modules/CoreSettings.h"
+
+
+namespace storm {
+    namespace modelchecker {
+
+            template <typename ParametricType>
+            RegionModelChecker<ParametricType>::RegionModelChecker() {
+                // Intentionally left empty
+            }
+        
+            template <typename ParametricType>
+            std::unique_ptr<storm::modelchecker::RegionCheckResult<ParametricType>> RegionModelChecker<ParametricType>::analyzeRegions(std::vector<storm::storage::ParameterRegion<ParametricType>> const& regions, bool sampleVerticesOfRegion) {
+                
+                std::vector<std::pair<storm::storage::ParameterRegion<ParametricType>, storm::modelchecker::RegionResult>> result;
+                
+                for (auto const& region : regions) {
+                    storm::modelchecker::RegionResult regionRes = analyzeRegion(region, storm::modelchecker::RegionResult::Unknown, sampleVerticesOfRegion);
+                    result.emplace_back(region, regionRes);
+                }
+                
+                return std::make_unique<storm::modelchecker::RegionCheckResult<ParametricType>>(std::move(result));
+            }
+
+            template <typename ParametricType>
+            std::unique_ptr<storm::modelchecker::RegionRefinementCheckResult<ParametricType>> RegionModelChecker<ParametricType>::performRegionRefinement(storm::storage::ParameterRegion<ParametricType> const& region, ParametricType const& threshold) {
+                STORM_LOG_INFO("Applying refinement on region: " << region.toString(true) << " .");
+                
+                auto thresholdAsCoefficient = storm::utility::convertNumber<CoefficientType>(threshold);
+                auto areaOfParameterSpace = region.area();
+                auto fractionOfUndiscoveredArea = storm::utility::one<CoefficientType>();
+                auto fractionOfAllSatArea = storm::utility::zero<CoefficientType>();
+                auto fractionOfAllViolatedArea = storm::utility::zero<CoefficientType>();
+                
+                std::queue<std::pair<storm::storage::ParameterRegion<ParametricType>, RegionResult>> unprocessedRegions;
+                std::vector<std::pair<storm::storage::ParameterRegion<ParametricType>, RegionResult>> result;
+                unprocessedRegions.emplace(region, RegionResult::Unknown);
+                uint_fast64_t numOfAnalyzedRegions = 0;
+                CoefficientType displayedProgress = storm::utility::zero<CoefficientType>();
+                if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) {
+                    STORM_PRINT_AND_LOG("Progress (solved fraction) :" << std::endl <<  "0% [");
+                    while (displayedProgress < storm::utility::one<CoefficientType>() - thresholdAsCoefficient) {
+                        STORM_PRINT_AND_LOG(" ");
+                        displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
+                    }
+                    while (displayedProgress < storm::utility::one<CoefficientType>()) {
+                        STORM_PRINT_AND_LOG("-");
+                        displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
+                    }
+                    STORM_PRINT_AND_LOG("] 100%" << std::endl << "   [");
+                    displayedProgress = storm::utility::zero<CoefficientType>();
+                }
+
+                while (fractionOfUndiscoveredArea > thresholdAsCoefficient) {
+                    STORM_LOG_THROW(!unprocessedRegions.empty(), storm::exceptions::InvalidStateException, "Threshold for undiscovered area not reached but no unprocessed regions left.");
+                    STORM_LOG_INFO("Analyzing region #" << numOfAnalyzedRegions << " (" << storm::utility::convertNumber<double>(fractionOfUndiscoveredArea) * 100 << "% still unknown)");
+                    auto& currentRegion = unprocessedRegions.front().first;
+                    auto& res = unprocessedRegions.front().second;
+                    res = analyzeRegion(currentRegion, res, false);
+                    switch (res) {
+                        case RegionResult::AllSat:
+                            fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace;
+                            fractionOfAllSatArea += currentRegion.area() / areaOfParameterSpace;
+                            result.push_back(std::move(unprocessedRegions.front()));
+                            break;
+                        case RegionResult::AllViolated:
+                            fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace;
+                            fractionOfAllViolatedArea += currentRegion.area() / areaOfParameterSpace;
+                            result.push_back(std::move(unprocessedRegions.front()));
+                            break;
+                        default:
+                            std::vector<storm::storage::ParameterRegion<ParametricType>> newRegions;
+                            currentRegion.split(currentRegion.getCenterPoint(), newRegions);
+                            RegionResult initResForNewRegions = (res == RegionResult::CenterSat) ? RegionResult::ExistsSat :
+                                                                     ((res == RegionResult::CenterViolated) ? RegionResult::ExistsViolated :
+                                                                      RegionResult::Unknown);
+                            for(auto& newRegion : newRegions) {
+                                unprocessedRegions.emplace(std::move(newRegion), initResForNewRegions);
+                            }
+                            break;
+                    }
+                    ++numOfAnalyzedRegions;
+                    unprocessedRegions.pop();
+                    if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) {
+                        while (displayedProgress < storm::utility::one<CoefficientType>() - fractionOfUndiscoveredArea) {
+                            STORM_PRINT_AND_LOG("#");
+                            displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
+                        }
+                    }
+                }
+                
+                if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) {
+                    while (displayedProgress < storm::utility::one<CoefficientType>()) {
+                        STORM_PRINT_AND_LOG("-");
+                        displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
+                    }
+                    STORM_PRINT_AND_LOG("]" << std::endl);
+                    
+                    STORM_PRINT_AND_LOG("Region Refinement Statistics:" << std::endl);
+                    STORM_PRINT_AND_LOG("    Analyzed a total of " << numOfAnalyzedRegions << " regions." << std::endl);
+                }
+                
+                auto regionCopyForResult = region;
+                return std::make_unique<storm::modelchecker::RegionRefinementCheckResult<ParametricType>>(std::move(result), std::move(regionCopyForResult));
+            }
+    
+#ifdef STORM_HAVE_CARL
+            template class RegionModelChecker<storm::RationalFunction>;
+#endif
+    } //namespace modelchecker
+} //namespace storm
+
diff --git a/src/storm-pars/modelchecker/region/RegionModelChecker.h b/src/storm-pars/modelchecker/region/RegionModelChecker.h
new file mode 100644
index 000000000..a8f1fdf01
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/RegionModelChecker.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <memory>
+
+#include "storm-pars/modelchecker/results/RegionCheckResult.h"
+#include "storm-pars/modelchecker/results/RegionRefinementCheckResult.h"
+#include "storm-pars/modelchecker/region/RegionResult.h"
+#include "storm-pars/storage/ParameterRegion.h"
+
+#include "storm/models/ModelBase.h"
+#include "storm/modelchecker/CheckTask.h"
+
+namespace storm {
+    namespace modelchecker{
+        
+        template<typename ParametricType>
+        class RegionModelChecker {
+        public:
+            
+            typedef typename storm::storage::ParameterRegion<ParametricType>::CoefficientType CoefficientType;
+
+            RegionModelChecker();
+            virtual ~RegionModelChecker() = default;
+            
+            virtual bool canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, ParametricType> const& checkTask) const = 0;
+            virtual void specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, ParametricType> const& checkTask) = 0;
+            
+            /*!
+             * Analyzes the given region.
+             * An initial region result can be given to simplify the analysis (e.g. if the initial result is ExistsSat, we do not check for AllViolated).
+             * If supported by this model checker, it is possible to sample the vertices of the region whenever AllSat/AllViolated could not be shown.
+             */
+            virtual RegionResult analyzeRegion(storm::storage::ParameterRegion<ParametricType> const& region, RegionResult const& initialResult = RegionResult::Unknown, bool sampleVerticesOfRegion = false) = 0;
+            
+             /*!
+             * Analyzes the given regions.
+             * If supported by this model checker, it is possible to sample the vertices of the regions whenever AllSat/AllViolated could not be shown.
+             */
+            std::unique_ptr<storm::modelchecker::RegionCheckResult<ParametricType>> analyzeRegions(std::vector<storm::storage::ParameterRegion<ParametricType>> const& regions, bool sampleVerticesOfRegion = false) ;
+            
+            /*!
+             * Iteratively refines the region until the region analysis yields a conclusive result (AllSat or AllViolated).
+             * The refinement stops as soon as the fraction of the area of the subregions with inconclusive result is less then the given threshold
+             */
+            std::unique_ptr<storm::modelchecker::RegionRefinementCheckResult<ParametricType>> performRegionRefinement(storm::storage::ParameterRegion<ParametricType> const& region, ParametricType const& threshold);
+            
+        };
+
+    } //namespace modelchecker
+} //namespace storm
diff --git a/src/storm-pars/modelchecker/region/RegionResult.cpp b/src/storm-pars/modelchecker/region/RegionResult.cpp
new file mode 100644
index 000000000..0da22a028
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/RegionResult.cpp
@@ -0,0 +1,40 @@
+#include "storm-pars/modelchecker/region/RegionResult.h"
+
+#include "storm/utility/macros.h"
+#include "storm/exceptions/NotImplementedException.h"
+
+namespace storm {
+    namespace modelchecker {
+        std::ostream& operator<<(std::ostream& os, RegionResult const& regionResult) {
+            switch (regionResult) {
+                case RegionResult::Unknown:
+                    os << "Unknown";
+                    break;
+                case RegionResult::ExistsSat:
+                    os << "ExistsSat";
+                    break;
+                case RegionResult::ExistsViolated:
+                    os << "ExistsViolated";
+                    break;
+                case RegionResult::CenterSat:
+                    os << "CenterSat";
+                    break;
+                case RegionResult::CenterViolated:
+                    os << "CenterViolated";
+                    break;
+                case RegionResult::ExistsBoth:
+                    os << "ExistsBoth";
+                    break;
+                case RegionResult::AllSat:
+                    os << "AllSat";
+                    break;
+                case RegionResult::AllViolated:
+                    os << "AllViolated";
+                    break;
+                default:
+                    STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Could not get a string from the region check result. The case has not been implemented");
+            }
+            return os;
+        }
+    }
+}
diff --git a/src/storm-pars/modelchecker/region/RegionResult.h b/src/storm-pars/modelchecker/region/RegionResult.h
new file mode 100644
index 000000000..1ad568f87
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/RegionResult.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <ostream>
+
+namespace storm {
+    namespace modelchecker {
+        /*!
+         * The results for a single Parameter Region
+         */
+        enum class RegionResult {
+            Unknown, /*!< the result is unknown */
+            ExistsSat, /*!< the formula is satisfied for at least one parameter evaluation that lies in the given region */
+            ExistsViolated, /*!< the formula is violated for at least one parameter evaluation that lies in the given region */
+            CenterSat, /*!< the formula is satisfied for the parameter Valuation that corresponds to the center point of the region */
+            CenterViolated, /*!< the formula is violated for the parameter Valuation that corresponds to the center point of the region */
+            ExistsBoth, /*!< the formula is satisfied for some parameters but also violated for others */
+            AllSat, /*!< the formula is satisfied for all parameters in the given region */
+            AllViolated /*!< the formula is violated for all parameters in the given region */
+        };
+        
+        std::ostream& operator<<(std::ostream& os, RegionResult const& regionCheckResult);
+    }
+}
+
diff --git a/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp
new file mode 100644
index 000000000..5f32c8386
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp
@@ -0,0 +1,328 @@
+#include "storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h"
+
+#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h"
+
+#include "storm/adapters/RationalFunctionAdapter.h"
+#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h"
+#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
+#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
+#include "storm/models/sparse/Dtmc.h"
+#include "storm/models/sparse/StandardRewardModel.h"
+#include "storm/solver/StandardMinMaxLinearEquationSolver.h"
+#include "storm/utility/vector.h"
+#include "storm/utility/graph.h"
+#include "storm/utility/NumberTraits.h"
+
+#include "storm/exceptions/InvalidArgumentException.h"
+#include "storm/exceptions/InvalidPropertyException.h"
+#include "storm/exceptions/NotSupportedException.h"
+#include "storm/exceptions/UnexpectedException.h"
+
+namespace storm {
+    namespace modelchecker {
+        
+        template <typename SparseModelType, typename ConstantType>
+        SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseDtmcParameterLiftingModelChecker() : SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>(std::make_unique<storm::solver::GeneralMinMaxLinearEquationSolverFactory<ConstantType>>()) {
+            // Intentionally left empty
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseDtmcParameterLiftingModelChecker(std::unique_ptr<storm::solver::MinMaxLinearEquationSolverFactory<ConstantType>>&& solverFactory) : solverFactory(std::move(solverFactory)) {
+            // Intentionally left empty
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        bool SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const {
+            bool result = parametricModel->isOfType(storm::models::ModelType::Dtmc);
+            result &= parametricModel->isSparseModel();
+            result &= parametricModel->supportsParameters();
+            auto dtmc = parametricModel->template as<SparseModelType>();
+            result &= static_cast<bool>(dtmc);
+            result &= checkTask.getFormula().isInFragment(storm::logic::reachability().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setBoundedUntilFormulasAllowed(true).setCumulativeRewardFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(true));
+            return result;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) {
+            auto dtmc = parametricModel->template as<SparseModelType>();
+            specify(dtmc, checkTask, false);
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specify(std::shared_ptr<SparseModelType> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask, bool skipModelSimplification) {
+
+            STORM_LOG_ASSERT(this->canHandle(parametricModel, checkTask), "specified model and formula can not be handled by this.");
+         
+            reset();
+            
+            if (skipModelSimplification) {
+                this->parametricModel = parametricModel;
+                this->specifyFormula(checkTask);
+            } else {
+                auto simplifier = storm::transformer::SparseParametricDtmcSimplifier<SparseModelType>(*parametricModel);
+                if (!simplifier.simplify(checkTask.getFormula())) {
+                    STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull.");
+                }
+                this->parametricModel = simplifier.getSimplifiedModel();
+                this->specifyFormula(checkTask.substituteFormula(*simplifier.getSimplifiedFormula()));
+            }
+        }
+        
+        
+        template <typename SparseModelType, typename ConstantType>
+        void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) {
+            
+            // get the step bound
+            STORM_LOG_THROW(!checkTask.getFormula().hasLowerBound(), storm::exceptions::NotSupportedException, "Lower step bounds are not supported.");
+            STORM_LOG_THROW(checkTask.getFormula().hasUpperBound(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with an upper bound.");
+            STORM_LOG_THROW(checkTask.getFormula().isStepBounded(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with step bounds.");
+            stepBound = checkTask.getFormula().getUpperBound().evaluateAsInt();
+            STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
+            if (checkTask.getFormula().isUpperBoundStrict()) {
+                STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero.");
+                --(*stepBound);
+            }
+            STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
+
+            // get the results for the subformulas
+            storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel);
+            STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported");
+            storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
+            storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
+            
+            // get the maybeStates
+            maybeStates = storm::utility::graph::performProbGreater0(this->parametricModel->getBackwardTransitions(), phiStates, psiStates, true, *stepBound);
+            maybeStates &= ~psiStates;
+            
+            // set the result for all non-maybe states
+            resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
+            storm::utility::vector::setVectorValues(resultsForNonMaybeStates, psiStates, storm::utility::one<ConstantType>());
+            
+            // if there are maybestates, create the parameterLifter
+            if (!maybeStates.empty()) {
+                // Create the vector of one-step probabilities to go to target states.
+                std::vector<typename SparseModelType::ValueType> b = this->parametricModel->getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(), true), psiStates);
+                
+                parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, maybeStates, maybeStates);
+            }
+            
+            // We know some bounds for the results so set them
+            lowerResultBound = storm::utility::zero<ConstantType>();
+            upperResultBound = storm::utility::one<ConstantType>();
+        }
+
+        template <typename SparseModelType, typename ConstantType>
+        void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) {
+            
+            // get the results for the subformulas
+            storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel);
+            STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported");
+            storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
+            storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
+            
+            // get the maybeStates
+            std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 = storm::utility::graph::performProb01(this->parametricModel->getBackwardTransitions(), phiStates, psiStates);
+            maybeStates = ~(statesWithProbability01.first | statesWithProbability01.second);
+            
+            // set the result for all non-maybe states
+            resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
+            storm::utility::vector::setVectorValues(resultsForNonMaybeStates, statesWithProbability01.second, storm::utility::one<ConstantType>());
+            
+            // if there are maybestates, create the parameterLifter
+            if (!maybeStates.empty()) {
+                // Create the vector of one-step probabilities to go to target states.
+                std::vector<typename SparseModelType::ValueType> b = this->parametricModel->getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(), true), psiStates);
+                
+                parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, maybeStates, maybeStates);
+            }
+            
+            // We know some bounds for the results so set them
+            lowerResultBound = storm::utility::zero<ConstantType>();
+            upperResultBound = storm::utility::one<ConstantType>();
+        }
+
+        template <typename SparseModelType, typename ConstantType>
+        void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) {
+            
+            // get the results for the subformula
+            storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel);
+            STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported");
+            storm::storage::BitVector targetStates = std::move(propositionalChecker.check(checkTask.getFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
+            
+            // get the maybeStates
+            storm::storage::BitVector infinityStates = storm::utility::graph::performProb1(this->parametricModel->getBackwardTransitions(), storm::storage::BitVector(this->parametricModel->getNumberOfStates(), true), targetStates);
+            infinityStates.complement();
+            maybeStates = ~(targetStates | infinityStates);
+            
+            // set the result for all the non-maybe states
+            resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
+            storm::utility::vector::setVectorValues(resultsForNonMaybeStates, infinityStates, storm::utility::infinity<ConstantType>());
+            
+            // if there are maybestates, create the parameterLifter
+            if (!maybeStates.empty()) {
+                // Create the reward vector
+                STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel->hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model.");
+
+                typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel->getRewardModel(checkTask.getRewardModel()) : this->parametricModel->getUniqueRewardModel();
+
+                std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel->getTransitionMatrix());
+                
+                parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, maybeStates, maybeStates);
+            }
+            
+            // We only know a lower bound for the result
+            lowerResultBound = storm::utility::zero<ConstantType>();
+
+        }
+
+        template <typename SparseModelType, typename ConstantType>
+        void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) {
+            
+            // Obtain the stepBound
+            stepBound = checkTask.getFormula().getBound().evaluateAsInt();
+            if (checkTask.getFormula().isBoundStrict()) {
+                STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero.");
+                --(*stepBound);
+            }
+            STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
+            
+            //Every state is a maybeState
+            maybeStates = storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getColumnCount(), true);
+            resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates());
+            
+            // Create the reward vector
+            STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel->hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model.");
+            typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel->getRewardModel(checkTask.getRewardModel()) : this->parametricModel->getUniqueRewardModel();
+            std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel->getTransitionMatrix());
+            
+            parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, maybeStates, maybeStates);
+            
+            
+            // We only know a lower bound for the result
+            lowerResultBound = storm::utility::zero<ConstantType>();
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        storm::modelchecker::SparseInstantiationModelChecker<SparseModelType, ConstantType>& SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::getInstantiationChecker() {
+            if (!instantiationChecker) {
+                instantiationChecker = std::make_unique<storm::modelchecker::SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>>(*this->parametricModel);
+                instantiationChecker->specifyFormula(this->currentCheckTask->template convertValueType<typename SparseModelType::ValueType>());
+                instantiationChecker->setInstantiationsAreGraphPreserving(true);
+            }
+            return *instantiationChecker;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        std::unique_ptr<CheckResult> SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) {
+            
+            if(maybeStates.empty()) {
+                return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(resultsForNonMaybeStates);
+            }
+            
+            parameterLifter->specifyRegion(region, dirForParameters);
+            
+            // Set up the solver
+            auto solver = solverFactory->create(parameterLifter->getMatrix());
+            if (storm::NumberTraits<ConstantType>::IsExact && dynamic_cast<storm::solver::StandardMinMaxLinearEquationSolver<ConstantType>*>(solver.get())) {
+                STORM_LOG_INFO("Parameter Lifting: Setting solution method for exact MinMaxSolver to policy iteration");
+                auto* standardSolver = dynamic_cast<storm::solver::StandardMinMaxLinearEquationSolver<ConstantType>*>(solver.get());
+                auto settings = standardSolver->getSettings();
+                settings.setSolutionMethod(storm::solver::StandardMinMaxLinearEquationSolverSettings<ConstantType>::SolutionMethod::PolicyIteration);
+                standardSolver->setSettings(settings);
+            }
+            if (lowerResultBound) solver->setLowerBound(lowerResultBound.get());
+            if (upperResultBound) solver->setUpperBound(upperResultBound.get());
+            if (!stepBound) solver->setTrackScheduler(true);
+            if (storm::solver::minimize(dirForParameters) && minSchedChoices && !stepBound) solver->setSchedulerHint(std::move(minSchedChoices.get()));
+            if (storm::solver::maximize(dirForParameters) && maxSchedChoices && !stepBound) solver->setSchedulerHint(std::move(maxSchedChoices.get()));
+            if (this->currentCheckTask->isBoundSet() && solver->hasSchedulerHint()) {
+                // If we reach this point, we know that after applying the hint, the x-values can only become larger (if we maximize) or smaller (if we minimize).
+                std::unique_ptr<storm::solver::TerminationCondition<ConstantType>> termCond;
+                storm::storage::BitVector relevantStatesInSubsystem = this->currentCheckTask->isOnlyInitialStatesRelevantSet() ? this->parametricModel->getInitialStates() % maybeStates : storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true);
+                if (storm::solver::minimize(dirForParameters)) {
+                    // Terminate if the value for ALL relevant states is already below the threshold
+                    termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumBelowThreshold<ConstantType>> (relevantStatesInSubsystem, this->currentCheckTask->getBoundThreshold(), true, false);
+                } else {
+                    // Terminate if the value for ALL relevant states is already above the threshold
+                    termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumExceedsThreshold<ConstantType>> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), true);
+                }
+                solver->setTerminationCondition(std::move(termCond));
+            }
+            
+            // Invoke the solver
+            if(stepBound) {
+                assert(*stepBound > 0);
+                x = std::vector<ConstantType>(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
+                solver->repeatedMultiply(dirForParameters, x, &parameterLifter->getVector(), *stepBound);
+            } else {
+                x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
+                solver->solveEquations(dirForParameters, x, parameterLifter->getVector());
+                if(storm::solver::minimize(dirForParameters)) {
+                    minSchedChoices = solver->getSchedulerChoices();
+                } else {
+                    maxSchedChoices = solver->getSchedulerChoices();
+                }
+            }
+            
+            // Get the result for the complete model (including maybestates)
+            std::vector<ConstantType> result = resultsForNonMaybeStates;
+            auto maybeStateResIt = x.begin();
+            for(auto const& maybeState : maybeStates) {
+                result[maybeState] = *maybeStateResIt;
+                ++maybeStateResIt;
+            }
+            return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(std::move(result));
+        }
+        
+        
+        template <typename SparseModelType, typename ConstantType>
+        void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::reset() {
+            maybeStates.resize(0);
+            resultsForNonMaybeStates.clear();
+            stepBound = boost::none;
+            instantiationChecker = nullptr;
+            parameterLifter = nullptr;
+            minSchedChoices = boost::none;
+            maxSchedChoices = boost::none;
+            x.clear();
+            lowerResultBound = boost::none;
+            upperResultBound = boost::none;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        boost::optional<storm::storage::Scheduler<ConstantType>> SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMinScheduler() {
+            if (!minSchedChoices) {
+                return boost::none;
+            }
+            
+            storm::storage::Scheduler<ConstantType> result(minSchedChoices->size());
+            uint_fast64_t state = 0;
+            for (auto const& schedulerChoice : minSchedChoices.get()) {
+                result.setChoice(schedulerChoice, state);
+                ++state;
+            }
+            
+            return result;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        boost::optional<storm::storage::Scheduler<ConstantType>> SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMaxScheduler() {
+            if (!maxSchedChoices) {
+                return boost::none;
+            }
+            
+            storm::storage::Scheduler<ConstantType> result(maxSchedChoices->size());
+            uint_fast64_t state = 0;
+            for (auto const& schedulerChoice : maxSchedChoices.get()) {
+                result.setChoice(schedulerChoice, state);
+                ++state;
+            }
+            
+            return result;
+        }
+        
+        template class SparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>;
+        template class SparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>;
+
+    }
+}
diff --git a/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h
new file mode 100644
index 000000000..d6f51032b
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h
@@ -0,0 +1,64 @@
+#pragma once
+
+#include <vector>
+#include <memory>
+#include <boost/optional.hpp>
+
+#include "storm-pars/transformer/ParameterLifter.h"
+#include "storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h"
+#include "storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.h"
+#include "storm/storage/BitVector.h"
+#include "storm/storage/Scheduler.h"
+#include "storm/solver/MinMaxLinearEquationSolver.h"
+#include "storm/logic/FragmentSpecification.h"
+
+
+namespace storm {
+    namespace modelchecker {
+            
+        template <typename SparseModelType, typename ConstantType>
+        class SparseDtmcParameterLiftingModelChecker : public SparseParameterLiftingModelChecker<SparseModelType, ConstantType> {
+        public:
+            SparseDtmcParameterLiftingModelChecker();
+            SparseDtmcParameterLiftingModelChecker(std::unique_ptr<storm::solver::MinMaxLinearEquationSolverFactory<ConstantType>>&& solverFactory);
+            virtual ~SparseDtmcParameterLiftingModelChecker() = default;
+            
+            virtual bool canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const override;
+            virtual void specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) override;
+            void specify(std::shared_ptr<SparseModelType> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask, bool skipModelSimplification);
+            
+            boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMinScheduler();
+            boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMaxScheduler();
+
+        protected:
+                
+            virtual void specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) override;
+            virtual void specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) override;
+            virtual void specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) override;
+            virtual void specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) override;
+
+            virtual storm::modelchecker::SparseInstantiationModelChecker<SparseModelType, ConstantType>& getInstantiationChecker() override;
+                
+            virtual std::unique_ptr<CheckResult> computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) override;
+                
+            virtual void reset() override;
+                
+        private:
+
+            
+            storm::storage::BitVector maybeStates;
+            std::vector<ConstantType> resultsForNonMaybeStates;
+            boost::optional<uint_fast64_t> stepBound;
+                
+            std::unique_ptr<storm::modelchecker::SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>> instantiationChecker;
+                
+            std::unique_ptr<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>> parameterLifter;
+            std::unique_ptr<storm::solver::MinMaxLinearEquationSolverFactory<ConstantType>> solverFactory;
+                
+            // Results from the most recent solver call.
+            boost::optional<std::vector<uint_fast64_t>> minSchedChoices, maxSchedChoices;
+            std::vector<ConstantType> x;
+            boost::optional<ConstantType> lowerResultBound, upperResultBound;
+        };
+    }
+}
diff --git a/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp
new file mode 100644
index 000000000..6169d22bf
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp
@@ -0,0 +1,408 @@
+#include "storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.h"
+#include "storm-pars/utility/parameterlifting.h"
+#include "storm-pars/transformer/SparseParametricMdpSimplifier.h"
+
+#include "storm/adapters/RationalFunctionAdapter.h"
+#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h"
+#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
+#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
+#include "storm/models/sparse/Mdp.h"
+#include "storm/models/sparse/StandardRewardModel.h"
+#include "storm/utility/vector.h"
+#include "storm/utility/graph.h"
+#include "storm/utility/NumberTraits.h"
+#include "storm/solver/StandardGameSolver.h"
+#include "storm/logic/FragmentSpecification.h"
+
+#include "storm/exceptions/InvalidArgumentException.h"
+#include "storm/exceptions/InvalidPropertyException.h"
+#include "storm/exceptions/NotSupportedException.h"
+#include "storm/exceptions/UnexpectedException.h"
+
+namespace storm {
+    namespace modelchecker {
+        
+        
+        template <typename SparseModelType, typename ConstantType>
+        SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseMdpParameterLiftingModelChecker() : SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>(std::make_unique<storm::solver::GameSolverFactory<ConstantType>>()) {
+            // Intentionally left empty
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseMdpParameterLiftingModelChecker(std::unique_ptr<storm::solver::GameSolverFactory<ConstantType>>&& solverFactory) : solverFactory(std::move(solverFactory)) {
+            // Intentionally left empty
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        bool SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const {
+            bool result = parametricModel->isOfType(storm::models::ModelType::Mdp);
+            result &= parametricModel->isSparseModel();
+            result &= parametricModel->supportsParameters();
+            auto mdp = parametricModel->template as<SparseModelType>();
+            result &= static_cast<bool>(mdp);
+            result &= checkTask.getFormula().isInFragment(storm::logic::reachability().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setBoundedUntilFormulasAllowed(true).setCumulativeRewardFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(true));
+            return result;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) {
+            auto mdp = parametricModel->template as<SparseModelType>();
+            specify(mdp, checkTask, false);
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specify(std::shared_ptr<SparseModelType> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask, bool skipModelSimplification) {
+
+            STORM_LOG_ASSERT(this->canHandle(parametricModel, checkTask), "specified model and formula can not be handled by this.");
+         
+            reset();
+            
+            if (skipModelSimplification) {
+                this->parametricModel = parametricModel;
+                this->specifyFormula(checkTask);
+            } else {
+                auto simplifier = storm::transformer::SparseParametricMdpSimplifier<SparseModelType>(*parametricModel);
+                if (!simplifier.simplify(checkTask.getFormula())) {
+                    STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull.");
+                }
+                this->parametricModel = simplifier.getSimplifiedModel();
+                this->specifyFormula(checkTask.substituteFormula(*simplifier.getSimplifiedFormula()));
+            }
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) {
+            
+            // get the step bound
+            STORM_LOG_THROW(!checkTask.getFormula().hasLowerBound(), storm::exceptions::NotSupportedException, "Lower step bounds are not supported.");
+            STORM_LOG_THROW(checkTask.getFormula().hasUpperBound(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with an upper bound.");
+            STORM_LOG_THROW(checkTask.getFormula().isStepBounded(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with step bounds.");
+            stepBound = checkTask.getFormula().getUpperBound().evaluateAsInt();
+            STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
+            if (checkTask.getFormula().isUpperBoundStrict()) {
+                STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero.");
+                --(*stepBound);
+            }
+            STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
+
+            // get the results for the subformulas
+            storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel);
+            STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported");
+            storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
+            storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
+            
+            // get the maybeStates
+            maybeStates = storm::solver::minimize(checkTask.getOptimizationDirection()) ?
+                          storm::utility::graph::performProbGreater0A(this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(), this->parametricModel->getBackwardTransitions(), phiStates, psiStates, true, *stepBound) :
+                          storm::utility::graph::performProbGreater0E(this->parametricModel->getBackwardTransitions(), phiStates, psiStates, true, *stepBound);
+            maybeStates &= ~psiStates;
+            
+            // set the result for all non-maybe states
+            resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
+            storm::utility::vector::setVectorValues(resultsForNonMaybeStates, psiStates, storm::utility::one<ConstantType>());
+            
+            // if there are maybestates, create the parameterLifter
+            if (!maybeStates.empty()) {
+                // Create the vector of one-step probabilities to go to target states.
+                std::vector<typename SparseModelType::ValueType> b = this->parametricModel->getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(), true), psiStates);
+                
+                parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, this->parametricModel->getTransitionMatrix().getRowFilter(maybeStates), maybeStates);
+                computePlayer1Matrix();
+                
+                applyPreviousResultAsHint = false;
+            }
+            
+            // We know some bounds for the results
+            lowerResultBound = storm::utility::zero<ConstantType>();
+            upperResultBound = storm::utility::one<ConstantType>();
+        }
+
+        template <typename SparseModelType, typename ConstantType>
+        void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) {
+            
+            // get the results for the subformulas
+            storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel);
+            STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported");
+            storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
+            storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
+            
+            // get the maybeStates
+            std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 = storm::solver::minimize(checkTask.getOptimizationDirection()) ?
+                                                                                                      storm::utility::graph::performProb01Min(this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(), this->parametricModel->getBackwardTransitions(), phiStates, psiStates) :
+                                                                                                      storm::utility::graph::performProb01Max(this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(), this->parametricModel->getBackwardTransitions(), phiStates, psiStates);
+            maybeStates = ~(statesWithProbability01.first | statesWithProbability01.second);
+            
+            // set the result for all non-maybe states
+            resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
+            storm::utility::vector::setVectorValues(resultsForNonMaybeStates, statesWithProbability01.second, storm::utility::one<ConstantType>());
+            
+            // if there are maybestates, create the parameterLifter
+            if (!maybeStates.empty()) {
+                // Create the vector of one-step probabilities to go to target states.
+                std::vector<typename SparseModelType::ValueType> b = this->parametricModel->getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(), true), statesWithProbability01.second);
+                
+                parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, this->parametricModel->getTransitionMatrix().getRowFilter(maybeStates), maybeStates);
+                computePlayer1Matrix();
+                
+                // Check whether there is an EC consisting of maybestates
+                applyPreviousResultAsHint = storm::solver::minimize(checkTask.getOptimizationDirection()) || // when minimizing, there can not be an EC within the maybestates
+                                            storm::utility::graph::performProb1A(this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(), this->parametricModel->getBackwardTransitions(), maybeStates, ~maybeStates).full();
+            }
+            
+            // We know some bounds for the results
+            lowerResultBound = storm::utility::zero<ConstantType>();
+            upperResultBound = storm::utility::one<ConstantType>();
+        }
+
+        template <typename SparseModelType, typename ConstantType>
+        void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) {
+            
+            // get the results for the subformula
+            storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(*this->parametricModel);
+            STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported");
+            storm::storage::BitVector targetStates = std::move(propositionalChecker.check(checkTask.getFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
+            
+            // get the maybeStates
+            storm::storage::BitVector infinityStates = storm::solver::minimize(checkTask.getOptimizationDirection()) ?
+                                                       storm::utility::graph::performProb1E(this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(), this->parametricModel->getBackwardTransitions(), storm::storage::BitVector(this->parametricModel->getNumberOfStates(), true), targetStates) :
+                                                       storm::utility::graph::performProb1A(this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(), this->parametricModel->getBackwardTransitions(), storm::storage::BitVector(this->parametricModel->getNumberOfStates(), true), targetStates);
+            infinityStates.complement();
+            maybeStates = ~(targetStates | infinityStates);
+            
+            // set the result for all the non-maybe states
+            resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
+            storm::utility::vector::setVectorValues(resultsForNonMaybeStates, infinityStates, storm::utility::infinity<ConstantType>());
+            
+            // if there are maybestates, create the parameterLifter
+            if (!maybeStates.empty()) {
+                // Create the reward vector
+                STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel->hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model.");
+
+                typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel->getRewardModel(checkTask.getRewardModel()) : this->parametricModel->getUniqueRewardModel();
+
+                std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel->getTransitionMatrix());
+                
+                // We need to handle choices that lead to an infinity state.
+                // As a maybeState does not have reward infinity, a choice leading to an infinity state will never be picked. Hence, we can unselect the corresponding rows
+                storm::storage::BitVector selectedRows = this->parametricModel->getTransitionMatrix().getRowFilter(maybeStates, ~infinityStates);
+                
+                parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, selectedRows, maybeStates);
+                computePlayer1Matrix(selectedRows);
+                
+                // Check whether there is an EC consisting of maybestates
+                applyPreviousResultAsHint = !storm::solver::minimize(checkTask.getOptimizationDirection()) || // when maximizing, there can not be an EC within the maybestates
+                                            storm::utility::graph::performProb1A(this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(), this->parametricModel->getBackwardTransitions(), maybeStates, ~maybeStates).full();
+            }
+            
+            // We only know a lower bound for the result
+            lowerResultBound = storm::utility::zero<ConstantType>();
+
+        }
+
+        template <typename SparseModelType, typename ConstantType>
+        void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) {
+            
+            // Obtain the stepBound
+            stepBound = checkTask.getFormula().getBound().evaluateAsInt();
+            if (checkTask.getFormula().isBoundStrict()) {
+                STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero.");
+                --(*stepBound);
+            }
+            STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
+            
+            //Every state is a maybeState
+            maybeStates = storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getColumnCount(), true);
+            resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates());
+
+            // Create the reward vector
+            STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel->hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model.");
+            typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel->getRewardModel(checkTask.getRewardModel()) : this->parametricModel->getUniqueRewardModel();
+            std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel->getTransitionMatrix());
+            
+            parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b, storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(), true), maybeStates);
+            computePlayer1Matrix();
+
+            applyPreviousResultAsHint = false;
+            
+            // We only know a lower bound for the result
+            lowerResultBound = storm::utility::zero<ConstantType>();
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        storm::modelchecker::SparseInstantiationModelChecker<SparseModelType, ConstantType>& SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getInstantiationChecker() {
+            if (!instantiationChecker) {
+                instantiationChecker = std::make_unique<storm::modelchecker::SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>>(*this->parametricModel);
+                instantiationChecker->specifyFormula(this->currentCheckTask->template convertValueType<typename SparseModelType::ValueType>());
+                instantiationChecker->setInstantiationsAreGraphPreserving(true);
+            }
+            return *instantiationChecker;
+        }
+
+        template <typename SparseModelType, typename ConstantType>
+        std::unique_ptr<CheckResult> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) {
+            
+            if (maybeStates.empty()) {
+                return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(resultsForNonMaybeStates);
+            }
+            
+            parameterLifter->specifyRegion(region, dirForParameters);
+            
+            // Set up the solver
+            auto solver = solverFactory->create(player1Matrix, parameterLifter->getMatrix());
+            if (storm::NumberTraits<ConstantType>::IsExact && dynamic_cast<storm::solver::StandardGameSolver<ConstantType>*>(solver.get())) {
+                STORM_LOG_INFO("Parameter Lifting: Setting solution method for exact Game Solver to policy iteration");
+                auto* standardSolver = dynamic_cast<storm::solver::StandardGameSolver<ConstantType>*>(solver.get());
+                auto settings = standardSolver->getSettings();
+                settings.setSolutionMethod(storm::solver::StandardGameSolverSettings<ConstantType>::SolutionMethod::PolicyIteration);
+                standardSolver->setSettings(settings);
+            }
+            if (lowerResultBound) solver->setLowerBound(lowerResultBound.get());
+            if (upperResultBound) solver->setUpperBound(upperResultBound.get());
+            if (applyPreviousResultAsHint) {
+                solver->setTrackSchedulers(true);
+                x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
+                if(storm::solver::minimize(dirForParameters) && minSchedChoices && player1SchedChoices) solver->setSchedulerHints(std::move(player1SchedChoices.get()), std::move(minSchedChoices.get()));
+                if(storm::solver::maximize(dirForParameters) && maxSchedChoices && player1SchedChoices) solver->setSchedulerHints(std::move(player1SchedChoices.get()), std::move(maxSchedChoices.get()));
+            } else {
+                x.assign(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
+            }
+            if (this->currentCheckTask->isBoundSet() && this->currentCheckTask->getOptimizationDirection() == dirForParameters && solver->hasSchedulerHints()) {
+                // If we reach this point, we know that after applying the hints, the x-values can only become larger (if we maximize) or smaller (if we minimize).
+                std::unique_ptr<storm::solver::TerminationCondition<ConstantType>> termCond;
+                storm::storage::BitVector relevantStatesInSubsystem = this->currentCheckTask->isOnlyInitialStatesRelevantSet() ? this->parametricModel->getInitialStates() % maybeStates : storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true);
+                if (storm::solver::minimize(dirForParameters)) {
+                    // Terminate if the value for ALL relevant states is already below the threshold
+                    termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumBelowThreshold<ConstantType>> (relevantStatesInSubsystem, this->currentCheckTask->getBoundThreshold(), true, false);
+                } else {
+                    // Terminate if the value for ALL relevant states is already above the threshold
+                    termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumExceedsThreshold<ConstantType>> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), true);
+                }
+                solver->setTerminationCondition(std::move(termCond));
+            }
+            
+            // Invoke the solver
+            if(stepBound) {
+                assert(*stepBound > 0);
+                solver->repeatedMultiply(this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, &parameterLifter->getVector(), *stepBound);
+            } else {
+                solver->solveGame(this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, parameterLifter->getVector());
+                if(applyPreviousResultAsHint) {
+                    if(storm::solver::minimize(dirForParameters)) {
+                        minSchedChoices = solver->getPlayer2SchedulerChoices();
+                    } else {
+                        maxSchedChoices = solver->getPlayer2SchedulerChoices();
+                    }
+                    player1SchedChoices = solver->getPlayer1SchedulerChoices();
+                }
+            }
+            
+            // Get the result for the complete model (including maybestates)
+            std::vector<ConstantType> result = resultsForNonMaybeStates;
+            auto maybeStateResIt = x.begin();
+            for(auto const& maybeState : maybeStates) {
+                result[maybeState] = *maybeStateResIt;
+                ++maybeStateResIt;
+            }
+            
+            return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(std::move(result));
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::computePlayer1Matrix(boost::optional<storm::storage::BitVector> const& selectedRows) {
+            uint_fast64_t n = 0;
+            if (selectedRows) {
+                // only count selected rows
+                n = selectedRows->getNumberOfSetBits();
+            } else {
+                for (auto const& maybeState : maybeStates) {
+                    n += this->parametricModel->getTransitionMatrix().getRowGroupSize(maybeState);
+                }
+            }
+            
+            // The player 1 matrix is the identity matrix of size n with the row groups as given by the original matrix (potentially without unselected rows)
+            storm::storage::SparseMatrixBuilder<storm::storage::sparse::state_type> matrixBuilder(n, n, n, true, true, maybeStates.getNumberOfSetBits());
+            uint_fast64_t p1MatrixRow = 0;
+            for (auto maybeState : maybeStates){
+                matrixBuilder.newRowGroup(p1MatrixRow);
+                if (selectedRows) {
+                    for (uint_fast64_t row = selectedRows->getNextSetIndex(this->parametricModel->getTransitionMatrix().getRowGroupIndices()[maybeState]); row < this->parametricModel->getTransitionMatrix().getRowGroupIndices()[maybeState + 1]; row = selectedRows->getNextSetIndex(row + 1)) {
+                        matrixBuilder.addNextValue(p1MatrixRow, p1MatrixRow, storm::utility::one<storm::storage::sparse::state_type>());
+                        ++p1MatrixRow;
+                    }
+                } else {
+                    for (uint_fast64_t endOfGroup = p1MatrixRow + this->parametricModel->getTransitionMatrix().getRowGroupSize(maybeState); p1MatrixRow < endOfGroup; ++p1MatrixRow){
+                        matrixBuilder.addNextValue(p1MatrixRow, p1MatrixRow, storm::utility::one<storm::storage::sparse::state_type>());
+                    }
+                }
+            }
+            player1Matrix = matrixBuilder.build();
+        }
+
+        template <typename SparseModelType, typename ConstantType>
+        void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::reset() {
+            maybeStates.resize(0);
+            resultsForNonMaybeStates.clear();
+            stepBound = boost::none;
+            instantiationChecker = nullptr;
+            player1Matrix = storm::storage::SparseMatrix<storm::storage::sparse::state_type>();
+            parameterLifter = nullptr;
+            minSchedChoices = boost::none;
+            maxSchedChoices = boost::none;
+            x.clear();
+            lowerResultBound = boost::none;
+            upperResultBound = boost::none;
+            applyPreviousResultAsHint = false;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMinScheduler() {
+            if (!minSchedChoices) {
+                return boost::none;
+            }
+            
+            storm::storage::Scheduler<ConstantType> result(minSchedChoices->size());
+            uint_fast64_t state = 0;
+            for (auto const& schedulerChoice : minSchedChoices.get()) {
+                result.setChoice(schedulerChoice, state);
+                ++state;
+            }
+            
+            return result;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMaxScheduler() {
+            if (!maxSchedChoices) {
+                return boost::none;
+            }
+            
+            storm::storage::Scheduler<ConstantType> result(maxSchedChoices->size());
+            uint_fast64_t state = 0;
+            for (auto const& schedulerChoice : maxSchedChoices.get()) {
+                result.setChoice(schedulerChoice, state);
+                ++state;
+            }
+            
+            return result;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentPlayer1Scheduler() {
+            if (!player1SchedChoices) {
+                return boost::none;
+            }
+            
+            storm::storage::Scheduler<ConstantType> result(player1SchedChoices->size());
+            uint_fast64_t state = 0;
+            for (auto const& schedulerChoice : player1SchedChoices.get()) {
+                result.setChoice(schedulerChoice, state);
+                ++state;
+            }
+            
+            return result;
+        }
+
+        template class SparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>;
+        template class SparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>;
+    }
+}
diff --git a/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.h b/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.h
new file mode 100644
index 000000000..346bb01f7
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#include <vector>
+#include <memory>
+#include <boost/optional.hpp>
+
+#include "storm-pars/transformer/ParameterLifter.h"
+#include "storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h"
+#include "storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.h"
+
+#include "storm/storage/BitVector.h"
+#include "storm/storage/SparseMatrix.h"
+#include "storm/storage/sparse/StateType.h"
+#include "storm/solver/GameSolver.h"
+#include "storm/storage/Scheduler.h"
+
+namespace storm {
+    namespace modelchecker {
+        
+        template <typename SparseModelType, typename ConstantType>
+        class SparseMdpParameterLiftingModelChecker : public SparseParameterLiftingModelChecker<SparseModelType, ConstantType> {
+        public:
+            SparseMdpParameterLiftingModelChecker();
+            SparseMdpParameterLiftingModelChecker(std::unique_ptr<storm::solver::GameSolverFactory<ConstantType>>&& solverFactory);
+            virtual ~SparseMdpParameterLiftingModelChecker() = default;
+            
+            virtual bool canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const override;
+            virtual void specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) override;
+            void specify(std::shared_ptr<SparseModelType> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask, bool skipModelSimplification);
+
+            boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMinScheduler();
+            boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMaxScheduler();
+            boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentPlayer1Scheduler();
+                
+        protected:
+                
+            virtual void specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) override;
+            virtual void specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) override;
+            virtual void specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) override;
+            virtual void specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) override;
+                
+            virtual storm::modelchecker::SparseInstantiationModelChecker<SparseModelType, ConstantType>& getInstantiationChecker() override;
+
+            virtual std::unique_ptr<CheckResult> computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) override;
+                
+            virtual void reset() override;
+                
+
+        private:
+            void computePlayer1Matrix(boost::optional<storm::storage::BitVector> const& selectedRows = boost::none);
+            
+            storm::storage::BitVector maybeStates;
+            std::vector<ConstantType> resultsForNonMaybeStates;
+            boost::optional<uint_fast64_t> stepBound;
+                
+            std::unique_ptr<storm::modelchecker::SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>> instantiationChecker;
+                
+            storm::storage::SparseMatrix<storm::storage::sparse::state_type> player1Matrix;
+            std::unique_ptr<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>> parameterLifter;
+            std::unique_ptr<storm::solver::GameSolverFactory<ConstantType>> solverFactory;
+                
+            // Results from the most recent solver call.
+            boost::optional<std::vector<uint_fast64_t>> minSchedChoices, maxSchedChoices;
+            boost::optional<std::vector<uint_fast64_t>> player1SchedChoices;
+            std::vector<ConstantType> x;
+            boost::optional<ConstantType> lowerResultBound, upperResultBound;
+            bool applyPreviousResultAsHint;
+        };
+    }
+}
diff --git a/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.cpp
new file mode 100644
index 000000000..17610df87
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.cpp
@@ -0,0 +1,176 @@
+#include "storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h"
+
+#include "storm/adapters/RationalFunctionAdapter.h"
+#include "storm/logic/FragmentSpecification.h"
+#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
+#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
+#include "storm/models/sparse/Dtmc.h"
+#include "storm/models/sparse/Mdp.h"
+#include "storm/models/sparse/StandardRewardModel.h"
+
+#include "storm/exceptions/InvalidArgumentException.h"
+#include "storm/exceptions/NotSupportedException.h"
+
+namespace storm {
+    namespace modelchecker {
+        
+        template <typename SparseModelType, typename ConstantType>
+        SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseParameterLiftingModelChecker() {
+            //Intentionally left empty
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) {
+
+            currentFormula = checkTask.getFormula().asSharedPointer();
+            currentCheckTask = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, ConstantType>>(checkTask.substituteFormula(*currentFormula).template convertValueType<ConstantType>());
+            
+            if(currentCheckTask->getFormula().isProbabilityOperatorFormula()) {
+                auto const& probOpFormula = currentCheckTask->getFormula().asProbabilityOperatorFormula();
+                if(probOpFormula.getSubformula().isBoundedUntilFormula()) {
+                    specifyBoundedUntilFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asBoundedUntilFormula()));
+                } else if(probOpFormula.getSubformula().isUntilFormula()) {
+                    specifyUntilFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asUntilFormula()));
+                } else if (probOpFormula.getSubformula().isEventuallyFormula()) {
+                    specifyReachabilityProbabilityFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asEventuallyFormula()));
+                } else {
+                    STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
+                }
+            } else if (currentCheckTask->getFormula().isRewardOperatorFormula()) {
+                auto const& rewOpFormula = currentCheckTask->getFormula().asRewardOperatorFormula();
+                if(rewOpFormula.getSubformula().isEventuallyFormula()) {
+                    specifyReachabilityRewardFormula(currentCheckTask->substituteFormula(rewOpFormula.getSubformula().asEventuallyFormula()));
+                } else if (rewOpFormula.getSubformula().isCumulativeRewardFormula()) {
+                    specifyCumulativeRewardFormula(currentCheckTask->substituteFormula(rewOpFormula.getSubformula().asCumulativeRewardFormula()));
+                }
+            }
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        RegionResult SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::analyzeRegion(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionResult const& initialResult, bool sampleVerticesOfRegion) {
+        
+            STORM_LOG_THROW(this->currentCheckTask->isOnlyInitialStatesRelevantSet(), storm::exceptions::NotSupportedException, "Analyzing regions with parameter lifting requires a property where only the value in the initial states is relevant.");
+            STORM_LOG_THROW(this->currentCheckTask->isBoundSet(), storm::exceptions::NotSupportedException, "Analyzing regions with parameter lifting requires a bounded property.");
+            STORM_LOG_THROW(this->parametricModel->getInitialStates().getNumberOfSetBits() == 1, storm::exceptions::NotSupportedException, "Analyzing regions with parameter lifting requires a model with a single initial state.");
+            
+            RegionResult result = initialResult;
+
+            // Check if we need to check the formula on one point to decide whether to show AllSat or AllViolated
+            if (result == RegionResult::Unknown) {
+                 result = getInstantiationChecker().check(region.getCenterPoint())->asExplicitQualitativeCheckResult()[*this->parametricModel->getInitialStates().begin()] ? RegionResult::CenterSat : RegionResult::CenterViolated;
+            }
+            
+            // try to prove AllSat or AllViolated, depending on the obtained result
+            if (result == RegionResult::ExistsSat || result == RegionResult::CenterSat) {
+                // show AllSat:
+                storm::solver::OptimizationDirection parameterOptimizationDirection = isLowerBound(this->currentCheckTask->getBound().comparisonType) ? storm::solver::OptimizationDirection::Minimize : storm::solver::OptimizationDirection::Maximize;
+                if (this->check(region, parameterOptimizationDirection)->asExplicitQualitativeCheckResult()[*this->parametricModel->getInitialStates().begin()]) {
+                    result = RegionResult::AllSat;
+                } else if (sampleVerticesOfRegion) {
+                    result = sampleVertices(region, result);
+                }
+            } else if (result == RegionResult::ExistsViolated || result == RegionResult::CenterViolated) {
+                // show AllViolated:
+                storm::solver::OptimizationDirection parameterOptimizationDirection = isLowerBound(this->currentCheckTask->getBound().comparisonType) ? storm::solver::OptimizationDirection::Maximize : storm::solver::OptimizationDirection::Minimize;
+                if (!this->check(region, parameterOptimizationDirection)->asExplicitQualitativeCheckResult()[*this->parametricModel->getInitialStates().begin()]) {
+                    result = RegionResult::AllViolated;
+                } else if (sampleVerticesOfRegion) {
+                    result = sampleVertices(region, result);
+                }
+            } else {
+                STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "When analyzing a region, an invalid initial result was given: " << initialResult);
+            }
+            return result;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        RegionResult SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::sampleVertices(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionResult const& initialResult) {
+            RegionResult result = initialResult;
+            
+            if (result == RegionResult::AllSat || result == RegionResult::AllViolated) {
+                return result;
+            }
+            
+            bool hasSatPoint = result == RegionResult::ExistsSat || result == RegionResult::CenterSat;
+            bool hasViolatedPoint = result == RegionResult::ExistsViolated || result == RegionResult::CenterViolated;
+            
+            // Check if there is a point in the region for which the property is satisfied
+            auto vertices = region.getVerticesOfRegion(region.getVariables());
+            auto vertexIt = vertices.begin();
+            while (vertexIt != vertices.end() && !(hasSatPoint && hasViolatedPoint)) {
+                if (getInstantiationChecker().check(*vertexIt)->asExplicitQualitativeCheckResult()[*this->parametricModel->getInitialStates().begin()]) {
+                    hasSatPoint = true;
+                } else {
+                    hasViolatedPoint = true;
+                }
+                ++vertexIt;
+            }
+            
+            if (hasSatPoint) {
+                if (hasViolatedPoint) {
+                    result = RegionResult::ExistsBoth;
+                } else if (result != RegionResult::CenterSat) {
+                    result = RegionResult::ExistsSat;
+                }
+            } else if (hasViolatedPoint && result != RegionResult::CenterViolated) {
+                result = RegionResult::ExistsViolated;
+            }
+            
+            return result;
+        }
+
+
+        template <typename SparseModelType, typename ConstantType>
+        std::unique_ptr<CheckResult> SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::check(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) {
+            auto quantitativeResult = computeQuantitativeValues(region, dirForParameters);
+            if(currentCheckTask->getFormula().hasQuantitativeResult()) {
+                return quantitativeResult;
+            } else {
+                return quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
+            }
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        SparseModelType const& SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::getConsideredParametricModel() const {
+            return *parametricModel;
+        }
+        
+        template <typename SparseModelType, typename ConstantType>
+        CheckTask<storm::logic::Formula, ConstantType> const& SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentCheckTask() const {
+            return *currentCheckTask;
+        }
+
+        template <typename SparseModelType, typename ConstantType>
+        void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyBoundedUntilFormula(CheckTask<logic::BoundedUntilFormula, ConstantType> const& checkTask) {
+            STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
+        }
+
+        template <typename SparseModelType, typename ConstantType>
+        void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyUntilFormula(CheckTask<logic::UntilFormula, ConstantType> const& checkTask) {
+            STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
+        }
+
+        template <typename SparseModelType, typename ConstantType>
+        void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityProbabilityFormula(CheckTask<logic::EventuallyFormula, ConstantType> const& checkTask) {
+            // transform to until formula
+            auto untilFormula = std::make_shared<storm::logic::UntilFormula const>(storm::logic::Formula::getTrueFormula(), checkTask.getFormula().getSubformula().asSharedPointer());
+            specifyUntilFormula(currentCheckTask->substituteFormula(*untilFormula));
+        }
+
+        template <typename SparseModelType, typename ConstantType>
+        void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityRewardFormula(CheckTask<logic::EventuallyFormula, ConstantType> const& checkTask) {
+            STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
+        }
+
+        template <typename SparseModelType, typename ConstantType>
+        void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyCumulativeRewardFormula(CheckTask<logic::CumulativeRewardFormula, ConstantType> const& checkTask) {
+            STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
+        }
+
+        template class SparseParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>;
+        template class SparseParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>;
+        template class SparseParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>;
+        template class SparseParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>;
+
+    }
+}
diff --git a/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h b/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h
new file mode 100644
index 000000000..b8abd518c
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include "storm-pars/modelchecker/region/RegionModelChecker.h"
+#include "storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h"
+#include "storm-pars/storage/ParameterRegion.h"
+#include "storm-pars/utility/parametric.h"
+
+#include "storm/logic/Formulas.h"
+#include "storm/modelchecker/CheckTask.h"
+#include "storm/modelchecker/results/CheckResult.h"
+#include "storm/solver/OptimizationDirection.h"
+
+namespace storm {
+    namespace modelchecker {
+            
+        /*!
+         * Class to approximatively check a formula on a parametric model for all parameter valuations within a region
+         * It is assumed that all considered valuations are graph-preserving and well defined, i.e.,
+         * * all non-const transition probabilities evaluate to some non-zero value
+         * * the sum of all outgoing transitions is one
+         */
+        template <typename SparseModelType, typename ConstantType>
+        class SparseParameterLiftingModelChecker : public RegionModelChecker<typename SparseModelType::ValueType> {
+        public:
+            SparseParameterLiftingModelChecker();
+            virtual ~SparseParameterLiftingModelChecker() = default;
+            
+
+            /*!
+             * Analyzes the given region by means of parameter lifting.
+             * We first check whether there is one point in the region for which the property is satisfied/violated.
+             * If the given initialResults already indicates that there is such a point, this step is skipped.
+             * Then, we check whether ALL points in the region violate/satisfy the property
+             *
+             */
+            virtual RegionResult analyzeRegion(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionResult const& initialResult = RegionResult::Unknown, bool sampleVerticesOfRegion = false) override;
+
+            /*!
+             * Analyzes the 2^#parameters corner points of the given region.
+             */
+            RegionResult sampleVertices(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionResult const& initialResult = RegionResult::Unknown);
+            
+            /*!
+             * Checks the specified formula on the given region by applying parameter lifting (Parameter choices are lifted to nondeterministic choices)
+             * This yields a (sound) approximative model checking result.
+
+             * @param region the region on which parameter lifting is applied
+             * @param dirForParameters  The optimization direction for the parameter choices. If this is, e.g., minimize, then the returned result will be a lower bound for all results induced by the parameter evaluations inside the region.
+             */
+            std::unique_ptr<CheckResult> check(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters);
+            
+            
+            SparseModelType const& getConsideredParametricModel() const;
+            CheckTask<storm::logic::Formula, ConstantType> const& getCurrentCheckTask() const;
+            
+        protected:
+            void specifyFormula(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask);
+            
+            // Resets all data that correspond to the currently defined property.
+            virtual void reset() = 0;
+
+            virtual void specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask);
+            virtual void specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask);
+            virtual void specifyReachabilityProbabilityFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask);
+            virtual void specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask);
+            virtual void specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask);
+
+            
+            virtual storm::modelchecker::SparseInstantiationModelChecker<SparseModelType, ConstantType>& getInstantiationChecker() = 0;
+            
+            virtual std::unique_ptr<CheckResult> computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) = 0;
+            
+            
+            std::shared_ptr<SparseModelType> parametricModel;
+            std::unique_ptr<CheckTask<storm::logic::Formula, ConstantType>> currentCheckTask;
+
+        private:
+            // store the current formula. Note that currentCheckTask only stores a reference to the formula.
+            std::shared_ptr<storm::logic::Formula const> currentFormula;
+            
+        };
+    }
+}
diff --git a/src/storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.cpp
new file mode 100644
index 000000000..2ab8c3103
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.cpp
@@ -0,0 +1,67 @@
+#include "storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.h"
+#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h"
+
+#include "storm/models/sparse/Dtmc.h"
+#include "storm/utility/macros.h"
+
+#include "storm/exceptions/UnexpectedException.h"
+
+namespace storm {
+    namespace modelchecker {
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        ValidatingSparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::ValidatingSparseDtmcParameterLiftingModelChecker() {
+            // Intentionally left empty
+        }
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        void ValidatingSparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) {
+            STORM_LOG_ASSERT(this->canHandle(parametricModel, checkTask), "specified model and formula can not be handled by this.");
+        
+            auto dtmc = parametricModel->template as<SparseModelType>();
+            auto simplifier = storm::transformer::SparseParametricDtmcSimplifier<SparseModelType>(*dtmc);
+
+            if (!simplifier.simplify(checkTask.getFormula())) {
+                STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull.");
+            }
+            
+            auto simplifiedTask = checkTask.substituteFormula(*simplifier.getSimplifiedFormula());
+            
+            impreciseChecker.specify(simplifier.getSimplifiedModel(), simplifiedTask, true);
+            preciseChecker.specify(simplifier.getSimplifiedModel(), simplifiedTask, true);
+        }
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType>& ValidatingSparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getImpreciseChecker() {
+            return impreciseChecker;
+        }
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType> const& ValidatingSparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getImpreciseChecker() const {
+            return impreciseChecker;
+        }
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        SparseParameterLiftingModelChecker<SparseModelType, PreciseType>& ValidatingSparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getPreciseChecker() {
+            return preciseChecker;
+        }
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        SparseParameterLiftingModelChecker<SparseModelType, PreciseType> const& ValidatingSparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getPreciseChecker() const {
+            return preciseChecker;
+        }
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        void ValidatingSparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::applyHintsToPreciseChecker() {
+        
+            if (impreciseChecker.getCurrentMaxScheduler()) {
+                preciseChecker.getCurrentMaxScheduler() = impreciseChecker.getCurrentMaxScheduler()->template toValueType<PreciseType>();
+            }
+            if (impreciseChecker.getCurrentMinScheduler()) {
+                preciseChecker.getCurrentMinScheduler() = impreciseChecker.getCurrentMinScheduler()->template toValueType<PreciseType>();
+            }
+        }
+        
+        template class ValidatingSparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber>;
+    }
+}
diff --git a/src/storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.h b/src/storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.h
new file mode 100644
index 000000000..9fd696be2
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/ValidatingSparseDtmcParameterLiftingModelChecker.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.h"
+#include "storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h"
+
+namespace storm {
+    namespace modelchecker {
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        class ValidatingSparseDtmcParameterLiftingModelChecker : public ValidatingSparseParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType> {
+        public:
+            ValidatingSparseDtmcParameterLiftingModelChecker();
+            virtual ~ValidatingSparseDtmcParameterLiftingModelChecker() = default;
+            
+            virtual void specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) override;
+
+        protected:
+            virtual SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType>& getImpreciseChecker() override;
+            virtual SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType> const& getImpreciseChecker() const override;
+            virtual SparseParameterLiftingModelChecker<SparseModelType, PreciseType>& getPreciseChecker() override;
+            virtual SparseParameterLiftingModelChecker<SparseModelType, PreciseType> const& getPreciseChecker() const override;
+            
+            virtual void applyHintsToPreciseChecker() override ;
+
+        private:
+            SparseDtmcParameterLiftingModelChecker<SparseModelType, ImpreciseType> impreciseChecker;
+            SparseDtmcParameterLiftingModelChecker<SparseModelType, PreciseType> preciseChecker;
+            
+        };
+    }
+}
diff --git a/src/storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.cpp
new file mode 100644
index 000000000..014cf6267
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.cpp
@@ -0,0 +1,71 @@
+#include "storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.h"
+#include "storm-pars/transformer/SparseParametricMdpSimplifier.h"
+
+#include "storm/models/sparse/Mdp.h"
+#include "storm/utility/macros.h"
+
+#include "storm/exceptions/UnexpectedException.h"
+
+namespace storm {
+    namespace modelchecker {
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        ValidatingSparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::ValidatingSparseMdpParameterLiftingModelChecker() {
+            // Intentionally left empty
+        }
+        
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        void ValidatingSparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) {
+            STORM_LOG_ASSERT(this->canHandle(parametricModel, checkTask), "specified model and formula can not be handled by this.");
+        
+            auto mdp = parametricModel->template as<SparseModelType>();
+            auto simplifier = storm::transformer::SparseParametricMdpSimplifier<SparseModelType>(*mdp);
+
+            if (!simplifier.simplify(checkTask.getFormula())) {
+                STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull.");
+            }
+            
+            auto simplifiedTask = checkTask.substituteFormula(*simplifier.getSimplifiedFormula());
+            
+            impreciseChecker.specify(simplifier.getSimplifiedModel(), simplifiedTask, true);
+            preciseChecker.specify(simplifier.getSimplifiedModel(), simplifiedTask, true);
+        }
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType>& ValidatingSparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getImpreciseChecker() {
+            return impreciseChecker;
+        }
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType> const& ValidatingSparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getImpreciseChecker() const {
+            return impreciseChecker;
+        }
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        SparseParameterLiftingModelChecker<SparseModelType, PreciseType>& ValidatingSparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getPreciseChecker() {
+            return preciseChecker;
+        }
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        SparseParameterLiftingModelChecker<SparseModelType, PreciseType> const& ValidatingSparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::getPreciseChecker() const {
+            return preciseChecker;
+        }
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        void ValidatingSparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::applyHintsToPreciseChecker() {
+        
+            if (impreciseChecker.getCurrentMaxScheduler()) {
+                preciseChecker.getCurrentMaxScheduler() = impreciseChecker.getCurrentMaxScheduler()->template toValueType<PreciseType>();
+            }
+            if (impreciseChecker.getCurrentMinScheduler()) {
+                preciseChecker.getCurrentMinScheduler() = impreciseChecker.getCurrentMinScheduler()->template toValueType<PreciseType>();
+            }
+            if (impreciseChecker.getCurrentPlayer1Scheduler()) {
+                preciseChecker.getCurrentPlayer1Scheduler() = impreciseChecker.getCurrentPlayer1Scheduler()->template toValueType<PreciseType>();
+            }
+        }
+            
+        template class ValidatingSparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber>;
+    }
+}
diff --git a/src/storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.h b/src/storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.h
new file mode 100644
index 000000000..1f56818c6
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/ValidatingSparseMdpParameterLiftingModelChecker.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.h"
+#include "storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.h"
+
+namespace storm {
+    namespace modelchecker {
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        class ValidatingSparseMdpParameterLiftingModelChecker : public ValidatingSparseParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType> {
+        public:
+            ValidatingSparseMdpParameterLiftingModelChecker();
+            virtual ~ValidatingSparseMdpParameterLiftingModelChecker() = default;
+            
+            virtual void specify(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) override;
+
+        protected:
+            virtual SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType>& getImpreciseChecker() override;
+            virtual SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType> const& getImpreciseChecker() const override;
+            virtual SparseParameterLiftingModelChecker<SparseModelType, PreciseType>& getPreciseChecker() override;
+            virtual SparseParameterLiftingModelChecker<SparseModelType, PreciseType> const& getPreciseChecker() const override;
+            
+            virtual void applyHintsToPreciseChecker() override ;
+
+        private:
+            SparseMdpParameterLiftingModelChecker<SparseModelType, ImpreciseType> impreciseChecker;
+            SparseMdpParameterLiftingModelChecker<SparseModelType, PreciseType> preciseChecker;
+            
+        };
+    }
+}
diff --git a/src/storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.cpp
new file mode 100644
index 000000000..d3dabab63
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.cpp
@@ -0,0 +1,73 @@
+#include "storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.h"
+
+#include "storm/adapters/RationalFunctionAdapter.h"
+#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
+#include "storm/settings/SettingsManager.h"
+#include "storm/settings/modules/CoreSettings.h"
+#include "storm/models/sparse/Dtmc.h"
+#include "storm/models/sparse/Mdp.h"
+
+namespace storm {
+    namespace modelchecker {
+       
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        ValidatingSparseParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::ValidatingSparseParameterLiftingModelChecker() : numOfWrongRegions(0) {
+            // Intentionally left empty
+        }
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        ValidatingSparseParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::~ValidatingSparseParameterLiftingModelChecker() {
+            if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) {
+                STORM_PRINT_AND_LOG("Validating Parameter Lifting Model Checker detected " << numOfWrongRegions << " regions where the imprecise method was wrong." << std::endl);
+            }
+        }
+        
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        bool ValidatingSparseParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const {
+            return getImpreciseChecker().canHandle(parametricModel, checkTask) && getPreciseChecker().canHandle(parametricModel, checkTask);
+        };
+ 
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        RegionResult ValidatingSparseParameterLiftingModelChecker<SparseModelType, ImpreciseType, PreciseType>::analyzeRegion(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionResult const& initialResult, bool sampleVerticesOfRegion) {
+        
+            RegionResult currentResult = getImpreciseChecker().analyzeRegion(region, initialResult);
+            
+            if (currentResult == RegionResult::AllSat || currentResult == RegionResult::AllViolated) {
+                applyHintsToPreciseChecker();
+                
+                storm::solver::OptimizationDirection parameterOptDir = getPreciseChecker().getCurrentCheckTask().getOptimizationDirection();
+                if (currentResult == RegionResult::AllViolated) {
+                    parameterOptDir = storm::solver::invert(parameterOptDir);
+                }
+                
+                bool preciseResult = getPreciseChecker().check(region, parameterOptDir)->asExplicitQualitativeCheckResult()[*getPreciseChecker().getConsideredParametricModel().getInitialStates().begin()];
+                bool preciseResultAgrees = preciseResult == (currentResult == RegionResult::AllSat);
+                
+                if (!preciseResultAgrees) {
+                    // Imprecise result is wrong!
+                    currentResult = RegionResult::Unknown;
+                    ++numOfWrongRegions;
+                    
+                    // Check the other direction
+                    parameterOptDir = storm::solver::invert(parameterOptDir);
+                    preciseResult = getPreciseChecker().check(region, parameterOptDir)->asExplicitQualitativeCheckResult()[*getPreciseChecker().getConsideredParametricModel().getInitialStates().begin()];
+                    if (preciseResult && parameterOptDir == getPreciseChecker().getCurrentCheckTask().getOptimizationDirection()) {
+                        currentResult = RegionResult::AllSat;
+                    } else if (!preciseResult && parameterOptDir == storm::solver::invert(getPreciseChecker().getCurrentCheckTask().getOptimizationDirection())) {
+                        currentResult = RegionResult::AllViolated;
+                    }
+                }
+            }
+            
+            if (sampleVerticesOfRegion && currentResult != RegionResult::AllSat && currentResult != RegionResult::AllViolated) {
+                currentResult = getPreciseChecker().sampleVertices(region, currentResult);
+            }
+    
+            return currentResult;
+        }
+
+        template class ValidatingSparseParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber>;
+        template class ValidatingSparseParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber>;
+
+    }
+}
diff --git a/src/storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.h b/src/storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.h
new file mode 100644
index 000000000..7f9789ebf
--- /dev/null
+++ b/src/storm-pars/modelchecker/region/ValidatingSparseParameterLiftingModelChecker.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "storm-pars/modelchecker/region/RegionModelChecker.h"
+#include "storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h"
+#include "storm-pars/storage/ParameterRegion.h"
+#include "storm/utility/NumberTraits.h"
+
+namespace storm {
+    namespace modelchecker {
+            
+        template <typename SparseModelType, typename ImpreciseType, typename PreciseType>
+        class ValidatingSparseParameterLiftingModelChecker : public RegionModelChecker<typename SparseModelType::ValueType> {
+            static_assert(storm::NumberTraits<PreciseType>::IsExact, "Specified type for exact computations is not exact.");
+
+        public:
+            ValidatingSparseParameterLiftingModelChecker();
+            virtual ~ValidatingSparseParameterLiftingModelChecker();
+            
+            virtual bool canHandle(std::shared_ptr<storm::models::ModelBase> parametricModel, CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const override;
+
+            /*!
+             * Analyzes the given region by means of parameter lifting.
+             * We first apply unsound solution methods (standard value iteratio with doubles) and then validate the obtained result
+             * by means of exact and soud methods.
+             */
+            virtual RegionResult analyzeRegion(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionResult const& initialResult = RegionResult::Unknown, bool sampleVerticesOfRegion = false) override;
+
+        protected:
+            
+            virtual SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType>& getImpreciseChecker() = 0;
+            virtual SparseParameterLiftingModelChecker<SparseModelType, ImpreciseType> const& getImpreciseChecker() const = 0;
+            virtual SparseParameterLiftingModelChecker<SparseModelType, PreciseType>& getPreciseChecker() = 0;
+            virtual SparseParameterLiftingModelChecker<SparseModelType, PreciseType> const& getPreciseChecker() const = 0;
+            
+            virtual void applyHintsToPreciseChecker() = 0;
+
+        private:
+            
+            // Information for statistics
+            uint_fast64_t numOfWrongRegions;
+            
+        };
+    }
+}
diff --git a/src/storm-pars/modelchecker/results/RegionCheckResult.cpp b/src/storm-pars/modelchecker/results/RegionCheckResult.cpp
new file mode 100644
index 000000000..2759034e9
--- /dev/null
+++ b/src/storm-pars/modelchecker/results/RegionCheckResult.cpp
@@ -0,0 +1,117 @@
+#include "storm-pars/modelchecker/results/RegionCheckResult.h"
+
+#include <map>
+
+#include "storm/adapters/RationalFunctionAdapter.h"
+#include "storm/utility/constants.h"
+#include "storm/utility/macros.h"
+
+namespace storm {
+    namespace modelchecker {
+
+        template<typename ValueType>
+        RegionCheckResult<ValueType>::RegionCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>> const& regionResults) : regionResults(regionResults) {
+            auto overallArea = storm::utility::zero<typename storm::storage::ParameterRegion<ValueType>::CoefficientType>();
+            for (auto const& res : this->regionResults) {
+                overallArea += res.first.area();
+            }
+            initFractions(overallArea);
+        }
+        
+        template<typename ValueType>
+        RegionCheckResult<ValueType>::RegionCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>>&& regionResults) : regionResults(std::move(regionResults)) {
+            auto overallArea = storm::utility::zero<typename storm::storage::ParameterRegion<ValueType>::CoefficientType>();
+            for (auto const& res : this->regionResults) {
+                overallArea += res.first.area();
+            }
+            initFractions(overallArea);
+        }
+
+        template<typename ValueType>
+        bool RegionCheckResult<ValueType>::isRegionCheckResult() const {
+            return true;
+        }
+        
+        template<typename ValueType>
+        bool RegionCheckResult<ValueType>::isRegionRefinementCheckResult() const {
+            return false;
+        }
+            
+        template<typename ValueType>
+        std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>> const& RegionCheckResult<ValueType>::getRegionResults() const {
+            return regionResults;
+        }
+        
+        template<typename ValueType>
+        typename storm::storage::ParameterRegion<ValueType>::CoefficientType const& RegionCheckResult<ValueType>::getSatFraction() const {
+            return satFraction;
+        }
+        
+        template<typename ValueType>
+        typename storm::storage::ParameterRegion<ValueType>::CoefficientType const& RegionCheckResult<ValueType>::getUnsatFraction() const {
+            return unsatFraction;
+        }
+
+        template<typename ValueType>
+        std::ostream& RegionCheckResult<ValueType>::writeToStream(std::ostream& out) const {
+            writeCondensedToStream(out);
+            out << std::endl << "Region results: " << std::endl;
+            for (auto const& res : this->regionResults) {
+                out << res.first.toString() << ": \t" << res.second << std::endl;
+            }
+            return out;
+        }
+        
+        template<typename ValueType>
+        std::ostream& RegionCheckResult<ValueType>::writeCondensedToStream(std::ostream& out) const {
+            double satPercent = storm::utility::convertNumber<double>(satFraction) * 100.0;
+            double unsatPercent = storm::utility::convertNumber<double>(unsatFraction) * 100.0;
+            auto oneHundred = storm::utility::convertNumber<typename storm::storage::ParameterRegion<ValueType>::CoefficientType>(100.0);
+            auto one = storm::utility::convertNumber<typename storm::storage::ParameterRegion<ValueType>::CoefficientType>(1.0);
+            out << "  Fraction of satisfied area: " << satPercent << "%" << std::endl;
+            out << "Fraction of unsatisfied area: " << unsatPercent << "%" << std::endl;
+            out << "            Unknown fraction: " << (100.0 - satPercent - unsatPercent) << "%" << std::endl;
+            out << "     Total number of regions: " << regionResults.size() << std::endl;
+            std::map<storm::modelchecker::RegionResult, uint_fast64_t> counters;
+            for (auto const& res : this->regionResults) {
+                ++counters[res.second];
+            }
+            for (auto const& counter : counters) {
+                out << std::setw(28) << counter.first << ": " << counter.second << std::endl;
+            }
+            return out;
+        }
+
+        template<typename ValueType>
+        std::ostream& RegionCheckResult<ValueType>::writeIllustrationToStream(std::ostream& out) const {
+            STORM_LOG_WARN("Writing illustration of region check result to a stream is not implemented.");
+            return out;
+        }
+  
+        template<typename ValueType>
+        void RegionCheckResult<ValueType>::initFractions(typename storm::storage::ParameterRegion<ValueType>::CoefficientType const& overallArea) {
+            auto satArea = storm::utility::zero<typename storm::storage::ParameterRegion<ValueType>::CoefficientType>();
+            auto unsatArea = storm::utility::zero<typename storm::storage::ParameterRegion<ValueType>::CoefficientType>();
+            for (auto const& res : this->regionResults) {
+                if (res.second == storm::modelchecker::RegionResult::AllSat) {
+                    satArea += res.first.area();
+                } else if (res.second == storm::modelchecker::RegionResult::AllViolated) {
+                    unsatArea += res.first.area();
+                }
+            }
+            satFraction = satArea / overallArea;
+            unsatFraction = unsatArea / overallArea;
+        }
+        
+        template<typename ValueType>
+        void RegionCheckResult<ValueType>::filter(QualitativeCheckResult const& filter) {
+            // Filtering has no effect as we only store the result w.r.t. a single state anyway.
+            // Hence, this is intentionally left empty.
+        }
+
+        
+#ifdef STORM_HAVE_CARL
+        template class RegionCheckResult<storm::RationalFunction>;
+#endif
+    }
+}
diff --git a/src/storm-pars/modelchecker/results/RegionCheckResult.h b/src/storm-pars/modelchecker/results/RegionCheckResult.h
new file mode 100644
index 000000000..7bb144cf6
--- /dev/null
+++ b/src/storm-pars/modelchecker/results/RegionCheckResult.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <vector>
+
+#include "storm/modelchecker/results/CheckResult.h"
+#include "storm-pars/modelchecker/region/RegionResult.h"
+#include "storm-pars/storage/ParameterRegion.h"
+
+namespace storm {
+    namespace modelchecker {
+        template<typename ValueType>
+        class RegionCheckResult : public CheckResult {
+        public:
+
+            RegionCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>> const& regionResults);
+            RegionCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>>&& regionResults);
+            virtual ~RegionCheckResult() = default;
+
+            virtual bool isRegionCheckResult() const;
+            virtual bool isRegionRefinementCheckResult() const;
+            
+            std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>> const& getRegionResults() const;
+            typename storm::storage::ParameterRegion<ValueType>::CoefficientType const& getSatFraction() const;
+            typename storm::storage::ParameterRegion<ValueType>::CoefficientType const& getUnsatFraction() const;
+            
+            virtual std::ostream& writeToStream(std::ostream& out) const override;
+            virtual std::ostream& writeCondensedToStream(std::ostream& out) const;
+            virtual std::ostream& writeIllustrationToStream(std::ostream& out) const;
+
+            virtual void filter(QualitativeCheckResult const& filter) override;
+            
+        protected:
+            virtual void initFractions(typename storm::storage::ParameterRegion<ValueType>::CoefficientType const& overallArea);
+            
+            std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>> regionResults;
+            typename storm::storage::ParameterRegion<ValueType>::CoefficientType satFraction, unsatFraction;
+
+        };
+    }
+}
diff --git a/src/storm-pars/modelchecker/results/RegionRefinementCheckResult.cpp b/src/storm-pars/modelchecker/results/RegionRefinementCheckResult.cpp
new file mode 100644
index 000000000..3cf8d1e1d
--- /dev/null
+++ b/src/storm-pars/modelchecker/results/RegionRefinementCheckResult.cpp
@@ -0,0 +1,100 @@
+#include "storm-pars/modelchecker/results/RegionRefinementCheckResult.h"
+
+#include <map>
+
+#include "storm/adapters/RationalFunctionAdapter.h"
+#include "storm/utility/constants.h"
+#include "storm/utility/macros.h"
+
+namespace storm {
+    namespace modelchecker {
+
+        template<typename ValueType>
+        RegionRefinementCheckResult<ValueType>::RegionRefinementCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>> const& regionResults, storm::storage::ParameterRegion<ValueType> const& parameterSpace) : RegionCheckResult<ValueType>(regionResults), parameterSpace(parameterSpace) {
+            this->initFractions(this->parameterSpace.area());
+        }
+        
+        
+        template<typename ValueType>
+        RegionRefinementCheckResult<ValueType>::RegionRefinementCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>>&& regionResults, storm::storage::ParameterRegion<ValueType>&& parameterSpace) : RegionCheckResult<ValueType>(std::move(regionResults)), parameterSpace(std::move(parameterSpace)) {
+            this->initFractions(this->parameterSpace.area());
+        }
+        
+        template<typename ValueType>
+        bool RegionRefinementCheckResult<ValueType>::isRegionRefinementCheckResult() const {
+            return true;
+        }
+        
+        template<typename ValueType>
+        storm::storage::ParameterRegion<ValueType> const& RegionRefinementCheckResult<ValueType>::getParameterSpace() const {
+            return parameterSpace;
+        }
+
+        template<typename ValueType>
+        std::ostream& RegionRefinementCheckResult<ValueType>::writeIllustrationToStream(std::ostream& out) const {
+            if (this->getParameterSpace().getVariables().size() == 2) {
+                
+                typedef typename storm::storage::ParameterRegion<ValueType>::CoefficientType CoefficientType;
+                auto x = *this->getParameterSpace().getVariables().begin();
+                auto y = *(this->getParameterSpace().getVariables().rbegin());
+            
+                uint_fast64_t const sizeX = 128;
+                uint_fast64_t const sizeY = 64;
+                
+                out << "Region refinement Check result (visualization):" << std::endl;
+                out << " \t x-axis: " << x << "  \t y-axis: " << y << "  \t S=safe, [ ]=unsafe, -=ambiguous " << std::endl;
+                for (uint_fast64_t i = 0; i < sizeX+2; ++i) out << "#"; out << std::endl;
+                
+                CoefficientType deltaX = (getParameterSpace().getUpperBoundary(x) - getParameterSpace().getLowerBoundary(x)) / storm::utility::convertNumber<CoefficientType>(sizeX);
+                CoefficientType deltaY = (getParameterSpace().getUpperBoundary(y) - getParameterSpace().getLowerBoundary(y)) / storm::utility::convertNumber<CoefficientType>(sizeY);
+                CoefficientType printedRegionArea = deltaX * deltaY;
+                for (CoefficientType yUpper = getParameterSpace().getUpperBoundary(y); yUpper != getParameterSpace().getLowerBoundary(y); yUpper -= deltaY) {
+                    CoefficientType yLower = yUpper - deltaY;
+                    out << "#";
+                    for (CoefficientType xLower = getParameterSpace().getLowerBoundary(x); xLower != getParameterSpace().getUpperBoundary(x); xLower += deltaX) {
+                        CoefficientType xUpper = xLower + deltaX;
+                        bool currRegionSafe = false;
+                        bool currRegionUnSafe = false;
+                        bool currRegionComplete = false;
+                        CoefficientType coveredArea = storm::utility::zero<CoefficientType>();
+                        for (auto const& r : this->getRegionResults()) {
+                            CoefficientType interesctionSizeY = std::min(yUpper, r.first.getUpperBoundary(y)) - std::max(yLower, r.first.getLowerBoundary(y));
+                            interesctionSizeY = std::max(interesctionSizeY, storm::utility::zero<CoefficientType>());
+                            CoefficientType interesctionSizeX = std::min(xUpper, r.first.getUpperBoundary(x)) - std::max(xLower, r.first.getLowerBoundary(x));
+                            interesctionSizeX = std::max(interesctionSizeX, storm::utility::zero<CoefficientType>());
+                            CoefficientType instersectionArea =  interesctionSizeY * interesctionSizeX;
+                            if(!storm::utility::isZero(instersectionArea)) {
+                                currRegionSafe = currRegionSafe || r.second == storm::modelchecker::RegionResult::AllSat;
+                                currRegionUnSafe = currRegionUnSafe || r.second == storm::modelchecker::RegionResult::AllViolated;
+                                coveredArea += instersectionArea;
+                                if(currRegionSafe && currRegionUnSafe) {
+                                    break;
+                                }
+                                if(coveredArea == printedRegionArea) {
+                                    currRegionComplete = true;
+                                    break;
+                                }
+                            }
+                        }
+                        if (currRegionComplete && currRegionSafe && !currRegionUnSafe) {
+                            out << "S";
+                        } else if (currRegionComplete && currRegionUnSafe && !currRegionSafe) {
+                            out << " ";
+                        } else {
+                            out << "-";
+                        }
+                    }
+                    out << "#" << std::endl;
+                }
+                for (uint_fast64_t i = 0; i < sizeX+2; ++i) out << "#"; out << std::endl;
+            } else {
+                STORM_LOG_WARN("Writing illustration of region check result to a stream is only implemented for two parameters.");
+            }
+            return out;
+        }
+        
+#ifdef STORM_HAVE_CARL
+        template class RegionRefinementCheckResult<storm::RationalFunction>;
+#endif
+    }
+}
diff --git a/src/storm-pars/modelchecker/results/RegionRefinementCheckResult.h b/src/storm-pars/modelchecker/results/RegionRefinementCheckResult.h
new file mode 100644
index 000000000..8b37afcca
--- /dev/null
+++ b/src/storm-pars/modelchecker/results/RegionRefinementCheckResult.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <vector>
+
+#include "storm-pars/modelchecker/results/RegionCheckResult.h"
+#include "storm-pars/modelchecker/region/RegionResult.h"
+#include "storm-pars/storage/ParameterRegion.h"
+
+namespace storm {
+    namespace modelchecker {
+        template<typename ValueType>
+        class RegionRefinementCheckResult : public RegionCheckResult<ValueType> {
+        public:
+
+            RegionRefinementCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>> const& regionResults, storm::storage::ParameterRegion<ValueType> const& parameterSpace);
+            RegionRefinementCheckResult(std::vector<std::pair<storm::storage::ParameterRegion<ValueType>, storm::modelchecker::RegionResult>>&& regionResults, storm::storage::ParameterRegion<ValueType>&& parameterSpace);
+            virtual ~RegionRefinementCheckResult() = default;
+
+            virtual bool isRegionRefinementCheckResult() const override;
+            
+            storm::storage::ParameterRegion<ValueType> const& getParameterSpace() const;
+
+            virtual std::ostream& writeIllustrationToStream(std::ostream& out) const override;
+            
+
+        protected:
+            storm::storage::ParameterRegion<ValueType> parameterSpace;
+        };
+    }
+}
diff --git a/src/storm-pars/parser/ParameterRegionParser.cpp b/src/storm-pars/parser/ParameterRegionParser.cpp
new file mode 100644
index 000000000..f6345eef1
--- /dev/null
+++ b/src/storm-pars/parser/ParameterRegionParser.cpp
@@ -0,0 +1,97 @@
+#include "storm-pars/parser/ParameterRegionParser.h"
+
+#include "storm/utility/macros.h"
+#include "storm/exceptions/InvalidArgumentException.h"
+#include "storm/utility/constants.h"
+#include "storm/utility/file.h"
+
+namespace storm {
+    namespace parser {
+
+        template<typename ParametricType>
+        void ParameterRegionParser<ParametricType>::parseParameterBoundaries(Valuation& lowerBoundaries, Valuation& upperBoundaries, std::string const& parameterBoundariesString, std::set<VariableType> const& consideredVariables) {
+            
+            std::string::size_type positionOfFirstRelation = parameterBoundariesString.find("<=");
+            STORM_LOG_THROW(positionOfFirstRelation!=std::string::npos, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find  a '<=' after the first number");
+            std::string::size_type positionOfSecondRelation = parameterBoundariesString.find("<=", positionOfFirstRelation+2);
+            STORM_LOG_THROW(positionOfSecondRelation!=std::string::npos, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find  a '<=' after the parameter");
+
+            std::string parameter = parameterBoundariesString.substr(positionOfFirstRelation+2,positionOfSecondRelation-(positionOfFirstRelation+2));
+            //removes all whitespaces from the parameter string:
+            parameter.erase(std::remove_if (parameter.begin(), parameter.end(), ::isspace), parameter.end());
+            STORM_LOG_THROW(parameter.length()>0, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find a parameter");
+
+            std::unique_ptr<VariableType> var;
+            for (auto const& v : consideredVariables) {
+                std::stringstream stream;
+                stream << v;
+                std::string vAsString = stream.str();
+                if (parameter == stream.str()) {
+                    var = std::make_unique<VariableType>(v);
+                }
+            }
+            STORM_LOG_ASSERT(var, "Could not find parameter " << parameter << " in the set of considered variables");
+            
+            CoefficientType lb = storm::utility::convertNumber<CoefficientType>(parameterBoundariesString.substr(0,positionOfFirstRelation));
+            CoefficientType ub = storm::utility::convertNumber<CoefficientType>(parameterBoundariesString.substr(positionOfSecondRelation+2));
+            lowerBoundaries.emplace(std::make_pair(*var, lb));
+            upperBoundaries.emplace(std::make_pair(*var, ub));
+        }
+
+        template<typename ParametricType>
+        storm::storage::ParameterRegion<ParametricType> ParameterRegionParser<ParametricType>::parseRegion(std::string const& regionString, std::set<VariableType> const& consideredVariables) {
+            Valuation lowerBoundaries;
+            Valuation upperBoundaries;
+            std::vector<std::string> parameterBoundaries;
+            boost::split(parameterBoundaries, regionString, boost::is_any_of(","));
+            for (auto const& parameterBoundary : parameterBoundaries){
+                if (!std::all_of(parameterBoundary.begin(),parameterBoundary.end(), ::isspace)){ //skip this string if it only consists of space
+                    parseParameterBoundaries(lowerBoundaries, upperBoundaries, parameterBoundary, consideredVariables);
+                }
+            }
+            return storm::storage::ParameterRegion<ParametricType>(std::move(lowerBoundaries), std::move(upperBoundaries));
+        }
+
+        template<typename ParametricType>
+        std::vector<storm::storage::ParameterRegion<ParametricType>> ParameterRegionParser<ParametricType>::parseMultipleRegions(std::string const& regionsString, std::set<VariableType> const& consideredVariables) {
+            std::vector<storm::storage::ParameterRegion<ParametricType>> result;
+            std::vector<std::string> regionsStrVec;
+            boost::split(regionsStrVec, regionsString, boost::is_any_of(";"));
+            for (auto const& regionStr : regionsStrVec){
+                if (!std::all_of(regionStr.begin(),regionStr.end(), ::isspace)){ //skip this string if it only consists of space
+                    result.emplace_back(parseRegion(regionStr, consideredVariables));
+                }
+            }
+            return result;
+        }
+
+        template<typename ParametricType>
+        std::vector<storm::storage::ParameterRegion<ParametricType>> ParameterRegionParser<ParametricType>::parseMultipleRegionsFromFile(std::string const& fileName, std::set<VariableType> const& consideredVariables) {
+     
+            // Open file and initialize result.
+            std::ifstream inputFileStream;
+            storm::utility::openFile(fileName, inputFileStream);
+            
+            std::vector<storm::storage::ParameterRegion<ParametricType>> result;
+            
+            // Now try to parse the contents of the file.
+            try {
+                std::string fileContent((std::istreambuf_iterator<char>(inputFileStream)), (std::istreambuf_iterator<char>()));
+                result = parseMultipleRegions(fileContent, consideredVariables);
+            } catch(std::exception& e) {
+                // In case of an exception properly close the file before passing exception.
+                storm::utility::closeFile(inputFileStream);
+                throw e;
+            }
+            
+            // Close the stream in case everything went smoothly and return result.
+            storm::utility::closeFile(inputFileStream);
+            return result;
+        }
+        
+#ifdef STORM_HAVE_CARL
+            template class ParameterRegionParser<storm::RationalFunction>;
+#endif
+    }
+}
+
diff --git a/src/storm-pars/parser/ParameterRegionParser.h b/src/storm-pars/parser/ParameterRegionParser.h
new file mode 100644
index 000000000..99063a4d6
--- /dev/null
+++ b/src/storm-pars/parser/ParameterRegionParser.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <map>
+
+#include "storm-pars/storage/ParameterRegion.h"
+
+namespace storm {
+    namespace parser {
+        template<typename ParametricType>
+        class ParameterRegionParser{
+        public:
+
+            typedef typename storm::storage::ParameterRegion<ParametricType>::VariableType VariableType;
+            typedef typename storm::storage::ParameterRegion<ParametricType>::CoefficientType CoefficientType;
+            typedef typename storm::storage::ParameterRegion<ParametricType>::Valuation Valuation;
+            
+            /*
+             * Parse a single parameter with its boundaries from a string of the form "0.3<=p<=0.5".
+             * The results will be inserted in the given maps
+             *
+             */
+            static void parseParameterBoundaries( Valuation& lowerBoundaries, Valuation& upperBoundaries, std::string const& parameterBoundariesString, std::set<VariableType> const& consideredVariables);
+
+            /*
+             * Parse a single region from a string of the form "0.3<=p<=0.5,0.4<=q<=0.7".
+             *
+             */
+            static storm::storage::ParameterRegion<ParametricType> parseRegion(std::string const& regionString, std::set<VariableType> const& consideredVariables);
+
+            /*
+             * Parse a vector of region from a string of the form "0.3<=p<=0.5,0.4<=q<=0.7;0.1<=p<=0.3,0.2<=q<=0.4".
+             *
+             */
+            static std::vector<storm::storage::ParameterRegion<ParametricType>> parseMultipleRegions(std::string const& regionsString, std::set<VariableType> const& consideredVariables);
+            
+
+            /*
+             * Parse multiple regions from a file
+             *
+             */
+            static std::vector<storm::storage::ParameterRegion<ParametricType>> parseMultipleRegionsFromFile(std::string const& fileName, std::set<VariableType> const& consideredVariables);
+            
+        };
+    }
+}
+
+
diff --git a/src/storm-pars/settings/ParsSettings.cpp b/src/storm-pars/settings/ParsSettings.cpp
new file mode 100644
index 000000000..53907dc1c
--- /dev/null
+++ b/src/storm-pars/settings/ParsSettings.cpp
@@ -0,0 +1,53 @@
+#include "storm-pars/settings/ParsSettings.h"
+
+#include "storm-pars/settings/modules/ParametricSettings.h"
+#include "storm-pars/settings/modules/RegionSettings.h"
+
+#include "storm/settings/SettingsManager.h"
+#include "storm/settings/modules/GeneralSettings.h"
+#include "storm/settings/modules/CoreSettings.h"
+#include "storm/settings/modules/IOSettings.h"
+#include "storm/settings/modules/DebugSettings.h"
+#include "storm/settings/modules/SylvanSettings.h"
+#include "storm/settings/modules/EigenEquationSolverSettings.h"
+#include "storm/settings/modules/GmmxxEquationSolverSettings.h"
+#include "storm/settings/modules/NativeEquationSolverSettings.h"
+#include "storm/settings/modules/EliminationSettings.h"
+#include "storm/settings/modules/MinMaxEquationSolverSettings.h"
+#include "storm/settings/modules/GameSolverSettings.h"
+#include "storm/settings/modules/BisimulationSettings.h"
+#include "storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h"
+#include "storm/settings/modules/ResourceSettings.h"
+#include "storm/settings/modules/JaniExportSettings.h"
+#include "storm/settings/modules/JitBuilderSettings.h"
+
+
+namespace storm {
+    namespace settings {
+        void initializeParsSettings(std::string const& name, std::string const& executableName) {
+            storm::settings::mutableManager().setName(name, executableName);
+        
+            // Register relevant settings modules.
+            storm::settings::addModule<storm::settings::modules::GeneralSettings>();
+            storm::settings::addModule<storm::settings::modules::IOSettings>();
+            storm::settings::addModule<storm::settings::modules::CoreSettings>();
+            storm::settings::addModule<storm::settings::modules::ParametricSettings>();
+            storm::settings::addModule<storm::settings::modules::RegionSettings>();
+            
+            storm::settings::addModule<storm::settings::modules::DebugSettings>();
+            storm::settings::addModule<storm::settings::modules::SylvanSettings>();
+            storm::settings::addModule<storm::settings::modules::GmmxxEquationSolverSettings>();
+            storm::settings::addModule<storm::settings::modules::EigenEquationSolverSettings>();
+            storm::settings::addModule<storm::settings::modules::NativeEquationSolverSettings>();
+            storm::settings::addModule<storm::settings::modules::EliminationSettings>();
+            storm::settings::addModule<storm::settings::modules::MinMaxEquationSolverSettings>();
+            storm::settings::addModule<storm::settings::modules::GameSolverSettings>();
+            storm::settings::addModule<storm::settings::modules::BisimulationSettings>();
+            storm::settings::addModule<storm::settings::modules::TopologicalValueIterationEquationSolverSettings>();
+            storm::settings::addModule<storm::settings::modules::ResourceSettings>();
+            storm::settings::addModule<storm::settings::modules::JaniExportSettings>();
+            storm::settings::addModule<storm::settings::modules::JitBuilderSettings>();
+        }
+    
+    }
+}
\ No newline at end of file
diff --git a/src/storm-pars/settings/ParsSettings.h b/src/storm-pars/settings/ParsSettings.h
new file mode 100644
index 000000000..724fa2a44
--- /dev/null
+++ b/src/storm-pars/settings/ParsSettings.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <string>
+
+namespace storm {
+    namespace settings {
+        
+        void initializeParsSettings(std::string const& name, std::string const& executableName);
+        
+    }
+}
\ No newline at end of file
diff --git a/src/storm-pars/settings/modules/ParametricSettings.cpp b/src/storm-pars/settings/modules/ParametricSettings.cpp
new file mode 100644
index 000000000..a50ef941e
--- /dev/null
+++ b/src/storm-pars/settings/modules/ParametricSettings.cpp
@@ -0,0 +1,47 @@
+#include "storm-pars/settings/modules/ParametricSettings.h"
+
+#include "storm/settings/Option.h"
+#include "storm/settings/OptionBuilder.h"
+#include "storm/settings/ArgumentBuilder.h"
+#include "storm/settings/Argument.h"
+
+#include "storm/utility/macros.h"
+#include "storm/exceptions/IllegalArgumentValueException.h"
+
+namespace storm {
+    namespace settings {
+        namespace modules {
+            
+            const std::string ParametricSettings::moduleName = "parametric";
+            const std::string ParametricSettings::exportResultOptionName = "resultfile";
+            const std::string ParametricSettings::derivativesOptionName = "derivatives";
+            const std::string ParametricSettings::transformContinuousOptionName = "transformcontinuous";
+            const std::string ParametricSettings::transformContinuousShortOptionName = "tc";
+            
+            ParametricSettings::ParametricSettings() : ModuleSettings(moduleName) {
+                this->addOption(storm::settings::OptionBuilder(moduleName, exportResultOptionName, false, "A path to a file where the parametric result should be saved.")
+                                .addArgument(storm::settings::ArgumentBuilder::createStringArgument("path", "the location.").addValidatorString(ArgumentValidatorFactory::createWritableFileValidator()).build()).build());
+                this->addOption(storm::settings::OptionBuilder(moduleName, derivativesOptionName, false, "Sets whether to generate the derivatives of the resulting rational function.").build());
+                this->addOption(storm::settings::OptionBuilder(moduleName, transformContinuousOptionName, false, "Sets whether to transform a continuous time input model to a discrete time model.").setShortName(transformContinuousShortOptionName).build());
+            }
+            
+            bool ParametricSettings::exportResultToFile() const {
+                return this->getOption(exportResultOptionName).getHasOptionBeenSet();
+            }
+            
+            std::string ParametricSettings::exportResultPath() const {
+                return this->getOption(exportResultOptionName).getArgumentByName("path").getValueAsString();
+            }
+            
+            bool ParametricSettings::isDerivativesSet() const {
+                return this->getOption(derivativesOptionName).getHasOptionBeenSet();
+            }
+            
+            bool ParametricSettings::transformContinuousModel() const {
+                return this->getOption(transformContinuousOptionName).getHasOptionBeenSet();
+            }
+            
+
+        } // namespace modules
+    } // namespace settings
+} // namespace storm
diff --git a/src/storm-pars/settings/modules/ParametricSettings.h b/src/storm-pars/settings/modules/ParametricSettings.h
new file mode 100644
index 000000000..436faa92d
--- /dev/null
+++ b/src/storm-pars/settings/modules/ParametricSettings.h
@@ -0,0 +1,58 @@
+#ifndef STORM_SETTINGS_MODULES_PARAMETRICSETTINGS_H_
+#define STORM_SETTINGS_MODULES_PARAMETRICSETTINGS_H_
+
+#include "storm/settings/modules/ModuleSettings.h"
+
+namespace storm {
+    namespace settings {
+        namespace modules {
+
+            /*!
+             * This class represents the settings for parametric model checking.
+             */
+            class ParametricSettings : public ModuleSettings {
+            public:
+                
+                /*!
+                 * Creates a new set of parametric model checking settings.
+                 */
+                ParametricSettings();
+				
+				/**
+				 * Retrieves whether the model checking result should be exported to a file.
+                 * @return  True iff the result should be exported to a file.
+                 */
+				bool exportResultToFile() const;
+				
+				/**
+				 * The path to a file location which should contain the model checking result.
+                 * @return A path to a file location.
+                 */
+				std::string exportResultPath() const;
+				
+               /*!
+                 * Retrieves whether or not derivatives of the resulting rational function are to be generated.
+                 *
+                 * @return True if the derivatives are to be generated.
+                 */
+                bool isDerivativesSet() const;
+                
+                /*!
+                 * Retrieves whether Continuous time models should be transformed to discrete time models
+                 */
+                bool transformContinuousModel() const;
+				
+                const static std::string moduleName;
+                
+            private:
+				const static std::string exportResultOptionName;
+                const static std::string derivativesOptionName;
+                const static std::string transformContinuousOptionName;
+                const static std::string transformContinuousShortOptionName;
+            };
+            
+        } // namespace modules
+    } // namespace settings
+} // namespace storm
+
+#endif /* STORM_SETTINGS_MODULES_PARAMETRICSETTINGS_H_ */
diff --git a/src/storm-pars/settings/modules/RegionSettings.cpp b/src/storm-pars/settings/modules/RegionSettings.cpp
new file mode 100644
index 000000000..2dba3c300
--- /dev/null
+++ b/src/storm-pars/settings/modules/RegionSettings.cpp
@@ -0,0 +1,83 @@
+#include "storm-pars/settings/modules/RegionSettings.h"
+
+#include "storm/settings/Option.h"
+#include "storm/settings/OptionBuilder.h"
+#include "storm/settings/ArgumentBuilder.h"
+#include "storm/settings/Argument.h"
+
+#include "storm/utility/macros.h"
+#include "storm/exceptions/IllegalArgumentValueException.h"
+
+namespace storm {
+    namespace settings {
+        namespace modules {
+            
+            const std::string RegionSettings::moduleName = "region";
+            const std::string RegionSettings::regionOptionName = "region";
+            const std::string RegionSettings::regionShortOptionName = "reg";
+            const std::string RegionSettings::refineOptionName = "refine";
+            const std::string RegionSettings::checkEngineOptionName = "engine";
+            const std::string RegionSettings::printNoIllustrationOptionName = "noillustration";
+            const std::string RegionSettings::printFullResultOptionName = "printfullresult";
+            
+            RegionSettings::RegionSettings() : ModuleSettings(moduleName) {
+                this->addOption(storm::settings::OptionBuilder(moduleName, regionOptionName, false, "Sets the region(s) considered for analysis.").setShortName(regionShortOptionName)
+                                .addArgument(storm::settings::ArgumentBuilder::createStringArgument("regioninput", "The region(s) given in format a<=x<=b,c<=y<=d seperated by ';'. Can also be a file.").build()).build());
+                
+                this->addOption(storm::settings::OptionBuilder(moduleName, refineOptionName, false, "Enables region refinement.")
+                                .addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("threshold", "Refinement converges if the fraction of unknown area falls below this threshold.").setDefaultValueDouble(0.05).addValidatorDouble(storm::settings::ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0,1.0)).build()).build());
+                
+                std::vector<std::string> engines = {"pl", "exactpl", "validatingpl"};
+                this->addOption(storm::settings::OptionBuilder(moduleName, checkEngineOptionName, true, "Sets which engine is used for analyzing regions.")
+                                .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the engine to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(engines)).setDefaultValueString("pl").build()).build());
+
+                this->addOption(storm::settings::OptionBuilder(moduleName, printNoIllustrationOptionName, false, "If set, no illustration of the result is printed.").build());
+                
+                this->addOption(storm::settings::OptionBuilder(moduleName, printFullResultOptionName, false, "If set, the full result for every region is printed.").build());
+            }
+            
+            bool RegionSettings::isRegionSet() const {
+                return this->getOption(regionOptionName).getHasOptionBeenSet();
+            }
+            
+            std::string RegionSettings::getRegionString() const {
+                return this->getOption(regionOptionName).getArgumentByName("regioninput").getValueAsString();
+            }
+            
+            bool RegionSettings::isRefineSet() const {
+                return this->getOption(refineOptionName).getHasOptionBeenSet();
+            }
+            
+            double RegionSettings::getRefinementThreshold() const {
+                return this->getOption(refineOptionName).getArgumentByName("threshold").getValueAsDouble();
+            }
+            
+            storm::modelchecker::RegionCheckEngine RegionSettings::getRegionCheckEngine() const {
+                std::string engineString = this->getOption(checkEngineOptionName).getArgumentByName("name").getValueAsString();
+                
+                storm::modelchecker::RegionCheckEngine result;
+                if (engineString == "pl") {
+                    result = storm::modelchecker::RegionCheckEngine::ParameterLifting;
+                } else if (engineString == "exactpl") {
+                    result = storm::modelchecker::RegionCheckEngine::ExactParameterLifting;
+                } else if (engineString == "validatingpl") {
+                    result = storm::modelchecker::RegionCheckEngine::ValidatingParameterLifting;
+                } else {
+                    STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown region check engine '" << engineString << "'.");
+                }
+                
+                return result;
+            }
+            
+            bool RegionSettings::isPrintNoIllustrationSet() const {
+                return this->getOption(printNoIllustrationOptionName).getHasOptionBeenSet();
+            }
+            
+            bool RegionSettings::isPrintFullResultSet() const {
+                return this->getOption(printFullResultOptionName).getHasOptionBeenSet();
+            }
+            
+
+        } // namespace modules
+    } // namespace settings
+} // namespace storm
diff --git a/src/storm-pars/settings/modules/RegionSettings.h b/src/storm-pars/settings/modules/RegionSettings.h
new file mode 100644
index 000000000..e668a3146
--- /dev/null
+++ b/src/storm-pars/settings/modules/RegionSettings.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include "storm-pars/modelchecker/region/RegionCheckEngine.h"
+
+#include "storm/settings/modules/ModuleSettings.h"
+
+namespace storm {
+    namespace settings {
+        namespace modules {
+
+            /*!
+             * This class represents the settings for parametric model checking.
+             */
+            class RegionSettings : public ModuleSettings {
+            public:
+                
+                /*!
+                 * Creates a new set of parametric model checking settings.
+                 */
+                RegionSettings();
+				
+				/*!
+				 * Retrieves whether region(s) were declared
+				 */
+				bool isRegionSet() const;
+				
+				/*!
+				 * Retrieves the region definition string
+				 */
+				std::string getRegionString() const;
+				
+				/*!
+				 * Retrieves whether region refinement is enabled
+				 */
+				bool isRefineSet() const;
+				
+				/*!
+				 * Retrieves the threshold considered for iterative region refinement.
+				 * The refinement converges as soon as the fraction of unknown area falls below this threshold
+				 */
+				double getRefinementThreshold() const;
+				
+				/*!
+				 * Retrieves which type of region check should be performed
+				 */
+				storm::modelchecker::RegionCheckEngine getRegionCheckEngine() const;
+				
+				/*!
+				 * Retrieves whether no illustration of the result should be printed.
+				 */
+                bool isPrintNoIllustrationSet() const;
+                
+                /*!
+                 * Retrieves whether the full result should be printed
+                 */
+                bool isPrintFullResultSet() const;
+                
+                const static std::string moduleName;
+                
+            private:
+				const static std::string regionOptionName;
+				const static std::string regionShortOptionName;
+				const static std::string refineOptionName;
+				const static std::string checkEngineOptionName;
+				const static std::string printNoIllustrationOptionName;
+				const static std::string printFullResultOptionName;
+            };
+            
+        } // namespace modules
+    } // namespace settings
+} // namespace storm
+
diff --git a/src/storm/storage/ParameterRegion.cpp b/src/storm-pars/storage/ParameterRegion.cpp
similarity index 71%
rename from src/storm/storage/ParameterRegion.cpp
rename to src/storm-pars/storage/ParameterRegion.cpp
index 9e5287d05..3d9e36c93 100644
--- a/src/storm/storage/ParameterRegion.cpp
+++ b/src/storm-pars/storage/ParameterRegion.cpp
@@ -1,13 +1,17 @@
-#include "ParameterRegion.h"
+#include "storm-pars/storage/ParameterRegion.h"
 
 #include "storm/utility/macros.h"
 #include "storm/exceptions/InvalidArgumentException.h"
 #include "storm/utility/constants.h"
-#include "storm/utility/file.h"
 
 namespace storm {
     namespace storage {
 
+        template<typename ParametricType>
+        ParameterRegion<ParametricType>::ParameterRegion() {
+            init();
+        }
+        
         template<typename ParametricType>
         ParameterRegion<ParametricType>::ParameterRegion(Valuation const& lowerBoundaries, Valuation const& upperBoundaries) : lowerBoundaries(lowerBoundaries), upperBoundaries(upperBoundaries) {
             init();
@@ -164,67 +168,17 @@ namespace storm {
             regionstring = regionstring.substr(0, regionstring.length() - 1) + ";";
             return regionstring;
         }
-
-
-        template<typename ParametricType>
-        void ParameterRegion<ParametricType>::parseParameterBoundaries(Valuation& lowerBoundaries, Valuation& upperBoundaries, std::string const& parameterBoundariesString, std::set<VariableType> const& consideredVariables) {
-            
-            std::string::size_type positionOfFirstRelation = parameterBoundariesString.find("<=");
-            STORM_LOG_THROW(positionOfFirstRelation!=std::string::npos, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find  a '<=' after the first number");
-            std::string::size_type positionOfSecondRelation = parameterBoundariesString.find("<=", positionOfFirstRelation+2);
-            STORM_LOG_THROW(positionOfSecondRelation!=std::string::npos, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find  a '<=' after the parameter");
-
-            std::string parameter = parameterBoundariesString.substr(positionOfFirstRelation+2,positionOfSecondRelation-(positionOfFirstRelation+2));
-            //removes all whitespaces from the parameter string:
-            parameter.erase(std::remove_if(parameter.begin(), parameter.end(), ::isspace), parameter.end());
-            STORM_LOG_THROW(parameter.length()>0, storm::exceptions::InvalidArgumentException, "When parsing the region" << parameterBoundariesString << " I could not find a parameter");
-
-            std::unique_ptr<VariableType> var;
-            for (auto const& v : consideredVariables) {
-                std::stringstream stream;
-                stream << v;
-                std::string vAsString = stream.str();
-                if(parameter == stream.str()) {
-                    var = std::make_unique<VariableType>(v);
-                }
-            }
-            STORM_LOG_ASSERT(var, "Could not find parameter " << parameter << " in the set of considered variables");
-            
-            CoefficientType lb = storm::utility::convertNumber<CoefficientType>(parameterBoundariesString.substr(0,positionOfFirstRelation));
-            CoefficientType ub = storm::utility::convertNumber<CoefficientType>(parameterBoundariesString.substr(positionOfSecondRelation+2));
-            lowerBoundaries.emplace(std::make_pair(*var, lb));
-            upperBoundaries.emplace(std::make_pair(*var, ub));
-        }
-
-        template<typename ParametricType>
-        ParameterRegion<ParametricType> ParameterRegion<ParametricType>::parseRegion(std::string const& regionString, std::set<VariableType> const& consideredVariables) {
-            Valuation lowerBoundaries;
-            Valuation upperBoundaries;
-            std::vector<std::string> parameterBoundaries;
-            boost::split(parameterBoundaries, regionString, boost::is_any_of(","));
-            for(auto const& parameterBoundary : parameterBoundaries){
-                if(!std::all_of(parameterBoundary.begin(),parameterBoundary.end(), ::isspace)){ //skip this string if it only consists of space
-                    parseParameterBoundaries(lowerBoundaries, upperBoundaries, parameterBoundary, consideredVariables);
-                }
-            }
-            return ParameterRegion(std::move(lowerBoundaries), std::move(upperBoundaries));
+        
+        template <typename ParametricType>
+        std::ostream& operator<<(std::ostream& out, ParameterRegion<ParametricType> const& region) {
+            out << region.toString();
+            return out;
         }
 
-        template<typename ParametricType>
-        std::vector<ParameterRegion<ParametricType>> ParameterRegion<ParametricType>::parseMultipleRegions(std::string const& regionsString, std::set<VariableType> const& consideredVariables) {
-            std::vector<ParameterRegion> result;
-            std::vector<std::string> regionsStrVec;
-            boost::split(regionsStrVec, regionsString, boost::is_any_of(";"));
-            for(auto const& regionStr : regionsStrVec){
-                if(!std::all_of(regionStr.begin(),regionStr.end(), ::isspace)){ //skip this string if it only consists of space
-                    result.emplace_back(parseRegion(regionStr, consideredVariables));
-                }
-            }
-            return result;
-        }
-            
+        
 #ifdef STORM_HAVE_CARL
             template class ParameterRegion<storm::RationalFunction>;
+            template std::ostream& operator<<(std::ostream& out, ParameterRegion<storm::RationalFunction> const& region);
 #endif
     }
 }
diff --git a/src/storm/storage/ParameterRegion.h b/src/storm-pars/storage/ParameterRegion.h
similarity index 68%
rename from src/storm/storage/ParameterRegion.h
rename to src/storm-pars/storage/ParameterRegion.h
index add11e0be..95a98aa87 100644
--- a/src/storm/storage/ParameterRegion.h
+++ b/src/storm-pars/storage/ParameterRegion.h
@@ -2,7 +2,7 @@
 
 #include <map>
 
-#include "storm/utility/parametric.h"
+#include "storm-pars/utility/parametric.h"
 
 namespace storm {
     namespace storage {
@@ -13,6 +13,7 @@ namespace storm {
             typedef typename storm::utility::parametric::CoefficientType<ParametricType>::type CoefficientType;
             typedef typename storm::utility::parametric::Valuation<ParametricType> Valuation;
             
+            ParameterRegion();
             ParameterRegion(Valuation const& lowerBoundaries, Valuation const& upperBoundaries);
             ParameterRegion(Valuation&& lowerBoundaries, Valuation&& upperBoundaries);
             ParameterRegion(ParameterRegion const& other) = default;
@@ -62,28 +63,6 @@ namespace storm {
             //returns the region as string in the format 0.3<=p<=0.4,0.2<=q<=0.5;
             std::string toString(bool boundariesAsDouble = false) const;
 
-            /*
-             * Can be used to parse a single parameter with its boundaries from a string of the form "0.3<=p<=0.5".
-             * The numbers are parsed as doubles and then converted to SparseDtmcRegionModelChecker::CoefficientType.
-             * The results will be inserted in the given maps
-             *
-             */
-            static void parseParameterBoundaries( Valuation& lowerBoundaries, Valuation& upperBoundaries, std::string const& parameterBoundariesString, std::set<VariableType> const& consideredVariables);
-
-            /*
-             * Can be used to parse a single region from a string of the form "0.3<=p<=0.5,0.4<=q<=0.7".
-             * The numbers are parsed as doubles and then converted to SparseDtmcRegionModelChecker::CoefficientType.
-             *
-             */
-            static ParameterRegion parseRegion(std::string const& regionString, std::set<VariableType> const& consideredVariables);
-
-            /*
-             * Can be used to parse a vector of region from a string of the form "0.3<=p<=0.5,0.4<=q<=0.7;0.1<=p<=0.3,0.2<=q<=0.4".
-             * The numbers are parsed as doubles and then converted to SparseDtmcRegionModelChecker::CoefficientType.
-             *
-             */
-            static std::vector<ParameterRegion> parseMultipleRegions(std::string const& regionsString, std::set<VariableType> const& consideredVariables);
-
         private:
 
             void init();
@@ -92,6 +71,10 @@ namespace storm {
             Valuation upperBoundaries;
             std::set<VariableType> variables;
         };
+
+        template<typename ParametricType>
+        std::ostream& operator<<(std::ostream& out, ParameterRegion<ParametricType> const& region);
+        
     }
 }
 
diff --git a/src/storm/transformer/ParameterLifter.cpp b/src/storm-pars/transformer/ParameterLifter.cpp
similarity index 99%
rename from src/storm/transformer/ParameterLifter.cpp
rename to src/storm-pars/transformer/ParameterLifter.cpp
index 43c76fd55..551529c4c 100644
--- a/src/storm/transformer/ParameterLifter.cpp
+++ b/src/storm-pars/transformer/ParameterLifter.cpp
@@ -1,4 +1,4 @@
-#include "storm/transformer/ParameterLifter.h"
+#include "storm-pars/transformer/ParameterLifter.h"
 
 
 #include "storm/adapters/RationalFunctionAdapter.h"
diff --git a/src/storm/transformer/ParameterLifter.h b/src/storm-pars/transformer/ParameterLifter.h
similarity index 98%
rename from src/storm/transformer/ParameterLifter.h
rename to src/storm-pars/transformer/ParameterLifter.h
index e29e648a6..ab16e5a88 100644
--- a/src/storm/transformer/ParameterLifter.h
+++ b/src/storm-pars/transformer/ParameterLifter.h
@@ -6,10 +6,10 @@
 #include <set>
 
 
+#include "storm-pars/storage/ParameterRegion.h"
+#include "storm-pars/utility/parametric.h"
 #include "storm/storage/BitVector.h"
 #include "storm/storage/SparseMatrix.h"
-#include "storm/utility/parametric.h"
-#include "storm/storage/ParameterRegion.h"
 #include "storm/solver/OptimizationDirection.h"
 
 namespace storm {
diff --git a/src/storm/transformer/SparseParametricDtmcSimplifier.cpp b/src/storm-pars/transformer/SparseParametricDtmcSimplifier.cpp
similarity index 99%
rename from src/storm/transformer/SparseParametricDtmcSimplifier.cpp
rename to src/storm-pars/transformer/SparseParametricDtmcSimplifier.cpp
index a150efe9b..ed05131e4 100644
--- a/src/storm/transformer/SparseParametricDtmcSimplifier.cpp
+++ b/src/storm-pars/transformer/SparseParametricDtmcSimplifier.cpp
@@ -1,4 +1,4 @@
-#include "storm/transformer/SparseParametricDtmcSimplifier.h"
+#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h"
 
 #include "storm/adapters/RationalFunctionAdapter.h"
 
diff --git a/src/storm/transformer/SparseParametricDtmcSimplifier.h b/src/storm-pars/transformer/SparseParametricDtmcSimplifier.h
similarity index 95%
rename from src/storm/transformer/SparseParametricDtmcSimplifier.h
rename to src/storm-pars/transformer/SparseParametricDtmcSimplifier.h
index 5f34b483b..efbbf231b 100644
--- a/src/storm/transformer/SparseParametricDtmcSimplifier.h
+++ b/src/storm-pars/transformer/SparseParametricDtmcSimplifier.h
@@ -1,7 +1,7 @@
 #pragma once
 
 
-#include "storm/transformer/SparseParametricModelSimplifier.h"
+#include "storm-pars/transformer/SparseParametricModelSimplifier.h"
 
 namespace storm {
     namespace transformer {
diff --git a/src/storm/transformer/SparseParametricMdpSimplifier.cpp b/src/storm-pars/transformer/SparseParametricMdpSimplifier.cpp
similarity index 99%
rename from src/storm/transformer/SparseParametricMdpSimplifier.cpp
rename to src/storm-pars/transformer/SparseParametricMdpSimplifier.cpp
index a6d8bf99e..1862936f4 100644
--- a/src/storm/transformer/SparseParametricMdpSimplifier.cpp
+++ b/src/storm-pars/transformer/SparseParametricMdpSimplifier.cpp
@@ -1,4 +1,4 @@
-#include "storm/transformer/SparseParametricMdpSimplifier.h"
+#include "storm-pars/transformer/SparseParametricMdpSimplifier.h"
 
 #include "storm/adapters/RationalFunctionAdapter.h"
 
diff --git a/src/storm/transformer/SparseParametricMdpSimplifier.h b/src/storm-pars/transformer/SparseParametricMdpSimplifier.h
similarity index 97%
rename from src/storm/transformer/SparseParametricMdpSimplifier.h
rename to src/storm-pars/transformer/SparseParametricMdpSimplifier.h
index ebe16f994..3a7c223bc 100644
--- a/src/storm/transformer/SparseParametricMdpSimplifier.h
+++ b/src/storm-pars/transformer/SparseParametricMdpSimplifier.h
@@ -1,7 +1,7 @@
 #pragma once
 
 
-#include "storm/transformer/SparseParametricModelSimplifier.h"
+#include "storm-pars/transformer/SparseParametricModelSimplifier.h"
 
 namespace storm {
     namespace transformer {
diff --git a/src/storm/transformer/SparseParametricModelSimplifier.cpp b/src/storm-pars/transformer/SparseParametricModelSimplifier.cpp
similarity index 99%
rename from src/storm/transformer/SparseParametricModelSimplifier.cpp
rename to src/storm-pars/transformer/SparseParametricModelSimplifier.cpp
index 3dd6fbd56..343fc06e3 100644
--- a/src/storm/transformer/SparseParametricModelSimplifier.cpp
+++ b/src/storm-pars/transformer/SparseParametricModelSimplifier.cpp
@@ -1,4 +1,4 @@
-#include "storm/transformer/SparseParametricModelSimplifier.h"
+#include "storm-pars/transformer/SparseParametricModelSimplifier.h"
 
 #include "storm/adapters/RationalFunctionAdapter.h"
 
diff --git a/src/storm/transformer/SparseParametricModelSimplifier.h b/src/storm-pars/transformer/SparseParametricModelSimplifier.h
similarity index 100%
rename from src/storm/transformer/SparseParametricModelSimplifier.h
rename to src/storm-pars/transformer/SparseParametricModelSimplifier.h
diff --git a/src/storm/utility/ModelInstantiator.cpp b/src/storm-pars/utility/ModelInstantiator.cpp
similarity index 99%
rename from src/storm/utility/ModelInstantiator.cpp
rename to src/storm-pars/utility/ModelInstantiator.cpp
index e28049862..f59649ab7 100644
--- a/src/storm/utility/ModelInstantiator.cpp
+++ b/src/storm-pars/utility/ModelInstantiator.cpp
@@ -1,4 +1,4 @@
-#include "storm/utility/ModelInstantiator.h"
+#include "storm-pars/utility/ModelInstantiator.h"
 #include "storm/models/sparse/StandardRewardModel.h"
 
 namespace storm {
diff --git a/src/storm/utility/ModelInstantiator.h b/src/storm-pars/utility/ModelInstantiator.h
similarity index 99%
rename from src/storm/utility/ModelInstantiator.h
rename to src/storm-pars/utility/ModelInstantiator.h
index fa1ba8099..e96a4dda8 100644
--- a/src/storm/utility/ModelInstantiator.h
+++ b/src/storm-pars/utility/ModelInstantiator.h
@@ -5,12 +5,12 @@
 #include <memory>
 #include <type_traits>
 
+#include "storm-pars/utility/parametric.h"
 #include "storm/models/sparse/Dtmc.h"
 #include "storm/models/sparse/Mdp.h"
 #include "storm/models/sparse/Ctmc.h"
 #include "storm/models/sparse/MarkovAutomaton.h"
 #include "storm/models/sparse/StochasticTwoPlayerGame.h"
-#include "storm/utility/parametric.h"
 #include "storm/utility/constants.h"
 
 namespace storm {
diff --git a/src/storm/utility/parameterlifting.h b/src/storm-pars/utility/parameterlifting.h
similarity index 81%
rename from src/storm/utility/parameterlifting.h
rename to src/storm-pars/utility/parameterlifting.h
index 3c8cdbf73..a32418d91 100644
--- a/src/storm/utility/parameterlifting.h
+++ b/src/storm-pars/utility/parameterlifting.h
@@ -3,8 +3,8 @@
 
 #include <vector>
 
+#include "storm-pars/utility/parametric.h"
 #include "storm/models/sparse/Model.h"
-#include "storm/utility/parametric.h"
 #include "storm/utility/macros.h"
 #include "storm/logic/Formula.h"
 #include "storm/logic/FragmentSpecification.h"
@@ -31,37 +31,38 @@ namespace storm {
              * @return true iff it was successfully validated that parameter lifting is sound on the provided model.
              */
             template<typename ValueType>
-            static bool validateParameterLiftingSound(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, std::shared_ptr<storm::logic::Formula const> const& formula) {
+            static bool validateParameterLiftingSound(storm::models::sparse::Model<ValueType> const& model, storm::logic::Formula const& formula) {
                 
                 // Check whether all numbers occurring in the model are multilinear
                 
                 // Transition matrix
-                if (model->isOfType(storm::models::ModelType::Dtmc) || model->isOfType(storm::models::ModelType::Mdp) || model->isOfType(storm::models::ModelType::Ctmc)) {
-                    for (auto const& entry : model->getTransitionMatrix()) {
+                if (model.isOfType(storm::models::ModelType::Dtmc) || model.isOfType(storm::models::ModelType::Mdp) || model.isOfType(storm::models::ModelType::Ctmc)) {
+                    for (auto const& entry : model.getTransitionMatrix()) {
                         if (!storm::utility::parametric::isMultiLinearPolynomial(entry.getValue())) {
                             STORM_LOG_WARN("The input model contains a non-linear polynomial as transition: '" << entry.getValue() << "'. Can not validate that parameter lifting is sound on this model.");
                             return false;
                         }
                     }
-                } else if (model->isOfType(storm::models::ModelType::MarkovAutomaton)) {
+                } else if (model.isOfType(storm::models::ModelType::MarkovAutomaton)) {
+                    auto const& ma = dynamic_cast<storm::models::sparse::MarkovAutomaton<ValueType> const&>(model);
                     // Markov Automata store the probability matrix and the exit rate vector. However, we need to considert the rate matrix.
-                    if (!model->template as<storm::models::sparse::MarkovAutomaton<ValueType>>()->isClosed()) {
+                    if (!ma.isClosed()) {
                         STORM_LOG_ERROR("parameter lifting requires a closed Markov automaton.");
                         return false;
                     }
-                    auto const& rateVector = model->template as<storm::models::sparse::MarkovAutomaton<ValueType>>()->getExitRates();
-                    auto const& markovianStates = model->template as<storm::models::sparse::MarkovAutomaton<ValueType>>()->getMarkovianStates();
-                    for (uint_fast64_t state = 0; state < model->getNumberOfStates(); ++state) {
+                    auto const& rateVector = ma.getExitRates();
+                    auto const& markovianStates = ma.getMarkovianStates();
+                    for (uint_fast64_t state = 0; state < model.getNumberOfStates(); ++state) {
                         if (markovianStates.get(state)) {
                             auto const& exitRate = rateVector[state];
-                            for (auto const& entry : model->getTransitionMatrix().getRowGroup(state)) {
+                            for (auto const& entry : model.getTransitionMatrix().getRowGroup(state)) {
                                 if (!storm::utility::parametric::isMultiLinearPolynomial(storm::utility::simplify(entry.getValue() * exitRate))) {
                                     STORM_LOG_WARN("The input model contains a non-linear polynomial as transition rate: '" << storm::utility::simplify(entry.getValue() * exitRate) << "'. Can not validate that parameter lifting is sound on this model.");
                                     return false;
                                 }
                             }
                         } else {
-                            for (auto const& entry : model->getTransitionMatrix().getRowGroup(state)) {
+                            for (auto const& entry : model.getTransitionMatrix().getRowGroup(state)) {
                                 if (!storm::utility::parametric::isMultiLinearPolynomial(entry.getValue())) {
                                     STORM_LOG_WARN("The input model contains a non-linear polynomial as transition: '" << entry.getValue() << "'. Can not validate that parameter lifting is sound on this model.");
                                     return false;
@@ -75,10 +76,10 @@ namespace storm {
                 }
                 
                 // Rewards
-                if (formula->isRewardOperatorFormula()) {
-                    storm::models::sparse::StandardRewardModel<ValueType> const& rewardModel = formula->asRewardOperatorFormula().hasRewardModelName() ?
-                                                                                    model->getRewardModel(formula->asRewardOperatorFormula().getRewardModelName()) :
-                                                                                    model->getUniqueRewardModel();
+                if (formula.isRewardOperatorFormula()) {
+                    storm::models::sparse::StandardRewardModel<ValueType> const& rewardModel = formula.asRewardOperatorFormula().hasRewardModelName() ?
+                                                                                    model.getRewardModel(formula.asRewardOperatorFormula().getRewardModelName()) :
+                                                                                    model.getUniqueRewardModel();
                     if (rewardModel.hasStateRewards()) {
                         for (auto const& rew : rewardModel.getStateRewardVector()) {
                             if (!storm::utility::parametric::isMultiLinearPolynomial(rew)) {
@@ -91,7 +92,7 @@ namespace storm {
                     // Note: This check could also be done action-wise.
                     std::set<typename storm::utility::parametric::VariableType<ValueType>::type> collectedRewardParameters;
                     if (rewardModel.hasStateActionRewards()) {
-                        if (model->isOfType(storm::models::ModelType::Ctmc) || model->isOfType(storm::models::ModelType::MarkovAutomaton)) {
+                        if (model.isOfType(storm::models::ModelType::Ctmc) || model.isOfType(storm::models::ModelType::MarkovAutomaton)) {
                             for (auto const& rew : rewardModel.getStateActionRewardVector()) {
                                 if (!storm::utility::parametric::isMultiLinearPolynomial(rew)) {
                                     STORM_LOG_WARN("The input model contains a non-linear polynomial as action reward: '" << rew << "'. Can not validate that parameter lifting is sound on this model.");
@@ -120,7 +121,7 @@ namespace storm {
                     }
                     
                     if (!collectedRewardParameters.empty()) {
-                        std::set<typename storm::utility::parametric::VariableType<ValueType>::type> transitionParameters = storm::models::sparse::getProbabilityParameters(*model);
+                        std::set<typename storm::utility::parametric::VariableType<ValueType>::type> transitionParameters = storm::models::sparse::getProbabilityParameters(model);
                         auto rewParIt = collectedRewardParameters.begin();
                         auto trParIt = transitionParameters.begin();
                         while (rewParIt != collectedRewardParameters.end() && trParIt != transitionParameters.end()) {
diff --git a/src/storm/utility/parametric.cpp b/src/storm-pars/utility/parametric.cpp
similarity index 97%
rename from src/storm/utility/parametric.cpp
rename to src/storm-pars/utility/parametric.cpp
index 78bb0b880..3b6934a3e 100644
--- a/src/storm/utility/parametric.cpp
+++ b/src/storm-pars/utility/parametric.cpp
@@ -1,6 +1,6 @@
 #include <string>
 
-#include "storm/utility/parametric.h"
+#include "storm-pars/utility/parametric.h"
 #include "storm/utility/constants.h"
 #include "storm/utility/macros.h"
 #include "storm/settings/SettingsManager.h"
diff --git a/src/storm/utility/parametric.h b/src/storm-pars/utility/parametric.h
similarity index 100%
rename from src/storm/utility/parametric.h
rename to src/storm-pars/utility/parametric.h
diff --git a/src/storm/api/storm.h b/src/storm/api/storm.h
index c2856da48..ffc4c75a6 100644
--- a/src/storm/api/storm.h
+++ b/src/storm/api/storm.h
@@ -4,6 +4,7 @@
 #include "storm/api/properties.h"
 #include "storm/api/builder.h"
 #include "storm/api/bisimulation.h"
+#include "storm/api/transformation.h"
 #include "storm/api/verification.h"
 #include "storm/api/counterexamples.h"
 #include "storm/api/export.h"
diff --git a/src/storm/api/transformation.h b/src/storm/api/transformation.h
new file mode 100644
index 000000000..204e283db
--- /dev/null
+++ b/src/storm/api/transformation.h
@@ -0,0 +1,80 @@
+#pragma once
+
+#include "storm/transformer/ContinuousToDiscreteTimeModelTransformer.h"
+#include "storm/transformer/SymbolicToSparseTransformer.h"
+
+#include "storm/utility/macros.h"
+#include "storm/exceptions/InvalidOperationException.h"
+#include "storm/exceptions/NotSupportedException.h"
+
+namespace storm {
+    namespace api {
+        
+        /*!
+         * Transforms the given continuous model to a discrete time model.
+         * If such a transformation does not preserve one of the given formulas, an error is issued.
+         */
+        template <typename ValueType>
+        std::shared_ptr<storm::models::sparse::Model<ValueType>> transformContinuousToDiscreteTimeSparseModel(std::shared_ptr<storm::models::sparse::Model<ValueType>> const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) {
+            
+            storm::transformer::ContinuousToDiscreteTimeModelTransformer<ValueType> transformer;
+            
+            for (auto const& formula : formulas) {
+                STORM_LOG_THROW(transformer.preservesFormula(*formula), storm::exceptions::InvalidOperationException, "Transformation to discrete time model does not preserve formula " << *formula << ".");
+            }
+            
+            if (model->isOfType(storm::models::ModelType::Ctmc)) {
+                return transformer.transform(*model->template as<storm::models::sparse::Ctmc<ValueType>>());
+            } else if (model->isOfType(storm::models::ModelType::MarkovAutomaton)) {
+                return transformer.transform(*model->template as<storm::models::sparse::MarkovAutomaton<ValueType>>());
+            } else {
+                STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Transformation of a " << model->getType() << " to a discrete time model is not supported");
+            }
+            return nullptr;
+        }
+
+        /*!
+         * Transforms the given continuous model to a discrete time model IN PLACE.
+         * This means that the input continuous time model is replaced by the new discrete time model.
+         * If such a transformation does not preserve one of the given formulas, an error is issued.
+         */
+        template <typename ValueType>
+        std::shared_ptr<storm::models::sparse::Model<ValueType>> transformContinuousToDiscreteTimeSparseModel(storm::models::sparse::Model<ValueType>&& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) {
+            
+            storm::transformer::ContinuousToDiscreteTimeModelTransformer<ValueType> transformer;
+            
+            for (auto const& formula : formulas) {
+                STORM_LOG_THROW(transformer.preservesFormula(*formula), storm::exceptions::InvalidOperationException, "Transformation to discrete time model does not preserve formula " << *formula << ".");
+            }
+            
+            if (model.isOfType(storm::models::ModelType::Ctmc)) {
+                return transformer.transform(std::move(*model.template as<storm::models::sparse::Ctmc<ValueType>>()));
+            } else if (model.isOfType(storm::models::ModelType::MarkovAutomaton)) {
+                return transformer.transform(std::move(*model.template as<storm::models::sparse::MarkovAutomaton<ValueType>>()));
+            } else {
+                STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Transformation of a " << model.getType() << " to a discrete time model is not supported.");
+            }
+            return nullptr;
+            
+        }
+        
+        /*!
+         * Transforms the given symbolic model to a sparse model.
+         */
+        template<storm::dd::DdType Type, typename ValueType>
+        std::shared_ptr<storm::models::sparse::Model<ValueType>> transformSymbolicToSparseModel(std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> const& symbolicModel) {
+            switch (symbolicModel->getType()) {
+                case storm::models::ModelType::Dtmc:
+                    return storm::transformer::SymbolicDtmcToSparseDtmcTransformer<Type, ValueType>().translate(*symbolicModel->template as<storm::models::symbolic::Dtmc<Type, ValueType>>());
+                case storm::models::ModelType::Mdp:
+                    return storm::transformer::SymbolicMdpToSparseMdpTransformer<Type, ValueType>::translate(*symbolicModel->template as<storm::models::symbolic::Mdp<Type, ValueType>>());
+                case storm::models::ModelType::Ctmc:
+                    return storm::transformer::SymbolicCtmcToSparseCtmcTransformer<Type, ValueType>::translate(*symbolicModel->template as<storm::models::symbolic::Ctmc<Type, ValueType>>());
+                default:
+                    STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Transformation of symbolic " << symbolicModel->getType() << " to sparse model is not supported.");
+            }
+            return nullptr;
+        }
+        
+    }
+}
diff --git a/src/storm/api/verification.h b/src/storm/api/verification.h
index 2bc6ec94e..16c42cd7e 100644
--- a/src/storm/api/verification.h
+++ b/src/storm/api/verification.h
@@ -255,131 +255,5 @@ namespace storm {
             return result;
         }
         
-        template<typename ParametricType>
-        std::unique_ptr<storm::modelchecker::CheckResult> verifyWithParameterLifting(std::shared_ptr<storm::models::sparse::Model<ParametricType>>, std::shared_ptr<storm::logic::Formula const> const&) {
-            STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter-lifting is unavailable for this data-type.");
-        }
-            
-        template<>
-        inline std::unique_ptr<storm::modelchecker::CheckResult> verifyWithParameterLifting(std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> markovModel, std::shared_ptr<storm::logic::Formula const> const& formula) {
-            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Parameter-lifting is currently unavailable from the API.");
-//                storm::utility::Stopwatch parameterLiftingStopWatch(true);
-//                std::shared_ptr<storm::logic::Formula const> consideredFormula = formula;
-//                
-//                STORM_LOG_WARN_COND(storm::utility::parameterlifting::validateParameterLiftingSound(markovModel, formula), "Could not validate whether parameter lifting is sound on the input model and the formula " << *formula);
-//                
-//                if (markovModel->isOfType(storm::models::ModelType::Ctmc) || markovModel->isOfType(storm::models::ModelType::MarkovAutomaton)) {
-//                    STORM_PRINT_AND_LOG("Transforming continuous model to discrete model...");
-//                    storm::transformer::transformContinuousToDiscreteModelInPlace(markovModel, consideredFormula);
-//                    STORM_PRINT_AND_LOG(" done!" << std::endl);
-//                    markovModel->printModelInformationToStream(std::cout);
-//                }
-//                
-//                auto modelParameters = storm::models::sparse::getProbabilityParameters(*markovModel);
-//                auto rewParameters = storm::models::sparse::getRewardParameters(*markovModel);
-//                modelParameters.insert(rewParameters.begin(), rewParameters.end());
-//                
-//                STORM_LOG_THROW(storm::settings::getModule<storm::settings::modules::ParametricSettings>().isParameterSpaceSet(), storm::exceptions::InvalidSettingsException, "Invoked Parameter lifting but no parameter space was defined.");
-//                auto parameterSpaceAsString = storm::settings::getModule<storm::settings::modules::ParametricSettings>().getParameterSpace();
-//                auto parameterSpace = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion(parameterSpaceAsString, modelParameters);
-//                auto refinementThreshold = storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(storm::settings::getModule<storm::settings::modules::ParametricSettings>().getRefinementThreshold());
-//                std::vector<std::pair<storm::storage::ParameterRegion<storm::RationalFunction>, storm::modelchecker::parametric::RegionCheckResult>> result;
-//                
-//                STORM_PRINT_AND_LOG("Performing parameter lifting for property " << *consideredFormula << " with parameter space " << parameterSpace.toString(true) << " and refinement threshold " << storm::utility::convertNumber<double>(refinementThreshold) << " ..." << std::endl);
-//                
-//                storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction> task(*consideredFormula, true);
-//                std::string resultVisualization;
-//                
-//                if (markovModel->isOfType(storm::models::ModelType::Dtmc)) {
-//                    if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isExactSet()) {
-//                        storm::modelchecker::parametric::SparseDtmcRegionChecker <storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber> regionChecker(*markovModel->template as<storm::models::sparse::Dtmc<storm::RationalFunction>>());
-//                        regionChecker.specifyFormula(task);
-//                        result = regionChecker.performRegionRefinement(parameterSpace, refinementThreshold);
-//                        parameterLiftingStopWatch.stop();
-//                        if (modelParameters.size() == 2) {
-//                            resultVisualization = regionChecker.visualizeResult(result, parameterSpace, *modelParameters.begin(), *(modelParameters.rbegin()));
-//                        }
-//                    } else {
-//                        storm::modelchecker::parametric::SparseDtmcRegionChecker <storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*markovModel->template as<storm::models::sparse::Dtmc<storm::RationalFunction>>());
-//                        regionChecker.specifyFormula(task);
-//                        result = regionChecker.performRegionRefinement(parameterSpace, refinementThreshold);
-//                        parameterLiftingStopWatch.stop();
-//                        if (modelParameters.size() == 2) {
-//                            resultVisualization = regionChecker.visualizeResult(result, parameterSpace, *modelParameters.begin(), *(modelParameters.rbegin()));
-//                        }
-//                    }
-//                } else if (markovModel->isOfType(storm::models::ModelType::Mdp)) {
-//                    if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isExactSet()) {
-//                        storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber> regionChecker(*markovModel->template as<storm::models::sparse::Mdp<storm::RationalFunction>>());
-//                        regionChecker.specifyFormula(task);
-//                        result = regionChecker.performRegionRefinement(parameterSpace, refinementThreshold);
-//                        parameterLiftingStopWatch.stop();
-//                        if (modelParameters.size() == 2) {
-//                            resultVisualization = regionChecker.visualizeResult(result, parameterSpace, *modelParameters.begin(), *(modelParameters.rbegin()));
-//                        }
-//                    } else {
-//                        storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*markovModel->template as<storm::models::sparse::Mdp<storm::RationalFunction>>());
-//                        regionChecker.specifyFormula(task);
-//                        result = regionChecker.performRegionRefinement(parameterSpace, refinementThreshold);
-//                        parameterLiftingStopWatch.stop();
-//                        if (modelParameters.size() == 2) {
-//                            resultVisualization = regionChecker.visualizeResult(result, parameterSpace, *modelParameters.begin(), *(modelParameters.rbegin()));
-//                        }
-//                    }
-//                } else {
-//                    STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unable to perform parameterLifting on the provided model type.");
-//                }
-//                
-//                
-//                auto satArea = storm::utility::zero<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>();
-//                auto unsatArea = storm::utility::zero<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>();
-//                uint_fast64_t numOfSatRegions = 0;
-//                uint_fast64_t numOfUnsatRegions = 0;
-//                for (auto const& res : result) {
-//                    switch (res.second) {
-//                        case storm::modelchecker::parametric::RegionCheckResult::AllSat:
-//                            satArea += res.first.area();
-//                            ++numOfSatRegions;
-//                            break;
-//                        case storm::modelchecker::parametric::RegionCheckResult::AllViolated:
-//                            unsatArea += res.first.area();
-//                            ++numOfUnsatRegions;
-//                            break;
-//                        default:
-//                            STORM_LOG_ERROR("Unexpected result for region " << res.first.toString(true) << " : " << res.second << ".");
-//                            break;
-//                    }
-//                }
-//                typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType satAreaFraction = satArea / parameterSpace.area();
-//                typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType unsatAreaFraction = unsatArea / parameterSpace.area();
-//                STORM_PRINT_AND_LOG("Done! Found " << numOfSatRegions << " safe regions and "
-//                                    << numOfUnsatRegions << " unsafe regions." << std::endl);
-//                STORM_PRINT_AND_LOG(storm::utility::convertNumber<double>(satAreaFraction) * 100 << "% of the parameter space is safe, and "
-//                                    << storm::utility::convertNumber<double>(unsatAreaFraction) * 100 << "% of the parameter space is unsafe." << std::endl);
-//                STORM_PRINT_AND_LOG("Model checking with parameter lifting took " << parameterLiftingStopWatch << " seconds." << std::endl);
-//                STORM_PRINT_AND_LOG(resultVisualization);
-//                
-//                if (storm::settings::getModule<storm::settings::modules::ParametricSettings>().exportResultToFile()) {
-//                    std::string path = storm::settings::getModule<storm::settings::modules::ParametricSettings>().exportResultPath();
-//                    STORM_PRINT_AND_LOG("Exporting result to path " << path << "." << std::endl);
-//                    std::ofstream filestream;
-//                    storm::utility::openFile(path, filestream);
-//                    
-//                    for (auto const& res : result) {
-//                        switch (res.second) {
-//                            case storm::modelchecker::parametric::RegionCheckResult::AllSat:
-//                                filestream << "safe: " << res.first.toString(true) << std::endl;
-//                                break;
-//                            case storm::modelchecker::parametric::RegionCheckResult::AllViolated:
-//                                filestream << "unsafe: " << res.first.toString(true) << std::endl;
-//                                break;
-//                            default:
-//                                break;
-//                        }
-//                    }
-//                }
-//            }
-        }
-        
     }
 }
diff --git a/src/storm/cli/cli.cpp b/src/storm/cli/cli.cpp
index 0f53aa2d3..b28f068c3 100644
--- a/src/storm/cli/cli.cpp
+++ b/src/storm/cli/cli.cpp
@@ -26,7 +26,6 @@
 
 #include "storm/settings/SettingsManager.h"
 #include "storm/settings/modules/ResourceSettings.h"
-#include "storm/settings/modules/ParametricSettings.h"
 
 #include <type_traits>
 
@@ -658,13 +657,6 @@ namespace storm {
                                             std::unique_ptr<storm::modelchecker::CheckResult> result = storm::api::verifyWithSparseEngine<ValueType>(sparseModel, storm::api::createTask<ValueType>(formula, true));
                                             result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(sparseModel->getInitialStates()));
                                             return result;
-                                        },
-                                        [&sparseModel] (std::unique_ptr<storm::modelchecker::CheckResult> const& result) {
-                                            auto parametricSettings = storm::settings::getModule<storm::settings::modules::ParametricSettings>();
-                                            if (std::is_same<ValueType, storm::RationalFunction>::value && sparseModel->isOfType(storm::models::ModelType::Dtmc) && parametricSettings.exportResultToFile()) {
-                                                auto dtmc = sparseModel->template as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
-                                                storm::api::exportParametricResultToFile(result->asExplicitQuantitativeCheckResult<storm::RationalFunction>()[*sparseModel->getInitialStates().begin()], storm::analysis::ConstraintCollector<storm::RationalFunction>(*dtmc), parametricSettings.exportResultPath());
-                                            }
                                         });
         }
 
diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp
index c555fd0e8..50e26ddae 100644
--- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp
+++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp
@@ -200,12 +200,16 @@ namespace storm {
             
             template <typename ValueType, typename RewardModelType>
             std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeReachabilityRewards(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
-                std::vector<ValueType> stateRewardWeights(transitionMatrix.getRowGroupCount());
+                
+                // Get a reward model where the state rewards are scaled accordingly
+                std::vector<ValueType> stateRewardWeights(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
                 for (auto const markovianState : markovianStates) {
                     stateRewardWeights[markovianState] = storm::utility::one<ValueType>() / exitRateVector[markovianState];
                 }
                 std::vector<ValueType> totalRewardVector = rewardModel.getTotalActionRewardVector(transitionMatrix, stateRewardWeights);
-                return computeExpectedRewards(dir, transitionMatrix, backwardTransitions, psiStates, totalRewardVector, minMaxLinearEquationSolverFactory);
+                RewardModelType scaledRewardModel(boost::none, std::move(totalRewardVector));
+                
+                return SparseMdpPrctlHelper<ValueType>::computeReachabilityRewards(dir, transitionMatrix, backwardTransitions, scaledRewardModel, psiStates, false, false, minMaxLinearEquationSolverFactory).values;
             }
             
             template<typename ValueType>
@@ -365,112 +369,15 @@ namespace storm {
             
             template <typename ValueType>
             std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeReachabilityTimes(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, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
+                
+                // Get a reward model representing expected sojourn times
                 std::vector<ValueType> rewardValues(transitionMatrix.getRowCount(), storm::utility::zero<ValueType>());
                 for (auto const markovianState : markovianStates) {
                     rewardValues[transitionMatrix.getRowGroupIndices()[markovianState]] = storm::utility::one<ValueType>() / exitRateVector[markovianState];
                 }
-                return computeExpectedRewards(dir, transitionMatrix, backwardTransitions, psiStates, rewardValues, minMaxLinearEquationSolverFactory);
-            }
-
-            template<typename ValueType>
-            std::vector<ValueType> SparseMarkovAutomatonCslHelper::computeExpectedRewards(OptimizationDirection dir,
-                                                                              storm::storage::SparseMatrix<ValueType> const &transitionMatrix,
-                                                                              storm::storage::SparseMatrix<ValueType> const &backwardTransitions,
-                                                                              storm::storage::BitVector const &goalStates,
-                                                                              std::vector<ValueType> const &stateActionRewardVector,
-                                                                              storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const &minMaxLinearEquationSolverFactory) {
-
-                uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount();
-
-                // First, we need to check which states have infinite expected time (by definition).
-                storm::storage::BitVector infinityStates;
-                if (dir == OptimizationDirection::Minimize) {
-                    // If we need to compute the minimum expected times, we have to set the values of those states to infinity that, under all schedulers,
-                    // reach a bottom SCC without a goal state.
-
-                    // So we start by computing all bottom SCCs without goal states.
-                    storm::storage::StronglyConnectedComponentDecomposition<ValueType> sccDecomposition(transitionMatrix,
-                                                                                                     ~goalStates, true,
-                                                                                                     true);
-
-                    // Now form the union of all these SCCs.
-                    storm::storage::BitVector unionOfNonGoalBSccs(numberOfStates);
-                    for (auto const &scc : sccDecomposition) {
-                        for (auto state : scc) {
-                            unionOfNonGoalBSccs.set(state);
-                        }
-                    }
-
-                    // Finally, if this union is non-empty, compute the states such that all schedulers reach some state of the union.
-                    if (!unionOfNonGoalBSccs.empty()) {
-                        infinityStates = storm::utility::graph::performProbGreater0A(transitionMatrix,
-                                                                                     transitionMatrix.getRowGroupIndices(),
-                                                                                     backwardTransitions,
-                                                                                     storm::storage::BitVector(
-                                                                                             numberOfStates, true),
-                                                                                     unionOfNonGoalBSccs);
-                    } else {
-                        // Otherwise, we have no infinity states.
-                        infinityStates = storm::storage::BitVector(numberOfStates);
-                    }
-                } else {
-                    // If we maximize the property, the expected time of a state is infinite, if an end-component without any goal state is reachable.
-
-                    // So we start by computing all MECs that have no goal state.
-                    storm::storage::MaximalEndComponentDecomposition<ValueType> mecDecomposition(transitionMatrix,
-                                                                                              backwardTransitions,
-                                                                                              ~goalStates);
-
-                    // Now we form the union of all states in these end components.
-                    storm::storage::BitVector unionOfNonGoalMaximalEndComponents(numberOfStates);
-                    for (auto const &mec : mecDecomposition) {
-                        for (auto const &stateActionPair : mec) {
-                            unionOfNonGoalMaximalEndComponents.set(stateActionPair.first);
-                        }
-                    }
-
-                    if (!unionOfNonGoalMaximalEndComponents.empty()) {
-                        // Now we need to check for which states there exists a scheduler that reaches one of the previously computed states.
-                        infinityStates = storm::utility::graph::performProbGreater0E(backwardTransitions,
-                                                                                     storm::storage::BitVector(
-                                                                                             numberOfStates, true),
-                                                                                     unionOfNonGoalMaximalEndComponents);
-                    } else {
-                        // Otherwise, we have no infinity states.
-                        infinityStates = storm::storage::BitVector(numberOfStates);
-                    }
-                }
-                // Now we identify the states for which values need to be computed.
-                storm::storage::BitVector maybeStates = ~(goalStates | infinityStates);
-
-                // Create resulting vector.
-                std::vector<ValueType> result(numberOfStates);
-
-                if (!maybeStates.empty()) {
-                    // Then, we can eliminate the rows and columns for all states whose values are already known.
-                    std::vector<ValueType> x(maybeStates.getNumberOfSetBits());
-                    storm::storage::SparseMatrix<ValueType> submatrix = transitionMatrix.getSubmatrix(true, maybeStates,
-                                                                                                      maybeStates);
-
-                    // Finally, prepare the actual right-hand side.
-                    std::vector<ValueType> b(submatrix.getRowCount());
-                    storm::utility::vector::selectVectorValues(b, maybeStates,
-                                                               transitionMatrix.getRowGroupIndices(),
-                                                               stateActionRewardVector);
-
-                    // Solve the corresponding system of equations.
-                    std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = minMaxLinearEquationSolverFactory.create(
-                            submatrix);
-                    solver->solveEquations(dir, x, b);
-
-                    // Set values of resulting vector according to previous result and return the result.
-                    storm::utility::vector::setVectorValues<ValueType>(result, maybeStates, x);
-                }
-
-                storm::utility::vector::setVectorValues(result, goalStates, storm::utility::zero<ValueType>());
-                storm::utility::vector::setVectorValues(result, infinityStates, storm::utility::infinity<ValueType>());
-
-                return result;
+                storm::models::sparse::StandardRewardModel<ValueType> rewardModel(boost::none, std::move(rewardValues));
+                
+                return SparseMdpPrctlHelper<ValueType>::computeReachabilityRewards(dir, transitionMatrix, backwardTransitions, rewardModel, psiStates, false, false, minMaxLinearEquationSolverFactory).values;
             }
 
             template<typename ValueType>
@@ -550,8 +457,6 @@ namespace storm {
                 
             template double SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, std::vector<double> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& goalStates, storm::storage::MaximalEndComponent const& mec);
                 
-            template std::vector<double> SparseMarkovAutomatonCslHelper::computeExpectedRewards(OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, storm::storage::BitVector const& goalStates, std::vector<double> const& stateRewards, storm::solver::MinMaxLinearEquationSolverFactory<double> const& minMaxLinearEquationSolverFactory);
-
             template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, std::vector<storm::RationalNumber> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory<storm::RationalNumber> const& minMaxLinearEquationSolverFactory);
                 
             template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory<storm::RationalNumber> const& minMaxLinearEquationSolverFactory);
@@ -566,8 +471,6 @@ namespace storm {
                 
             template storm::RationalNumber SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, std::vector<storm::RationalNumber> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& goalStates, storm::storage::MaximalEndComponent const& mec);
                 
-            template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeExpectedRewards(OptimizationDirection dir, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, storm::storage::BitVector const& goalStates, std::vector<storm::RationalNumber> const& stateRewards, storm::solver::MinMaxLinearEquationSolverFactory<storm::RationalNumber> const& minMaxLinearEquationSolverFactory);
-
         }
     }
 }
diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h
index d61baf0c2..20d6c9598 100644
--- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h
+++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h
@@ -55,22 +55,6 @@ namespace storm {
                  */
                 template <typename ValueType>
                 static ValueType computeLraForMaximalEndComponent(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& goalStates, storm::storage::MaximalEndComponent const& mec);
-                
-                /*!
-                 * Computes the expected reward that is gained from each state before entering any of the goal states.
-                 *
-                 * @param dir Indicates whether minimal or maximal rewards are to be computed.
-                 * @param transitionMatrix The transition matrix of the underlying Markov automaton.
-                 * @param backwardTransitions The reversed transition relation of the underlying Markov automaton.
-                 * @param goalStates The goal states that define until which point rewards are gained.
-                 * @param stateRewards A vector that defines the reward gained in each state. For probabilistic states,
-                 * this is an instantaneous reward that is fully gained and for Markovian states the actually gained
-                 * reward is dependent on the expected time to stay in the state, i.e. it is gouverned by the exit rate
-                 * of the state.
-                 * @return A vector that contains the expected reward for each state of the model.
-                 */
-                template <typename ValueType>
-                static std::vector<ValueType> computeExpectedRewards(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& goalStates, std::vector<ValueType> const& stateRewards, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
             };
             
         }
diff --git a/src/storm/modelchecker/parametric/RegionCheckResult.cpp b/src/storm/modelchecker/parametric/RegionCheckResult.cpp
deleted file mode 100644
index 48f743462..000000000
--- a/src/storm/modelchecker/parametric/RegionCheckResult.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-#include "storm/modelchecker/parametric/RegionCheckResult.h"
-
-#include "storm/utility/macros.h"
-#include "storm/exceptions/NotImplementedException.h"
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-            std::ostream& operator<<(std::ostream& os, RegionCheckResult const& regionCheckResult) {
-                switch (regionCheckResult) {
-                    case RegionCheckResult::Unknown:
-                        os << "Unknown";
-                        break;
-                    case RegionCheckResult::ExistsSat:
-                        os << "ExistsSat";
-                        break;
-                    case RegionCheckResult::ExistsViolated:
-                        os << "ExistsViolated";
-                        break;
-                    case RegionCheckResult::CenterSat:
-                        os << "CenterSat";
-                        break;
-                    case RegionCheckResult::CenterViolated:
-                        os << "CenterViolated";
-                        break;
-                    case RegionCheckResult::ExistsBoth:
-                        os << "ExistsBoth";
-                        break;
-                    case RegionCheckResult::AllSat:
-                        os << "AllSat";
-                        break;
-                    case RegionCheckResult::AllViolated:
-                        os << "AllViolated";
-                        break;
-                    default:
-                        STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Could not get a string from the region check result. The case has not been implemented");
-                }
-                return os;
-            }
-        }
-    }
-}
diff --git a/src/storm/modelchecker/parametric/RegionCheckResult.h b/src/storm/modelchecker/parametric/RegionCheckResult.h
deleted file mode 100644
index 267b6e665..000000000
--- a/src/storm/modelchecker/parametric/RegionCheckResult.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-
-#include <ostream>
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-            /*!
-             * The results for a single Parameter region
-             */
-            enum class RegionCheckResult { 
-                Unknown, /*!< the result is unknown */
-                ExistsSat, /*!< the formula is satisfied for at least one parameter evaluation that lies in the given region */
-                ExistsViolated, /*!< the formula is violated for at least one parameter evaluation that lies in the given region */
-                CenterSat, /*!< the formula is satisfied for the parameter Valuation that corresponds to the center point of the region */
-                CenterViolated, /*!< the formula is violated for the parameter Valuation that corresponds to the center point of the region */
-                ExistsBoth, /*!< the formula is satisfied for some parameters but also violated for others */
-                AllSat, /*!< the formula is satisfied for all parameters in the given region */
-                AllViolated /*!< the formula is violated for all parameters in the given region */
-            };
-            
-            std::ostream& operator<<(std::ostream& os, RegionCheckResult const& regionCheckResult);
-        }
-    }
-}
-
diff --git a/src/storm/modelchecker/parametric/RegionChecker.cpp b/src/storm/modelchecker/parametric/RegionChecker.cpp
deleted file mode 100644
index 163e28b7a..000000000
--- a/src/storm/modelchecker/parametric/RegionChecker.cpp
+++ /dev/null
@@ -1,326 +0,0 @@
-#include <sstream>
-#include <queue>
-
-#include "storm/modelchecker/parametric/RegionChecker.h"
-
-#include "storm/adapters/RationalFunctionAdapter.h"
-
-#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
-
-#include "storm/utility/vector.h"
-#include "storm/models/sparse/StandardRewardModel.h"
-#include "storm/models/sparse/Dtmc.h"
-#include "storm/models/sparse/Mdp.h"
-
-#include "storm/exceptions/NotSupportedException.h"
-#include "storm/exceptions/InvalidStateException.h"
-#include "storm/exceptions/InvalidArgumentException.h"
-
-#include "storm/settings/SettingsManager.h"
-#include "storm/settings/modules/CoreSettings.h"
-#include "storm/settings/modules/ParametricSettings.h"
-
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-
-            RegionCheckerSettings::RegionCheckerSettings() {
-                this->applyExactValidation = storm::settings::getModule<storm::settings::modules::ParametricSettings>().isExactValidationSet();
-            }
-            
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            RegionChecker<SparseModelType, ConstantType, ExactConstantType>::RegionChecker(SparseModelType const& parametricModel) : parametricModel(parametricModel), numOfCorrectedRegions(0) {
-                initializationStopwatch.start();
-                STORM_LOG_THROW(parametricModel.getInitialStates().getNumberOfSetBits() == 1, storm::exceptions::NotSupportedException, "Parameter lifting requires models with only one initial state");
-                initializationStopwatch.stop();
-            }
-        
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            RegionCheckerSettings const& RegionChecker<SparseModelType, ConstantType, ExactConstantType>::getSettings() const {
-                return settings;
-            }
-            
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            void RegionChecker<SparseModelType, ConstantType, ExactConstantType>::setSettings(RegionCheckerSettings const& newSettings) {
-                settings = newSettings;
-            }
-            
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            void RegionChecker<SparseModelType, ConstantType, ExactConstantType>::specifyFormula(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) {
-                initializationStopwatch.start();
-                STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::NotSupportedException, "Parameter lifting requires a property where only the value in the initial states is relevant.");
-                STORM_LOG_THROW(checkTask.isBoundSet(), storm::exceptions::NotSupportedException, "Parameter lifting requires a bounded property.");
-                
-                simplifyParametricModel(checkTask);
-                initializeUnderlyingCheckers();
-                currentCheckTask = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, typename SparseModelType::ValueType>>(checkTask.substituteFormula(*currentFormula));
-
-                STORM_LOG_THROW(parameterLiftingChecker->canHandle(*currentCheckTask) &&
-                                (!exactParameterLiftingChecker || exactParameterLiftingChecker->canHandle(*currentCheckTask)),
-                                storm::exceptions::NotSupportedException, "Parameter lifting is not supported for this property.");
-                if (exactParameterLiftingChecker) {
-                    exactParameterLiftingChecker->specifyFormula(*currentCheckTask);
-                }
-                parameterLiftingChecker->specifyFormula(*currentCheckTask);
-                instantiationChecker->specifyFormula(*currentCheckTask);
-                initializationStopwatch.stop();
-            }
-    
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            RegionCheckResult RegionChecker<SparseModelType, ConstantType, ExactConstantType>::analyzeRegion(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionCheckResult const& initialResult, bool sampleVerticesOfRegion) {
-                      RegionCheckResult result = initialResult;
-
-                // Check if we need to check the formula on one point to decide whether to show AllSat or AllViolated
-                instantiationCheckerStopwatch.start();
-                if (result == RegionCheckResult::Unknown) {
-                     result = instantiationChecker->check(region.getCenterPoint())->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()] ? RegionCheckResult::CenterSat : RegionCheckResult::CenterViolated;
-                }
-                instantiationCheckerStopwatch.stop();
-                
-                // try to prove AllSat or AllViolated, depending on the obtained result
-                parameterLiftingCheckerStopwatch.start();
-                if(result == RegionCheckResult::ExistsSat || result == RegionCheckResult::CenterSat) {
-                    // show AllSat:
-                    storm::solver::OptimizationDirection parameterOptimizationDirection = isLowerBound(this->currentCheckTask->getBound().comparisonType) ? storm::solver::OptimizationDirection::Minimize : storm::solver::OptimizationDirection::Maximize;
-                    if(parameterLiftingChecker->check(region, parameterOptimizationDirection)->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) {
-                        result = RegionCheckResult::AllSat;
-                    } else if (sampleVerticesOfRegion) {
-                        parameterLiftingCheckerStopwatch.stop(); instantiationCheckerStopwatch.start();
-                        // Check if there is a point in the region for which the property is violated
-                        auto vertices = region.getVerticesOfRegion(region.getVariables());
-                        for (auto const& v : vertices) {
-                            if (!instantiationChecker->check(v)->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) {
-                                result = RegionCheckResult::ExistsBoth;
-                            }
-                        }
-                        instantiationCheckerStopwatch.stop(); parameterLiftingCheckerStopwatch.start();
-                    }
-                } else if (result == RegionCheckResult::ExistsViolated || result == RegionCheckResult::CenterViolated) {
-                    // show AllViolated:
-                    storm::solver::OptimizationDirection parameterOptimizationDirection = isLowerBound(this->currentCheckTask->getBound().comparisonType) ? storm::solver::OptimizationDirection::Maximize : storm::solver::OptimizationDirection::Minimize;
-                    if(!parameterLiftingChecker->check(region, parameterOptimizationDirection)->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) {
-                        result = RegionCheckResult::AllViolated;
-                    } else if (sampleVerticesOfRegion) {
-                        parameterLiftingCheckerStopwatch.stop(); instantiationCheckerStopwatch.start();
-                        // Check if there is a point in the region for which the property is satisfied
-                        auto vertices = region.getVerticesOfRegion(region.getVariables());
-                        for (auto const& v : vertices) {
-                            if (instantiationChecker->check(v)->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) {
-                                result = RegionCheckResult::ExistsBoth;
-                            }
-                        }
-                        instantiationCheckerStopwatch.stop(); parameterLiftingCheckerStopwatch.start();
-                    }
-                } else {
-                    STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "When analyzing a region, an invalid initial result was given: " << initialResult);
-                }
-                parameterLiftingCheckerStopwatch.stop();
-                return result;
-            }
-            
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            RegionCheckResult RegionChecker<SparseModelType, ConstantType, ExactConstantType>::analyzeRegionExactValidation(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionCheckResult const& initialResult) {
-                RegionCheckResult numericResult = analyzeRegion(region, initialResult, false);
-                parameterLiftingCheckerStopwatch.start();
-                if (numericResult == RegionCheckResult::AllSat || numericResult == RegionCheckResult::AllViolated) {
-                    applyHintsToExactChecker();
-                }
-                if (numericResult == RegionCheckResult::AllSat) {
-                    if(!exactParameterLiftingChecker->check(region, this->currentCheckTask->getOptimizationDirection())->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) {
-                        // Numerical result is wrong; Check whether the region is AllViolated!
-                        STORM_LOG_INFO("Numerical result was wrong for one region... Applying exact methods to obtain the actual result...");
-                        ++numOfCorrectedRegions;
-                        if(!exactParameterLiftingChecker->check(region, storm::solver::invert(this->currentCheckTask->getOptimizationDirection()))->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) {
-                            parameterLiftingCheckerStopwatch.stop();
-                            return RegionCheckResult::AllViolated;
-                        } else {
-                            parameterLiftingCheckerStopwatch.stop();
-                            return RegionCheckResult::Unknown;
-                        }
-                    }
-                } else if (numericResult == RegionCheckResult::AllViolated) {
-                    if(exactParameterLiftingChecker->check(region, storm::solver::invert(this->currentCheckTask->getOptimizationDirection()))->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) {
-                        // Numerical result is wrong; Check whether the region is AllSat!
-                        STORM_LOG_INFO("Numerical result was wrong for one region... Applying exact methods to obtain the actual result...");
-                        ++numOfCorrectedRegions;
-                        if(exactParameterLiftingChecker->check(region, this->currentCheckTask->getOptimizationDirection())->asExplicitQualitativeCheckResult()[*getConsideredParametricModel().getInitialStates().begin()]) {
-                            parameterLiftingCheckerStopwatch.stop();
-                            return RegionCheckResult::AllSat;
-                        } else {
-                            parameterLiftingCheckerStopwatch.stop();
-                            return RegionCheckResult::Unknown;
-                        }
-                    }
-                }
-                parameterLiftingCheckerStopwatch.stop();
-                return numericResult;
-            }
-
-    
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            std::vector<std::pair<storm::storage::ParameterRegion<typename SparseModelType::ValueType>, RegionCheckResult>> RegionChecker<SparseModelType, ConstantType, ExactConstantType>::performRegionRefinement(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, CoefficientType const& threshold) {
-                STORM_LOG_INFO("Applying refinement on region: " << region.toString(true) << " .");
-                
-                auto areaOfParameterSpace = region.area();
-                auto fractionOfUndiscoveredArea = storm::utility::one<CoefficientType>();
-                auto fractionOfAllSatArea = storm::utility::zero<CoefficientType>();
-                auto fractionOfAllViolatedArea = storm::utility::zero<CoefficientType>();
-                
-                std::queue<std::pair<storm::storage::ParameterRegion<typename SparseModelType::ValueType>, RegionCheckResult>> unprocessedRegions;
-                std::vector<std::pair<storm::storage::ParameterRegion<typename SparseModelType::ValueType>, RegionCheckResult>> result;
-                unprocessedRegions.emplace(region, RegionCheckResult::Unknown);
-                uint_fast64_t numOfAnalyzedRegions = 0;
-                numOfCorrectedRegions = 0;
-                CoefficientType displayedProgress = storm::utility::zero<CoefficientType>();
-                if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) {
-                    STORM_PRINT_AND_LOG("Progress (solved fraction) :" << std::endl <<  "0% [");
-                    while (displayedProgress < storm::utility::one<CoefficientType>() - threshold) {
-                        STORM_PRINT_AND_LOG(" ");
-                        displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
-                    }
-                    while (displayedProgress < storm::utility::one<CoefficientType>()) {
-                        STORM_PRINT_AND_LOG("-");
-                        displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
-                    }
-                    STORM_PRINT_AND_LOG("] 100%" << std::endl << "   [");
-                    displayedProgress = storm::utility::zero<CoefficientType>();
-                }
-
-                while (fractionOfUndiscoveredArea > threshold) {
-                    STORM_LOG_THROW(!unprocessedRegions.empty(), storm::exceptions::InvalidStateException, "Threshold for undiscovered area not reached but no unprocessed regions left.");
-                    STORM_LOG_INFO("Analyzing region #" << numOfAnalyzedRegions << " (" << storm::utility::convertNumber<double>(fractionOfUndiscoveredArea) * 100 << "% still unknown)");
-                    auto& currentRegion = unprocessedRegions.front().first;
-                    auto& res = unprocessedRegions.front().second;
-                    if (settings.applyExactValidation) {
-                        res = analyzeRegionExactValidation(currentRegion, res);
-                    } else {
-                        res = analyzeRegion(currentRegion, res, false);
-                    }
-                    switch (res) {
-                        case RegionCheckResult::AllSat:
-                            fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace;
-                            fractionOfAllSatArea += currentRegion.area() / areaOfParameterSpace;
-                            result.push_back(std::move(unprocessedRegions.front()));
-                            break;
-                        case RegionCheckResult::AllViolated:
-                            fractionOfUndiscoveredArea -= currentRegion.area() / areaOfParameterSpace;
-                            fractionOfAllViolatedArea += currentRegion.area() / areaOfParameterSpace;
-                            result.push_back(std::move(unprocessedRegions.front()));
-                            break;
-                        default:
-                            std::vector<storm::storage::ParameterRegion<typename SparseModelType::ValueType>> newRegions;
-                            currentRegion.split(currentRegion.getCenterPoint(), newRegions);
-                            RegionCheckResult initResForNewRegions = (res == RegionCheckResult::CenterSat) ? RegionCheckResult::ExistsSat :
-                                                                     ((res == RegionCheckResult::CenterViolated) ? RegionCheckResult::ExistsViolated :
-                                                                      RegionCheckResult::Unknown);
-                            for(auto& newRegion : newRegions) {
-                                unprocessedRegions.emplace(std::move(newRegion), initResForNewRegions);
-                            }
-                            break;
-                    }
-                    ++numOfAnalyzedRegions;
-                    unprocessedRegions.pop();
-                    if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) {
-                        while (displayedProgress < storm::utility::one<CoefficientType>() - fractionOfUndiscoveredArea) {
-                            STORM_PRINT_AND_LOG("#");
-                            displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
-                        }
-                    }
-                }
-                
-                if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) {
-                    while (displayedProgress < storm::utility::one<CoefficientType>()) {
-                        STORM_PRINT_AND_LOG("-");
-                        displayedProgress += storm::utility::convertNumber<CoefficientType>(0.01);
-                    }
-                    STORM_PRINT_AND_LOG("]" << std::endl);
-                    
-                    STORM_PRINT_AND_LOG("Parameter Lifting Statistics:" << std::endl);
-                    STORM_PRINT_AND_LOG("    Analyzed a total of " << numOfAnalyzedRegions << " regions." << std::endl);
-                    if (settings.applyExactValidation) {
-                        STORM_PRINT_AND_LOG("    Exact validation corrected " << numOfCorrectedRegions << " regions." << std::endl);
-                    }
-                    STORM_PRINT_AND_LOG("    Initialization took " << initializationStopwatch << " seconds." << std::endl);
-                    STORM_PRINT_AND_LOG("    Checking sampled models took " << instantiationCheckerStopwatch << " seconds." << std::endl);
-                    STORM_PRINT_AND_LOG("    Checking lifted models took " << parameterLiftingCheckerStopwatch << " seconds." << std::endl);
-                }
-                return result;
-            }
-    
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            SparseModelType const& RegionChecker<SparseModelType, ConstantType, ExactConstantType>::getConsideredParametricModel() const {
-                if (simplifiedModel) {
-                    return *simplifiedModel;
-                } else {
-                    return parametricModel;
-                }
-            }
-    
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            std::string RegionChecker<SparseModelType, ConstantType, ExactConstantType>::visualizeResult(std::vector<std::pair<storm::storage::ParameterRegion<typename SparseModelType::ValueType>, RegionCheckResult>> const& result, storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& parameterSpace, typename storm::storage::ParameterRegion<typename SparseModelType::ValueType>::VariableType const& x, typename storm::storage::ParameterRegion<typename SparseModelType::ValueType>::VariableType const& y) {
-                
-                std::stringstream stream;
-                
-                uint_fast64_t const sizeX = 128;
-                uint_fast64_t const sizeY = 64;
-                
-                stream << "Parameter lifting result (visualization):" << std::endl;
-                stream << " \t x-axis: " << x << "  \t y-axis: " << y << "  \t S=safe, [ ]=unsafe, -=ambiguous " << std::endl;
-                for (uint_fast64_t i = 0; i < sizeX+2; ++i) stream << "#"; stream << std::endl;
-                
-                CoefficientType deltaX = (parameterSpace.getUpperBoundary(x) - parameterSpace.getLowerBoundary(x)) / storm::utility::convertNumber<CoefficientType>(sizeX);
-                CoefficientType deltaY = (parameterSpace.getUpperBoundary(y) - parameterSpace.getLowerBoundary(y)) / storm::utility::convertNumber<CoefficientType>(sizeY);
-                CoefficientType printedRegionArea = deltaX * deltaY;
-                for (CoefficientType yUpper = parameterSpace.getUpperBoundary(y); yUpper != parameterSpace.getLowerBoundary(y); yUpper -= deltaY) {
-                    CoefficientType yLower = yUpper - deltaY;
-                    stream << "#";
-                    for (CoefficientType xLower = parameterSpace.getLowerBoundary(x); xLower != parameterSpace.getUpperBoundary(x); xLower += deltaX) {
-                        CoefficientType xUpper = xLower + deltaX;
-                        bool currRegionSafe = false;
-                        bool currRegionUnSafe = false;
-                        bool currRegionComplete = false;
-                        CoefficientType coveredArea = storm::utility::zero<CoefficientType>();
-                        for (auto const& r : result) {
-                            CoefficientType interesctionSizeY = std::min(yUpper, r.first.getUpperBoundary(y)) - std::max(yLower, r.first.getLowerBoundary(y));
-                            interesctionSizeY = std::max(interesctionSizeY, storm::utility::zero<CoefficientType>());
-                            CoefficientType interesctionSizeX = std::min(xUpper, r.first.getUpperBoundary(x)) - std::max(xLower, r.first.getLowerBoundary(x));
-                            interesctionSizeX = std::max(interesctionSizeX, storm::utility::zero<CoefficientType>());
-                            CoefficientType instersectionArea =  interesctionSizeY * interesctionSizeX;
-                            if(!storm::utility::isZero(instersectionArea)) {
-                                currRegionSafe = currRegionSafe || r.second == RegionCheckResult::AllSat;
-                                currRegionUnSafe = currRegionUnSafe || r.second == RegionCheckResult::AllViolated;
-                                coveredArea += instersectionArea;
-                                if(currRegionSafe && currRegionUnSafe) {
-                                    break;
-                                }
-                                if(coveredArea == printedRegionArea) {
-                                    currRegionComplete = true;
-                                    break;
-                                }
-                            }
-                        }
-                        if (currRegionComplete && currRegionSafe && !currRegionUnSafe) {
-                            stream << "S";
-                        } else if (currRegionComplete && currRegionUnSafe && !currRegionSafe) {
-                            stream << " ";
-                        } else {
-                            stream << "-";
-                        }
-                    }
-                    stream << "#" << std::endl;
-                }
-                for (uint_fast64_t i = 0; i < sizeX+2; ++i) stream << "#"; stream << std::endl;
-                return stream.str();
-            }
-        
-#ifdef STORM_HAVE_CARL
-            template class RegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber>;
-            template class RegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber>;
-            template class RegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>;
-            template class RegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>;
-#endif
-        } // namespace parametric
-    } //namespace modelchecker
-} //namespace storm
-
diff --git a/src/storm/modelchecker/parametric/RegionChecker.h b/src/storm/modelchecker/parametric/RegionChecker.h
deleted file mode 100644
index 64bdcd580..000000000
--- a/src/storm/modelchecker/parametric/RegionChecker.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#pragma once
-
-#include <memory>
-
-#include "storm/modelchecker/parametric/RegionCheckResult.h"
-#include "storm/modelchecker/parametric/SparseInstantiationModelChecker.h"
-#include "storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h"
-#include "storm/modelchecker/CheckTask.h"
-#include "storm/storage/ParameterRegion.h"
-#include "storm/utility/Stopwatch.h"
-#include "storm/utility/NumberTraits.h"
-
-namespace storm {
-    namespace modelchecker{
-        namespace parametric{
-            
-            struct RegionCheckerSettings {
-                RegionCheckerSettings();
-                
-                bool applyExactValidation;
-            };
-
-            template<typename SparseModelType, typename ConstantType, typename ExactConstantType = ConstantType>
-            class RegionChecker {
-                static_assert(storm::NumberTraits<ExactConstantType>::IsExact, "Specified type for exact computations is not exact.");
-
-            public:
-                
-                typedef typename storm::storage::ParameterRegion<typename SparseModelType::ValueType>::CoefficientType CoefficientType;
-
-                RegionChecker(SparseModelType const& parametricModel);
-                virtual ~RegionChecker() = default;
-                
-                RegionCheckerSettings const& getSettings() const;
-                void setSettings(RegionCheckerSettings const& newSettings);
-                
-                void specifyFormula(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask);
-                
-                /*!
-                 * Analyzes the given region by means of parameter lifting.
-                 * We first check whether there is one point in the region for which the property is satisfied/violated.
-                 * If the given initialResults already indicates that there is such a point, this step is skipped.
-                 * Then, we check whether ALL points in the region violate/satisfy the property
-                 *
-                 */
-                RegionCheckResult analyzeRegion(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionCheckResult const& initialResult = RegionCheckResult::Unknown, bool sampleVerticesOfRegion = false);
-                /*!
-                 * Similar to analyze region but additionaly invokes exact parameter lifting to validate results AllSat or AllViolated
-                 */
-                RegionCheckResult analyzeRegionExactValidation(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, RegionCheckResult const& initialResult = RegionCheckResult::Unknown);
-                
-                /*!
-                 * Iteratively refines the region until parameter lifting yields a conclusive result (AllSat or AllViolated).
-                 * The refinement stops as soon as the fraction of the area of the subregions with inconclusive result is less then the given threshold
-                 */
-                std::vector<std::pair<storm::storage::ParameterRegion<typename SparseModelType::ValueType>, RegionCheckResult>> performRegionRefinement(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, CoefficientType const& threshold);
-                
-                static std::string visualizeResult(std::vector<std::pair<storm::storage::ParameterRegion<typename SparseModelType::ValueType>, RegionCheckResult>> const& result, storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& parameterSpace, typename storm::storage::ParameterRegion<typename SparseModelType::ValueType>::VariableType const& x, typename storm::storage::ParameterRegion<typename SparseModelType::ValueType>::VariableType const& y);
-                
-            protected:
-                SparseModelType const& getConsideredParametricModel() const;
-                
-                virtual void initializeUnderlyingCheckers() = 0;
-                virtual void simplifyParametricModel(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) = 0;
-                virtual void applyHintsToExactChecker() = 0;
-                
-                SparseModelType const& parametricModel;
-                RegionCheckerSettings settings;
-                std::unique_ptr<CheckTask<storm::logic::Formula, typename SparseModelType::ValueType>> currentCheckTask;
-                std::shared_ptr<storm::logic::Formula const> currentFormula;
-                std::shared_ptr<SparseModelType> simplifiedModel;
-                
-
-                std::unique_ptr<SparseParameterLiftingModelChecker<SparseModelType, ConstantType>> parameterLiftingChecker;
-                std::unique_ptr<SparseParameterLiftingModelChecker<SparseModelType, ExactConstantType>> exactParameterLiftingChecker;
-                std::unique_ptr<SparseInstantiationModelChecker<SparseModelType, ConstantType>> instantiationChecker;
-                
-                // Information for statistics
-                mutable storm::utility::Stopwatch initializationStopwatch, instantiationCheckerStopwatch, parameterLiftingCheckerStopwatch;
-                mutable uint_fast64_t numOfCorrectedRegions;
-            };
-    
-        } //namespace parametric
-    } //namespace modelchecker
-} //namespace storm
diff --git a/src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.cpp b/src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.cpp
deleted file mode 100644
index 6b3d376a8..000000000
--- a/src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-#include "SparseDtmcInstantiationModelChecker.h"
-
-#include "storm/logic/FragmentSpecification.h"
-#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
-#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
-#include "storm/modelchecker/hints/ExplicitModelCheckerHint.h"
-#include "storm/utility/vector.h"
-
-#include "storm/exceptions/InvalidArgumentException.h"
-#include "storm/exceptions/InvalidStateException.h"
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-            
-            template <typename SparseModelType, typename ConstantType>
-            SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::SparseDtmcInstantiationModelChecker(SparseModelType const& parametricModel) : SparseInstantiationModelChecker<SparseModelType, ConstantType>(parametricModel), modelInstantiator(parametricModel) {
-                //Intentionally left empty
-            }
-    
-            template <typename SparseModelType, typename ConstantType>
-            std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) {
-                STORM_LOG_THROW(this->currentCheckTask, storm::exceptions::InvalidStateException, "Checking has been invoked but no property has been specified before.");
-                auto const& instantiatedModel = modelInstantiator.instantiate(valuation);
-                STORM_LOG_ASSERT(instantiatedModel.getTransitionMatrix().isProbabilistic(), "Instantiated matrix is not probabilistic!");
-                storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>> modelChecker(instantiatedModel);
-
-                // Check if there are some optimizations implemented for the specified property
-                if(this->currentCheckTask->getFormula().isInFragment(storm::logic::reachability())) {
-                    return checkReachabilityProbabilityFormula(modelChecker);
-                } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) {
-                    return checkReachabilityRewardFormula(modelChecker);
-                } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setProbabilityOperatorsAllowed(true).setBoundedUntilFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) {
-                    return checkBoundedUntilFormula(modelChecker);
-                } else {
-                    return modelChecker.check(*this->currentCheckTask);
-                }
-            }
-                
-            template <typename SparseModelType, typename ConstantType>
-            std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityProbabilityFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker) {
-                
-                if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) {
-                    this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>());
-                }
-                ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>();
-                std::unique_ptr<CheckResult> result;
-                
-                // Check the formula and store the result as a hint for the next call.
-                // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula
-                if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) {
-                    result = modelChecker.check(*this->currentCheckTask);
-                    hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector());
-                } else {
-                    auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false);
-                    std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask);
-                    result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
-                    hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()));
-                }
-                
-                if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) {
-                    // Extract the maybe states from the current result.
-                    assert(hint.hasResultHint());
-                    storm::storage::BitVector maybeStates = ~storm::utility::vector::filter<ConstantType>(hint.getResultHint(),
-                                    [] (ConstantType const& value) -> bool { return storm::utility::isZero<ConstantType>(value) || storm::utility::isOne<ConstantType>(value); });
-                    hint.setMaybeStates(std::move(maybeStates));
-                    hint.setComputeOnlyMaybeStates(true);
-                }
-                
-                return result;
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityRewardFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker) {
-                
-                if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) {
-                    this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>());
-                }
-                ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>();
-                std::unique_ptr<CheckResult> result;
-                
-                // Check the formula and store the result as a hint for the next call.
-                // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula
-                if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) {
-                    result = modelChecker.check(*this->currentCheckTask);
-                    this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>().setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector());
-                } else {
-                    auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false);
-                    std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeRewards(this->currentCheckTask->getFormula().asRewardOperatorFormula().getMeasureType(), newCheckTask);
-                    result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
-                    this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>().setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()));
-                }
-                                
-                if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) {
-                    // Extract the maybe states from the current result.
-                    assert(hint.hasResultHint());
-                    storm::storage::BitVector maybeStates = ~storm::utility::vector::filterInfinity(hint.getResultHint());
-                    // We need to exclude the target states from the maybe states.
-                    // Note that we can not consider the states with reward zero since a valuation might set a reward to zero
-                    std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asEventuallyFormula().getSubformula());
-                    maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector());
-                    hint.setMaybeStates(std::move(maybeStates));
-                    hint.setComputeOnlyMaybeStates(true);
-                }
-                
-                return result;
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            std::unique_ptr<CheckResult> SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>::checkBoundedUntilFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker) {
-                
-                if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) {
-                    this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>());
-                }
-                std::unique_ptr<CheckResult> result;
-                ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>();
-                
-                if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) {
-                    // We extract the maybestates from the quantitative result
-                    // For qualitative properties, we still need a quantitative result. Hence we perform the check on the subformula
-                    if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) {
-                        result = modelChecker.check(*this->currentCheckTask);
-                        hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector());
-                    } else {
-                        auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false);
-                        std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask);
-                        result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
-                        hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()));
-                    }
-                    
-                    storm::storage::BitVector maybeStates = storm::utility::vector::filterGreaterZero(hint.getResultHint());
-                    // We need to exclude the target states from the maybe states.
-                    // Note that we can not consider the states with probability one since a state might reach a target state with prob 1 within >0 steps
-                    std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asBoundedUntilFormula().getRightSubformula());
-                    maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector());
-                    hint.setMaybeStates(std::move(maybeStates));
-                    hint.setComputeOnlyMaybeStates(true);
-                } else {
-                    result = modelChecker.check(*this->currentCheckTask);
-                }
-                
-                return result;
-            }
-            
-            template class SparseDtmcInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>;
-            template class SparseDtmcInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>;
-
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.h b/src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.h
deleted file mode 100644
index 511253107..000000000
--- a/src/storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#pragma once
-
-#include <memory>
-#include <boost/optional.hpp>
-
-#include "storm/models/sparse/Dtmc.h"
-#include "storm/models/sparse/StandardRewardModel.h"
-#include "storm/modelchecker/parametric/SparseInstantiationModelChecker.h"
-#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h"
-#include "storm/utility/ModelInstantiator.h"
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-            
-            /*!
-             * Class to efficiently check a formula on a parametric model with different parameter instantiations
-             */
-            template <typename SparseModelType, typename ConstantType>
-            class SparseDtmcInstantiationModelChecker : public SparseInstantiationModelChecker<SparseModelType, ConstantType> {
-            public:
-                SparseDtmcInstantiationModelChecker(SparseModelType const& parametricModel);
-                
-                virtual std::unique_ptr<CheckResult> check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) override;
-
-            protected:
-                
-                // Optimizations for the different formula types
-                std::unique_ptr<CheckResult> checkReachabilityProbabilityFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker);
-                std::unique_ptr<CheckResult> checkReachabilityRewardFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker);
-                std::unique_ptr<CheckResult> checkBoundedUntilFormula(storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<ConstantType>>& modelChecker);
-                
-                storm::utility::ModelInstantiator<SparseModelType, storm::models::sparse::Dtmc<ConstantType>> modelInstantiator;
-            };
-        }
-    }
-}
diff --git a/src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.cpp b/src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.cpp
deleted file mode 100644
index 0a802b584..000000000
--- a/src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.cpp
+++ /dev/null
@@ -1,281 +0,0 @@
-#include "storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.h"
-
-#include "storm/adapters/RationalFunctionAdapter.h"
-#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h"
-#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
-#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
-#include "storm/models/sparse/Dtmc.h"
-#include "storm/models/sparse/StandardRewardModel.h"
-#include "storm/solver/StandardMinMaxLinearEquationSolver.h"
-#include "storm/utility/vector.h"
-#include "storm/utility/graph.h"
-#include "storm/utility/NumberTraits.h"
-
-#include "storm/exceptions/InvalidArgumentException.h"
-#include "storm/exceptions/InvalidPropertyException.h"
-#include "storm/exceptions/NotSupportedException.h"
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-            
-            template <typename SparseModelType, typename ConstantType>
-            SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseDtmcParameterLiftingModelChecker(SparseModelType const& parametricModel) : SparseParameterLiftingModelChecker<SparseModelType, ConstantType>(parametricModel), solverFactory(std::make_unique<storm::solver::GeneralMinMaxLinearEquationSolverFactory<ConstantType>>()) {
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseDtmcParameterLiftingModelChecker(SparseModelType const& parametricModel, std::unique_ptr<storm::solver::MinMaxLinearEquationSolverFactory<ConstantType>>&& solverFactory) : SparseParameterLiftingModelChecker<SparseModelType, ConstantType>(parametricModel), solverFactory(std::move(solverFactory)) {
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            bool SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::canHandle(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const {
-                return checkTask.getFormula().isInFragment(storm::logic::reachability().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setBoundedUntilFormulasAllowed(true).setCumulativeRewardFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true));
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) {
-                
-                // get the step bound
-                STORM_LOG_THROW(!checkTask.getFormula().hasLowerBound(), storm::exceptions::NotSupportedException, "Lower step bounds are not supported.");
-                STORM_LOG_THROW(checkTask.getFormula().hasUpperBound(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with an upper bound.");
-                STORM_LOG_THROW(checkTask.getFormula().isStepBounded(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with step bounds.");
-                stepBound = checkTask.getFormula().getUpperBound().evaluateAsInt();
-                STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
-                if (checkTask.getFormula().isUpperBoundStrict()) {
-                    STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero.");
-                    --(*stepBound);
-                }
-                STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
-
-                // get the results for the subformulas
-                storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(this->parametricModel);
-                STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported");
-                storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
-                storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
-                
-                // get the maybeStates
-                maybeStates = storm::utility::graph::performProbGreater0(this->parametricModel.getBackwardTransitions(), phiStates, psiStates, true, *stepBound);
-                maybeStates &= ~psiStates;
-                
-                // set the result for all non-maybe states
-                resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates(), storm::utility::zero<ConstantType>());
-                storm::utility::vector::setVectorValues(resultsForNonMaybeStates, psiStates, storm::utility::one<ConstantType>());
-                
-                // if there are maybestates, create the parameterLifter
-                if (!maybeStates.empty()) {
-                    // Create the vector of one-step probabilities to go to target states.
-                    std::vector<typename SparseModelType::ValueType> b = this->parametricModel.getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getRowCount(), true), psiStates);
-                    
-                    parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, maybeStates, maybeStates);
-                }
-                
-                // We know some bounds for the results so set them
-                lowerResultBound = storm::utility::zero<ConstantType>();
-                upperResultBound = storm::utility::one<ConstantType>();
-            }
-    
-            template <typename SparseModelType, typename ConstantType>
-            void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) {
-                
-                // get the results for the subformulas
-                storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(this->parametricModel);
-                STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported");
-                storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
-                storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
-                
-                // get the maybeStates
-                std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 = storm::utility::graph::performProb01(this->parametricModel.getBackwardTransitions(), phiStates, psiStates);
-                maybeStates = ~(statesWithProbability01.first | statesWithProbability01.second);
-                
-                // set the result for all non-maybe states
-                resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates(), storm::utility::zero<ConstantType>());
-                storm::utility::vector::setVectorValues(resultsForNonMaybeStates, statesWithProbability01.second, storm::utility::one<ConstantType>());
-                
-                // if there are maybestates, create the parameterLifter
-                if (!maybeStates.empty()) {
-                    // Create the vector of one-step probabilities to go to target states.
-                    std::vector<typename SparseModelType::ValueType> b = this->parametricModel.getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getRowCount(), true), psiStates);
-                    
-                    parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, maybeStates, maybeStates);
-                }
-                                
-                // We know some bounds for the results so set them
-                lowerResultBound = storm::utility::zero<ConstantType>();
-                upperResultBound = storm::utility::one<ConstantType>();
-            }
-    
-            template <typename SparseModelType, typename ConstantType>
-            void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) {
-                
-                // get the results for the subformula
-                storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(this->parametricModel);
-                STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported");
-                storm::storage::BitVector targetStates = std::move(propositionalChecker.check(checkTask.getFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
-                
-                // get the maybeStates
-                storm::storage::BitVector infinityStates = storm::utility::graph::performProb1(this->parametricModel.getBackwardTransitions(), storm::storage::BitVector(this->parametricModel.getNumberOfStates(), true), targetStates);
-                infinityStates.complement();
-                maybeStates = ~(targetStates | infinityStates);
-                
-                // set the result for all the non-maybe states
-                resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates(), storm::utility::zero<ConstantType>());
-                storm::utility::vector::setVectorValues(resultsForNonMaybeStates, infinityStates, storm::utility::infinity<ConstantType>());
-                
-                // if there are maybestates, create the parameterLifter
-                if (!maybeStates.empty()) {
-                    // Create the reward vector
-                    STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel.hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel.hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model.");
-
-                    typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel.getRewardModel(checkTask.getRewardModel()) : this->parametricModel.getUniqueRewardModel();
-
-                    std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel.getTransitionMatrix());
-                    
-                    parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, maybeStates, maybeStates);
-                }
-                
-                // We only know a lower bound for the result
-                lowerResultBound = storm::utility::zero<ConstantType>();
-
-            }
-    
-            template <typename SparseModelType, typename ConstantType>
-            void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) {
-                
-                // Obtain the stepBound
-                stepBound = checkTask.getFormula().getBound().evaluateAsInt();
-                if (checkTask.getFormula().isBoundStrict()) {
-                    STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero.");
-                    --(*stepBound);
-                }
-                STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
-                
-                //Every state is a maybeState
-                maybeStates = storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getColumnCount(), true);
-                resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates());
-                
-                // Create the reward vector
-                STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel.hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel.hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model.");
-                typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel.getRewardModel(checkTask.getRewardModel()) : this->parametricModel.getUniqueRewardModel();
-                std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel.getTransitionMatrix());
-                    
-                parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, maybeStates, maybeStates);
-                
-                                
-                // We only know a lower bound for the result
-                lowerResultBound = storm::utility::zero<ConstantType>();
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            std::unique_ptr<CheckResult> SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) {
-                
-                if(maybeStates.empty()) {
-                    return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(resultsForNonMaybeStates);
-                }
-                
-                parameterLifter->specifyRegion(region, dirForParameters);
-                
-                // Set up the solver
-                auto solver = solverFactory->create(parameterLifter->getMatrix());
-                if (storm::NumberTraits<ConstantType>::IsExact && dynamic_cast<storm::solver::StandardMinMaxLinearEquationSolver<ConstantType>*>(solver.get())) {
-                    STORM_LOG_INFO("Parameter Lifting: Setting solution method for exact MinMaxSolver to policy iteration");
-                    auto* standardSolver = dynamic_cast<storm::solver::StandardMinMaxLinearEquationSolver<ConstantType>*>(solver.get());
-                    auto settings = standardSolver->getSettings();
-                    settings.setSolutionMethod(storm::solver::StandardMinMaxLinearEquationSolverSettings<ConstantType>::SolutionMethod::PolicyIteration);
-                    standardSolver->setSettings(settings);
-                }
-                if (lowerResultBound) solver->setLowerBound(lowerResultBound.get());
-                if (upperResultBound) solver->setUpperBound(upperResultBound.get());
-                if (!stepBound) solver->setTrackScheduler(true);
-                if (storm::solver::minimize(dirForParameters) && minSchedChoices && !stepBound) solver->setSchedulerHint(std::move(minSchedChoices.get()));
-                if (storm::solver::maximize(dirForParameters) && maxSchedChoices && !stepBound) solver->setSchedulerHint(std::move(maxSchedChoices.get()));
-                if (this->currentCheckTask->isBoundSet() && solver->hasSchedulerHint()) {
-                    // If we reach this point, we know that after applying the hint, the x-values can only become larger (if we maximize) or smaller (if we minimize).
-                    std::unique_ptr<storm::solver::TerminationCondition<ConstantType>> termCond;
-                    storm::storage::BitVector relevantStatesInSubsystem = this->currentCheckTask->isOnlyInitialStatesRelevantSet() ? this->parametricModel.getInitialStates() % maybeStates : storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true);
-                    if (storm::solver::minimize(dirForParameters)) {
-                        // Terminate if the value for ALL relevant states is already below the threshold
-                        termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumBelowThreshold<ConstantType>> (relevantStatesInSubsystem, this->currentCheckTask->getBoundThreshold(), true, false);
-                    } else {
-                        // Terminate if the value for ALL relevant states is already above the threshold
-                        termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumExceedsThreshold<ConstantType>> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), true);
-                    }
-                    solver->setTerminationCondition(std::move(termCond));
-                }
-                
-                // Invoke the solver
-                if(stepBound) {
-                    assert(*stepBound > 0);
-                    x = std::vector<ConstantType>(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
-                    solver->repeatedMultiply(dirForParameters, x, &parameterLifter->getVector(), *stepBound);
-                } else {
-                    x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
-                    solver->solveEquations(dirForParameters, x, parameterLifter->getVector());
-                    if(storm::solver::minimize(dirForParameters)) {
-                        minSchedChoices = solver->getSchedulerChoices();
-                    } else {
-                        maxSchedChoices = solver->getSchedulerChoices();
-                    }
-                }
-                
-                // Get the result for the complete model (including maybestates)
-                std::vector<ConstantType> result = resultsForNonMaybeStates;
-                auto maybeStateResIt = x.begin();
-                for(auto const& maybeState : maybeStates) {
-                    result[maybeState] = *maybeStateResIt;
-                    ++maybeStateResIt;
-                }
-                return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(std::move(result));
-            }
-            
-                
-            template <typename SparseModelType, typename ConstantType>
-            void SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::reset() {
-                maybeStates.resize(0);
-                resultsForNonMaybeStates.clear();
-                stepBound = boost::none;
-                parameterLifter = nullptr;
-                minSchedChoices = boost::none;
-                maxSchedChoices = boost::none;
-                x.clear();
-                lowerResultBound = boost::none;
-                upperResultBound = boost::none;
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            boost::optional<storm::storage::Scheduler<ConstantType>> SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMinScheduler() {
-                if (!minSchedChoices) {
-                    return boost::none;
-                }
-                
-                storm::storage::Scheduler<ConstantType> result(minSchedChoices->size());
-                uint_fast64_t state = 0;
-                for (auto const& schedulerChoice : minSchedChoices.get()) {
-                    result.setChoice(schedulerChoice, state);
-                    ++state;
-                }
-                
-                return result;
-            }
-                    
-            template <typename SparseModelType, typename ConstantType>
-            boost::optional<storm::storage::Scheduler<ConstantType>> SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMaxScheduler() {
-                if (!maxSchedChoices) {
-                    return boost::none;
-                }
-                
-                storm::storage::Scheduler<ConstantType> result(maxSchedChoices->size());
-                uint_fast64_t state = 0;
-                for (auto const& schedulerChoice : maxSchedChoices.get()) {
-                    result.setChoice(schedulerChoice, state);
-                    ++state;
-                }
-                
-                return result;
-            }
-            
-            template class SparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>;
-            template class SparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>;
-
-        }
-    }
-}
diff --git a/src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.h b/src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.h
deleted file mode 100644
index 73ee17fe7..000000000
--- a/src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#pragma once
-
-#include <vector>
-#include <memory>
-#include <boost/optional.hpp>
-
-#include "storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h"
-#include "storm/storage/BitVector.h"
-#include "storm/storage/Scheduler.h"
-#include "storm/solver/MinMaxLinearEquationSolver.h"
-#include "storm/transformer/ParameterLifter.h"
-#include "storm/logic/FragmentSpecification.h"
-
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-            
-            template <typename SparseModelType, typename ConstantType>
-            class SparseDtmcParameterLiftingModelChecker : public SparseParameterLiftingModelChecker<SparseModelType, ConstantType> {
-            public:
-                SparseDtmcParameterLiftingModelChecker(SparseModelType const& parametricModel);
-                SparseDtmcParameterLiftingModelChecker(SparseModelType const& parametricModel, std::unique_ptr<storm::solver::MinMaxLinearEquationSolverFactory<ConstantType>>&& solverFactory);
-                
-                virtual bool canHandle(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const override;
-                
-                boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMinScheduler();
-                boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMaxScheduler();
-
-            protected:
-                
-                virtual void specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) override;
-                virtual void specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) override;
-                virtual void specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) override;
-                virtual void specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) override;
-                
-                virtual std::unique_ptr<CheckResult> computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) override;
-                
-                virtual void reset() override;
-                
-            private:
-                storm::storage::BitVector maybeStates;
-                std::vector<ConstantType> resultsForNonMaybeStates;
-                boost::optional<uint_fast64_t> stepBound;
-                
-                std::unique_ptr<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>> parameterLifter;
-                std::unique_ptr<storm::solver::MinMaxLinearEquationSolverFactory<ConstantType>> solverFactory;
-                
-                // Results from the most recent solver call.
-                boost::optional<std::vector<uint_fast64_t>> minSchedChoices, maxSchedChoices;
-                std::vector<ConstantType> x;
-                boost::optional<ConstantType> lowerResultBound, upperResultBound;
-            };
-        }
-    }
-}
diff --git a/src/storm/modelchecker/parametric/SparseDtmcRegionChecker.cpp b/src/storm/modelchecker/parametric/SparseDtmcRegionChecker.cpp
deleted file mode 100644
index b280bc046..000000000
--- a/src/storm/modelchecker/parametric/SparseDtmcRegionChecker.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-#include "storm/modelchecker/parametric/SparseDtmcRegionChecker.h"
-
-#include "storm/adapters/RationalFunctionAdapter.h"
-
-#include "storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.h"
-#include "storm/modelchecker/parametric/SparseDtmcInstantiationModelChecker.h"
-#include "storm/transformer/SparseParametricDtmcSimplifier.h"
-#include "storm/models/sparse/StandardRewardModel.h"
-#include "storm/models/sparse/Dtmc.h"
-#include "storm/utility/NumberTraits.h"
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            SparseDtmcRegionChecker<SparseModelType, ConstantType, ExactConstantType>::SparseDtmcRegionChecker(SparseModelType const& parametricModel) : RegionChecker<SparseModelType, ConstantType, ExactConstantType>(parametricModel) {
-                // Intentionally left empty
-            }
-    
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            void SparseDtmcRegionChecker<SparseModelType, ConstantType, ExactConstantType>::simplifyParametricModel(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) {
-                storm::transformer::SparseParametricDtmcSimplifier<SparseModelType> simplifier(this->parametricModel);
-                if(simplifier.simplify(checkTask.getFormula())) {
-                    this->simplifiedModel = simplifier.getSimplifiedModel();
-                    this->currentFormula = simplifier.getSimplifiedFormula();
-                } else {
-                    this->simplifiedModel = nullptr;
-                    this->currentFormula = checkTask.getFormula().asSharedPointer();
-                }
-            }
-            
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            void SparseDtmcRegionChecker<SparseModelType, ConstantType, ExactConstantType>::initializeUnderlyingCheckers() {
-                if (this->settings.applyExactValidation) {
-                    STORM_LOG_WARN_COND(!storm::NumberTraits<ConstantType>::IsExact, "Exact validation is not necessarry if the original computation is already exact");
-                    this->exactParameterLiftingChecker = std::make_unique<SparseDtmcParameterLiftingModelChecker<SparseModelType, ExactConstantType>>(this->getConsideredParametricModel());
-                }
-                this->parameterLiftingChecker = std::make_unique<SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>>(this->getConsideredParametricModel());
-                this->instantiationChecker = std::make_unique<SparseDtmcInstantiationModelChecker<SparseModelType, ConstantType>>(this->getConsideredParametricModel());
-                this->instantiationChecker->setInstantiationsAreGraphPreserving(true);
-            }
-    
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            void SparseDtmcRegionChecker<SparseModelType, ConstantType, ExactConstantType>::applyHintsToExactChecker() {
-                auto dtmcPLChecker = dynamic_cast<storm::modelchecker::parametric::SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>*>(this->parameterLiftingChecker.get());
-                STORM_LOG_ASSERT(dtmcPLChecker, "Underlying Parameter lifting checker has unexpected type");
-                auto exactDtmcPLChecker = dynamic_cast<storm::modelchecker::parametric::SparseDtmcParameterLiftingModelChecker<SparseModelType, ExactConstantType>*>(this->exactParameterLiftingChecker.get());
-                STORM_LOG_ASSERT(exactDtmcPLChecker, "Underlying exact parameter lifting checker has unexpected type");
-                if (dtmcPLChecker->getCurrentMaxScheduler()) {
-                    exactDtmcPLChecker->getCurrentMaxScheduler() = dtmcPLChecker->getCurrentMaxScheduler()->template toValueType<ExactConstantType>();
-                }
-                if (dtmcPLChecker->getCurrentMinScheduler()) {
-                    exactDtmcPLChecker->getCurrentMinScheduler() = dtmcPLChecker->getCurrentMinScheduler()->template toValueType<ExactConstantType>();
-                }
-            }
-       
-#ifdef STORM_HAVE_CARL
-            template class SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber>;
-            template class SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>;
-#endif
-        } // namespace parametric
-    } //namespace modelchecker
-} //namespace storm
-
diff --git a/src/storm/modelchecker/parametric/SparseDtmcRegionChecker.h b/src/storm/modelchecker/parametric/SparseDtmcRegionChecker.h
deleted file mode 100644
index 561594d2e..000000000
--- a/src/storm/modelchecker/parametric/SparseDtmcRegionChecker.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#pragma once
-
-#include <memory>
-
-#include "storm/modelchecker/parametric/RegionChecker.h"
-
-namespace storm {
-    namespace modelchecker{
-        namespace parametric{
-            
-
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType = ConstantType>
-            class SparseDtmcRegionChecker : public RegionChecker<SparseModelType, ConstantType, ExactConstantType> {
-
-            public:
-                SparseDtmcRegionChecker(SparseModelType const& parametricModel);
-                
-            protected:
-                virtual void simplifyParametricModel(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) override;
-                virtual void initializeUnderlyingCheckers() override;
-                virtual void applyHintsToExactChecker() override;
-                
-            };
-    
-        } //namespace parametric
-    } //namespace modelchecker
-} //namespace storm
diff --git a/src/storm/modelchecker/parametric/SparseInstantiationModelChecker.cpp b/src/storm/modelchecker/parametric/SparseInstantiationModelChecker.cpp
deleted file mode 100644
index 1a7a004d4..000000000
--- a/src/storm/modelchecker/parametric/SparseInstantiationModelChecker.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-#include "SparseInstantiationModelChecker.h"
-
-#include "storm/adapters/RationalFunctionAdapter.h"
-#include "storm/models/sparse/Dtmc.h"
-#include "storm/models/sparse/Mdp.h"
-#include "storm/models/sparse/StandardRewardModel.h"
-
-#include "storm/exceptions/InvalidArgumentException.h"
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-            
-            template <typename SparseModelType, typename ConstantType>
-            SparseInstantiationModelChecker<SparseModelType, ConstantType>::SparseInstantiationModelChecker(SparseModelType const& parametricModel) : parametricModel(parametricModel), instantiationsAreGraphPreserving(false) {
-                //Intentionally left empty
-            }
-            
-                
-            template <typename SparseModelType, typename ConstantType>
-            void SparseInstantiationModelChecker<SparseModelType, ConstantType>::specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) {
-                currentFormula = checkTask.getFormula().asSharedPointer();
-                currentCheckTask = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, ConstantType>>(checkTask.substituteFormula(*currentFormula).template convertValueType<ConstantType>());
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            void SparseInstantiationModelChecker<SparseModelType, ConstantType>::setInstantiationsAreGraphPreserving(bool value) {
-                instantiationsAreGraphPreserving = value;
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            bool SparseInstantiationModelChecker<SparseModelType, ConstantType>::getInstantiationsAreGraphPreserving() const {
-                return instantiationsAreGraphPreserving;
-            }
-            
-            template class SparseInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>;
-            template class SparseInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>;
-            
-            template class SparseInstantiationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>;
-            template class SparseInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>;
-
-        }
-    }
-}
diff --git a/src/storm/modelchecker/parametric/SparseInstantiationModelChecker.h b/src/storm/modelchecker/parametric/SparseInstantiationModelChecker.h
deleted file mode 100644
index d51f87f38..000000000
--- a/src/storm/modelchecker/parametric/SparseInstantiationModelChecker.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#pragma once
-
-#include "storm/logic/Formulas.h"
-#include "storm/modelchecker/CheckTask.h"
-#include "storm/modelchecker/results/CheckResult.h"
-#include "storm/modelchecker/hints/ModelCheckerHint.h"
-#include "storm/utility/parametric.h"
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-            
-            /*!
-             * Class to efficiently check a formula on a parametric model with different parameter instantiations
-             */
-            template <typename SparseModelType, typename ConstantType>
-            class SparseInstantiationModelChecker {
-            public:
-                SparseInstantiationModelChecker(SparseModelType const& parametricModel);
-                virtual ~SparseInstantiationModelChecker() = default;
-                
-                void specifyFormula(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask);
-                
-                virtual std::unique_ptr<CheckResult> check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) = 0;
-                
-                // If set, it is assumed that all considered model instantiations have the same underlying graph structure.
-                // This bypasses the graph analysis for the different instantiations.
-                void setInstantiationsAreGraphPreserving(bool value);
-                bool getInstantiationsAreGraphPreserving() const;
-                
-            protected:
-                
-                SparseModelType const& parametricModel;
-                std::unique_ptr<CheckTask<storm::logic::Formula, ConstantType>> currentCheckTask;
-                
-            private:
-                // store the current formula. Note that currentCheckTask only stores a reference to the formula.
-                std::shared_ptr<storm::logic::Formula const> currentFormula;
-
-                bool instantiationsAreGraphPreserving;
-            };
-        }
-    }
-}
diff --git a/src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.cpp b/src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.cpp
deleted file mode 100644
index 1be1e9ac8..000000000
--- a/src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-#include "SparseMdpInstantiationModelChecker.h"
-
-#include "storm/logic/FragmentSpecification.h"
-#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
-#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
-#include "storm/modelchecker/hints/ExplicitModelCheckerHint.h"
-#include "storm/storage/Scheduler.h"
-#include "storm/utility/graph.h"
-#include "storm/utility/vector.h"
-
-#include "storm/exceptions/InvalidArgumentException.h"
-#include "storm/exceptions/InvalidStateException.h"
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-            
-            template <typename SparseModelType, typename ConstantType>
-            SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::SparseMdpInstantiationModelChecker(SparseModelType const& parametricModel) : SparseInstantiationModelChecker<SparseModelType, ConstantType>(parametricModel), modelInstantiator(parametricModel) {
-                //Intentionally left empty
-            }
-    
-           template <typename SparseModelType, typename ConstantType>
-            std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) {
-                STORM_LOG_THROW(this->currentCheckTask, storm::exceptions::InvalidStateException, "Checking has been invoked but no property has been specified before.");
-                auto const& instantiatedModel = modelInstantiator.instantiate(valuation);
-                STORM_LOG_ASSERT(instantiatedModel.getTransitionMatrix().isProbabilistic(), "Instantiated matrix is not probabilistic!");
-                storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>> modelChecker(instantiatedModel);
-
-                // Check if there are some optimizations implemented for the specified property
-                if(this->currentCheckTask->getFormula().isInFragment(storm::logic::reachability())) {
-                    return checkReachabilityProbabilityFormula(modelChecker, instantiatedModel);
-                } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) {
-                    return checkReachabilityRewardFormula(modelChecker, instantiatedModel);
-                } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setProbabilityOperatorsAllowed(true).setBoundedUntilFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setTimeBoundedUntilFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) {
-                    return checkBoundedUntilFormula(modelChecker);
-                } else {
-                    return modelChecker.check(*this->currentCheckTask);
-                }
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityProbabilityFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel) {
-                
-                this->currentCheckTask->setProduceSchedulers(true);
-                
-                if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) {
-                    this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>());
-                }
-                ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>();
-                std::unique_ptr<CheckResult> result;
-                
-                // Check the formula and store the result as a hint for the next call.
-                // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula
-                if(this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) {
-                    result = modelChecker.check(*this->currentCheckTask);
-                    storm::storage::Scheduler<ConstantType> const& scheduler = result->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
-                    hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector());
-                    hint.setSchedulerHint(dynamic_cast<storm::storage::Scheduler<ConstantType> const&>(scheduler));
-                } else {
-                    auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false);
-                    std::unique_ptr<storm::modelchecker::CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask);
-                    result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
-                    storm::storage::Scheduler<ConstantType>& scheduler = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
-                    hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()));
-                    hint.setSchedulerHint(std::move(dynamic_cast<storm::storage::Scheduler<ConstantType>&>(scheduler)));
-                }
-                
-                if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) {
-                    // Extract the maybe states from the current result.
-                    assert(hint.hasResultHint());
-                    storm::storage::BitVector maybeStates = ~storm::utility::vector::filter<ConstantType>(hint.getResultHint(),
-                                    [] (ConstantType const& value) -> bool { return storm::utility::isZero<ConstantType>(value) || storm::utility::isOne<ConstantType>(value); });
-                    hint.setMaybeStates(std::move(maybeStates));
-                    hint.setComputeOnlyMaybeStates(true);
-                    
-                    // Check if there can be end components within the maybestates
-                    if (storm::solver::minimize(this->currentCheckTask->getOptimizationDirection()) ||
-                    storm::utility::graph::performProb1A(instantiatedModel.getTransitionMatrix(), instantiatedModel.getTransitionMatrix().getRowGroupIndices(), instantiatedModel.getBackwardTransitions(), hint.getMaybeStates(), ~hint.getMaybeStates()).full()) {
-                        hint.setNoEndComponentsInMaybeStates(true);
-                    }
-                }
-                
-                return result;
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::checkReachabilityRewardFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel) {
-                
-                this->currentCheckTask->setProduceSchedulers(true);
-                
-                if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) {
-                    this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>());
-                }
-                ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>();
-                std::unique_ptr<CheckResult> result;
-                
-                // Check the formula and store the result as a hint for the next call.
-                // For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula
-                if(this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) {
-                    std::unique_ptr<storm::modelchecker::CheckResult> result = modelChecker.check(*this->currentCheckTask);
-                    storm::storage::Scheduler<ConstantType> const& scheduler = result->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
-                    hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector());
-                    hint.setSchedulerHint(dynamic_cast<storm::storage::Scheduler<ConstantType> const&>(scheduler));
-                } else {
-                    auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false);
-                    std::unique_ptr<storm::modelchecker::CheckResult> quantitativeResult = modelChecker.computeRewards(this->currentCheckTask->getFormula().asRewardOperatorFormula().getMeasureType(), newCheckTask);
-                    result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
-                    storm::storage::Scheduler<ConstantType>& scheduler = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
-                    hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()));
-                    hint.setSchedulerHint(std::move(dynamic_cast<storm::storage::Scheduler<ConstantType>&>(scheduler)));
-                }
-                
-                if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) {
-                    // Extract the maybe states from the current result.
-                    assert(hint.hasResultHint());
-                    storm::storage::BitVector maybeStates = ~storm::utility::vector::filterInfinity(hint.getResultHint());
-                    // We need to exclude the target states from the maybe states.
-                    // Note that we can not consider the states with reward zero since a valuation might set a reward to zero
-                    std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asEventuallyFormula().getSubformula());
-                    maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector());
-                    hint.setMaybeStates(std::move(maybeStates));
-                    hint.setComputeOnlyMaybeStates(true);
-                    
-                    // Check if there can be end components within the maybestates
-                    if (storm::solver::maximize(this->currentCheckTask->getOptimizationDirection()) ||
-                    storm::utility::graph::performProb1A(instantiatedModel.getTransitionMatrix(), instantiatedModel.getTransitionMatrix().getRowGroupIndices(), instantiatedModel.getBackwardTransitions(), hint.getMaybeStates(), ~hint.getMaybeStates()).full()) {
-                        hint.setNoEndComponentsInMaybeStates(true);
-                    }
-                }
-                return result;
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            std::unique_ptr<CheckResult> SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>::checkBoundedUntilFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker) {
-                 
-                if (!this->currentCheckTask->getHint().isExplicitModelCheckerHint()) {
-                    this->currentCheckTask->setHint(std::make_shared<ExplicitModelCheckerHint<ConstantType>>());
-                }
-                std::unique_ptr<CheckResult> result;
-                ExplicitModelCheckerHint<ConstantType>& hint = this->currentCheckTask->getHint().template asExplicitModelCheckerHint<ConstantType>();
-                
-                if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) {
-                    // We extract the maybestates from the quantitative result
-                    // For qualitative properties, we still need a quantitative result. Hence we perform the check on the subformula
-                    if (this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) {
-                        result = modelChecker.check(*this->currentCheckTask);
-                        hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector());
-                    } else {
-                        auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false);
-                        std::unique_ptr<CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask);
-                        result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
-                        hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()));
-                    }
-                    storm::storage::BitVector maybeStates = storm::utility::vector::filterGreaterZero(hint.getResultHint());
-                    // We need to exclude the target states from the maybe states.
-                    // Note that we can not consider the states with probability one since a state might reach a target state with prob 1 within >0 steps
-                    std::unique_ptr<CheckResult> subFormulaResult = modelChecker.check(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula().asBoundedUntilFormula().getRightSubformula());
-                    maybeStates = maybeStates & ~(subFormulaResult->asExplicitQualitativeCheckResult().getTruthValuesVector());
-                    hint.setMaybeStates(std::move(maybeStates));
-                    hint.setComputeOnlyMaybeStates(true);
-                } else {
-                    result = modelChecker.check(*this->currentCheckTask);
-                }
-                return result;
-            }
-            
-            template class SparseMdpInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>;
-            template class SparseMdpInstantiationModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>;
-
-        }
-    }
-}
diff --git a/src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.h b/src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.h
deleted file mode 100644
index a5570acc0..000000000
--- a/src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#pragma once
-
-#include <memory>
-
-#include "storm/models/sparse/Mdp.h"
-#include "storm/models/sparse/Dtmc.h"
-#include "storm/models/sparse/StandardRewardModel.h"
-#include "storm/modelchecker/parametric/SparseInstantiationModelChecker.h"
-#include "storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h"
-#include "storm/utility/ModelInstantiator.h"
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-            
-            /*!
-             * Class to efficiently check a formula on a parametric model with different parameter instantiations
-             */
-            template <typename SparseModelType, typename ConstantType>
-            class SparseMdpInstantiationModelChecker : public SparseInstantiationModelChecker<SparseModelType, ConstantType> {
-            public:
-                SparseMdpInstantiationModelChecker(SparseModelType const& parametricModel);
-                
-                virtual std::unique_ptr<CheckResult> check(storm::utility::parametric::Valuation<typename SparseModelType::ValueType> const& valuation) override;
-
-            protected:
-                // Optimizations for the different formula types
-                std::unique_ptr<CheckResult> checkReachabilityProbabilityFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel);
-                std::unique_ptr<CheckResult> checkReachabilityRewardFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker, storm::models::sparse::Mdp<ConstantType> const& instantiatedModel);
-                std::unique_ptr<CheckResult> checkBoundedUntilFormula(storm::modelchecker::SparseMdpPrctlModelChecker<storm::models::sparse::Mdp<ConstantType>>& modelChecker);
-                
-                storm::utility::ModelInstantiator<SparseModelType, storm::models::sparse::Mdp<ConstantType>> modelInstantiator;
-            };
-        }
-    }
-}
diff --git a/src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.cpp b/src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.cpp
deleted file mode 100644
index 7b8df081a..000000000
--- a/src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.cpp
+++ /dev/null
@@ -1,348 +0,0 @@
-#include "storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.h"
-
-#include "storm/adapters/RationalFunctionAdapter.h"
-#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h"
-#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
-#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
-#include "storm/models/sparse/Mdp.h"
-#include "storm/models/sparse/StandardRewardModel.h"
-#include "storm/utility/vector.h"
-#include "storm/utility/graph.h"
-#include "storm/utility/NumberTraits.h"
-#include "storm/solver/StandardGameSolver.h"
-#include "storm/logic/FragmentSpecification.h"
-
-#include "storm/exceptions/InvalidArgumentException.h"
-#include "storm/exceptions/InvalidPropertyException.h"
-#include "storm/exceptions/NotSupportedException.h"
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-            
-            template <typename SparseModelType, typename ConstantType>
-            SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseMdpParameterLiftingModelChecker(SparseModelType const& parametricModel) : SparseParameterLiftingModelChecker<SparseModelType, ConstantType>(parametricModel), solverFactory(std::make_unique<storm::solver::GameSolverFactory<ConstantType>>()) {
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseMdpParameterLiftingModelChecker(SparseModelType const& parametricModel, std::unique_ptr<storm::solver::GameSolverFactory<ConstantType>>&& solverFactory) : SparseParameterLiftingModelChecker<SparseModelType, ConstantType>(parametricModel), solverFactory(std::move(solverFactory)) {
-            }
-    
-            template <typename SparseModelType, typename ConstantType>
-            bool SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::canHandle(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const {
-                return checkTask.getFormula().isInFragment(storm::logic::reachability().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setBoundedUntilFormulasAllowed(true).setStepBoundedUntilFormulasAllowed(true).setCumulativeRewardFormulasAllowed(true));
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) {
-                
-                // get the step bound
-                STORM_LOG_THROW(!checkTask.getFormula().hasLowerBound(), storm::exceptions::NotSupportedException, "Lower step bounds are not supported.");
-                STORM_LOG_THROW(checkTask.getFormula().hasUpperBound(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with an upper bound.");
-                STORM_LOG_THROW(checkTask.getFormula().isStepBounded(), storm::exceptions::NotSupportedException, "Expected a bounded until formula with step bounds.");
-                stepBound = checkTask.getFormula().getUpperBound().evaluateAsInt();
-                STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
-                if (checkTask.getFormula().isUpperBoundStrict()) {
-                    STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero.");
-                    --(*stepBound);
-                }
-                STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
-
-                // get the results for the subformulas
-                storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(this->parametricModel);
-                STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported");
-                storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
-                storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
-                
-                // get the maybeStates
-                maybeStates = storm::solver::minimize(checkTask.getOptimizationDirection()) ?
-                              storm::utility::graph::performProbGreater0A(this->parametricModel.getTransitionMatrix(), this->parametricModel.getTransitionMatrix().getRowGroupIndices(), this->parametricModel.getBackwardTransitions(), phiStates, psiStates, true, *stepBound) :
-                              storm::utility::graph::performProbGreater0E(this->parametricModel.getBackwardTransitions(), phiStates, psiStates, true, *stepBound);
-                maybeStates &= ~psiStates;
-                
-                // set the result for all non-maybe states
-                resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates(), storm::utility::zero<ConstantType>());
-                storm::utility::vector::setVectorValues(resultsForNonMaybeStates, psiStates, storm::utility::one<ConstantType>());
-                
-                // if there are maybestates, create the parameterLifter
-                if (!maybeStates.empty()) {
-                    // Create the vector of one-step probabilities to go to target states.
-                    std::vector<typename SparseModelType::ValueType> b = this->parametricModel.getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getRowCount(), true), psiStates);
-                    
-                    parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, this->parametricModel.getTransitionMatrix().getRowFilter(maybeStates), maybeStates);
-                    computePlayer1Matrix();
-                    
-                    applyPreviousResultAsHint = false;
-                }
-                
-                // We know some bounds for the results
-                lowerResultBound = storm::utility::zero<ConstantType>();
-                upperResultBound = storm::utility::one<ConstantType>();
-            }
-    
-            template <typename SparseModelType, typename ConstantType>
-            void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) {
-                
-                // get the results for the subformulas
-                storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(this->parametricModel);
-                STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getLeftSubformula()) && propositionalChecker.canHandle(checkTask.getFormula().getRightSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported");
-                storm::storage::BitVector phiStates = std::move(propositionalChecker.check(checkTask.getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
-                storm::storage::BitVector psiStates = std::move(propositionalChecker.check(checkTask.getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
-                
-                // get the maybeStates
-                std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 = storm::solver::minimize(checkTask.getOptimizationDirection()) ?
-                                                                                                          storm::utility::graph::performProb01Min(this->parametricModel.getTransitionMatrix(), this->parametricModel.getTransitionMatrix().getRowGroupIndices(), this->parametricModel.getBackwardTransitions(), phiStates, psiStates) :
-                                                                                                          storm::utility::graph::performProb01Max(this->parametricModel.getTransitionMatrix(), this->parametricModel.getTransitionMatrix().getRowGroupIndices(), this->parametricModel.getBackwardTransitions(), phiStates, psiStates);
-                maybeStates = ~(statesWithProbability01.first | statesWithProbability01.second);
-                
-                // set the result for all non-maybe states
-                resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates(), storm::utility::zero<ConstantType>());
-                storm::utility::vector::setVectorValues(resultsForNonMaybeStates, statesWithProbability01.second, storm::utility::one<ConstantType>());
-                
-                // if there are maybestates, create the parameterLifter
-                if (!maybeStates.empty()) {
-                    // Create the vector of one-step probabilities to go to target states.
-                    std::vector<typename SparseModelType::ValueType> b = this->parametricModel.getTransitionMatrix().getConstrainedRowSumVector(storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getRowCount(), true), statesWithProbability01.second);
-                    
-                    parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, this->parametricModel.getTransitionMatrix().getRowFilter(maybeStates), maybeStates);
-                    computePlayer1Matrix();
-                    
-                    // Check whether there is an EC consisting of maybestates
-                    applyPreviousResultAsHint = storm::solver::minimize(checkTask.getOptimizationDirection()) || // when minimizing, there can not be an EC within the maybestates
-                                                storm::utility::graph::performProb1A(this->parametricModel.getTransitionMatrix(), this->parametricModel.getTransitionMatrix().getRowGroupIndices(), this->parametricModel.getBackwardTransitions(), maybeStates, ~maybeStates).full();
-                }
-                                
-                // We know some bounds for the results
-                lowerResultBound = storm::utility::zero<ConstantType>();
-                upperResultBound = storm::utility::one<ConstantType>();
-            }
-    
-            template <typename SparseModelType, typename ConstantType>
-            void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) {
-                
-                // get the results for the subformula
-                storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> propositionalChecker(this->parametricModel);
-                STORM_LOG_THROW(propositionalChecker.canHandle(checkTask.getFormula().getSubformula()), storm::exceptions::NotSupportedException, "Parameter lifting with non-propositional subformulas is not supported");
-                storm::storage::BitVector targetStates = std::move(propositionalChecker.check(checkTask.getFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
-                
-                // get the maybeStates
-                storm::storage::BitVector infinityStates = storm::solver::minimize(checkTask.getOptimizationDirection()) ?
-                                                           storm::utility::graph::performProb1E(this->parametricModel.getTransitionMatrix(), this->parametricModel.getTransitionMatrix().getRowGroupIndices(), this->parametricModel.getBackwardTransitions(), storm::storage::BitVector(this->parametricModel.getNumberOfStates(), true), targetStates) :
-                                                           storm::utility::graph::performProb1A(this->parametricModel.getTransitionMatrix(), this->parametricModel.getTransitionMatrix().getRowGroupIndices(), this->parametricModel.getBackwardTransitions(), storm::storage::BitVector(this->parametricModel.getNumberOfStates(), true), targetStates);
-                infinityStates.complement();
-                maybeStates = ~(targetStates | infinityStates);
-                
-                // set the result for all the non-maybe states
-                resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates(), storm::utility::zero<ConstantType>());
-                storm::utility::vector::setVectorValues(resultsForNonMaybeStates, infinityStates, storm::utility::infinity<ConstantType>());
-                
-                // if there are maybestates, create the parameterLifter
-                if (!maybeStates.empty()) {
-                    // Create the reward vector
-                    STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel.hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel.hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model.");
-
-                    typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel.getRewardModel(checkTask.getRewardModel()) : this->parametricModel.getUniqueRewardModel();
-
-                    std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel.getTransitionMatrix());
-                    
-                    // We need to handle choices that lead to an infinity state.
-                    // As a maybeState does not have reward infinity, a choice leading to an infinity state will never be picked. Hence, we can unselect the corresponding rows
-                    storm::storage::BitVector selectedRows = this->parametricModel.getTransitionMatrix().getRowFilter(maybeStates, ~infinityStates);
-                    
-                    parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, selectedRows, maybeStates);
-                    computePlayer1Matrix();
-                    
-                    // Check whether there is an EC consisting of maybestates
-                    applyPreviousResultAsHint = !storm::solver::minimize(checkTask.getOptimizationDirection()) || // when maximizing, there can not be an EC within the maybestates
-                                                storm::utility::graph::performProb1A(this->parametricModel.getTransitionMatrix(), this->parametricModel.getTransitionMatrix().getRowGroupIndices(), this->parametricModel.getBackwardTransitions(), maybeStates, ~maybeStates).full();
-                }
-                
-                // We only know a lower bound for the result
-                lowerResultBound = storm::utility::zero<ConstantType>();
-
-            }
-    
-            template <typename SparseModelType, typename ConstantType>
-            void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) {
-                
-                // Obtain the stepBound
-                stepBound = checkTask.getFormula().getBound().evaluateAsInt();
-                if (checkTask.getFormula().isBoundStrict()) {
-                    STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Expected a strict upper step bound that is greater than zero.");
-                    --(*stepBound);
-                }
-                STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException, "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
-                
-                //Every state is a maybeState
-                maybeStates = storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getColumnCount(), true);
-                resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel.getNumberOfStates());
-
-                // Create the reward vector
-                STORM_LOG_THROW((checkTask.isRewardModelSet() && this->parametricModel.hasRewardModel(checkTask.getRewardModel())) || (!checkTask.isRewardModelSet() && this->parametricModel.hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by the CheckTask is not available in the given model.");
-                typename SparseModelType::RewardModelType const& rewardModel = checkTask.isRewardModelSet() ? this->parametricModel.getRewardModel(checkTask.getRewardModel()) : this->parametricModel.getUniqueRewardModel();
-                std::vector<typename SparseModelType::ValueType> b = rewardModel.getTotalRewardVector(this->parametricModel.getTransitionMatrix());
-                    
-                parameterLifter = std::make_unique<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>>(this->parametricModel.getTransitionMatrix(), b, storm::storage::BitVector(this->parametricModel.getTransitionMatrix().getRowCount(), true), maybeStates);
-                computePlayer1Matrix();
-
-                applyPreviousResultAsHint = false;
-                
-                // We only know a lower bound for the result
-                lowerResultBound = storm::utility::zero<ConstantType>();
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            std::unique_ptr<CheckResult> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) {
-                
-                if(maybeStates.empty()) {
-                    return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(resultsForNonMaybeStates);
-                }
-                
-                parameterLifter->specifyRegion(region, dirForParameters);
-                
-                // Set up the solver
-                auto solver = solverFactory->create(player1Matrix, parameterLifter->getMatrix());
-                if (storm::NumberTraits<ConstantType>::IsExact && dynamic_cast<storm::solver::StandardGameSolver<ConstantType>*>(solver.get())) {
-                    STORM_LOG_INFO("Parameter Lifting: Setting solution method for exact Game Solver to policy iteration");
-                    auto* standardSolver = dynamic_cast<storm::solver::StandardGameSolver<ConstantType>*>(solver.get());
-                    auto settings = standardSolver->getSettings();
-                    settings.setSolutionMethod(storm::solver::StandardGameSolverSettings<ConstantType>::SolutionMethod::PolicyIteration);
-                    standardSolver->setSettings(settings);
-                }
-                if (lowerResultBound) solver->setLowerBound(lowerResultBound.get());
-                if (upperResultBound) solver->setUpperBound(upperResultBound.get());
-                if (applyPreviousResultAsHint) {
-                    solver->setTrackSchedulers(true);
-                    x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
-                    if(storm::solver::minimize(dirForParameters) && minSchedChoices && player1SchedChoices) solver->setSchedulerHints(std::move(player1SchedChoices.get()), std::move(minSchedChoices.get()));
-                    if(storm::solver::maximize(dirForParameters) && maxSchedChoices && player1SchedChoices) solver->setSchedulerHints(std::move(player1SchedChoices.get()), std::move(maxSchedChoices.get()));
-                } else {
-                    x.assign(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
-                }
-                if (this->currentCheckTask->isBoundSet() && this->currentCheckTask->getOptimizationDirection() == dirForParameters && solver->hasSchedulerHints()) {
-                    // If we reach this point, we know that after applying the hints, the x-values can only become larger (if we maximize) or smaller (if we minimize).
-                    std::unique_ptr<storm::solver::TerminationCondition<ConstantType>> termCond;
-                    storm::storage::BitVector relevantStatesInSubsystem = this->currentCheckTask->isOnlyInitialStatesRelevantSet() ? this->parametricModel.getInitialStates() % maybeStates : storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true);
-                    if (storm::solver::minimize(dirForParameters)) {
-                        // Terminate if the value for ALL relevant states is already below the threshold
-                        termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumBelowThreshold<ConstantType>> (relevantStatesInSubsystem, this->currentCheckTask->getBoundThreshold(), true, false);
-                    } else {
-                        // Terminate if the value for ALL relevant states is already above the threshold
-                        termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumExceedsThreshold<ConstantType>> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), true);
-                    }
-                    solver->setTerminationCondition(std::move(termCond));
-                }
-                
-                // Invoke the solver
-                if(stepBound) {
-                    assert(*stepBound > 0);
-                    solver->repeatedMultiply(this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, &parameterLifter->getVector(), *stepBound);
-                } else {
-                    solver->solveGame(this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, parameterLifter->getVector());
-                    if(applyPreviousResultAsHint) {
-                        if(storm::solver::minimize(dirForParameters)) {
-                            minSchedChoices = solver->getPlayer2SchedulerChoices();
-                        } else {
-                            maxSchedChoices = solver->getPlayer2SchedulerChoices();
-                        }
-                        player1SchedChoices = solver->getPlayer1SchedulerChoices();
-                    }
-                }
-                
-                // Get the result for the complete model (including maybestates)
-                std::vector<ConstantType> result = resultsForNonMaybeStates;
-                auto maybeStateResIt = x.begin();
-                for(auto const& maybeState : maybeStates) {
-                    result[maybeState] = *maybeStateResIt;
-                    ++maybeStateResIt;
-                }
-                return std::make_unique<storm::modelchecker::ExplicitQuantitativeCheckResult<ConstantType>>(std::move(result));
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::computePlayer1Matrix() {
-                uint_fast64_t n = 0;
-                for(auto const& maybeState : maybeStates) {
-                    n += this->parametricModel.getTransitionMatrix().getRowGroupSize(maybeState);
-                }
-                // The player 1 matrix is the identity matrix of size n with the row groups as given by the original matrix
-                storm::storage::SparseMatrixBuilder<storm::storage::sparse::state_type> matrixBuilder(n, n, n, true, true, maybeStates.getNumberOfSetBits());
-                uint_fast64_t p1MatrixRow = 0;
-                for (auto maybeState : maybeStates){
-                    matrixBuilder.newRowGroup(p1MatrixRow);
-                    for (uint_fast64_t row = this->parametricModel.getTransitionMatrix().getRowGroupIndices()[maybeState]; row < this->parametricModel.getTransitionMatrix().getRowGroupIndices()[maybeState + 1]; ++row){
-                        matrixBuilder.addNextValue(p1MatrixRow, p1MatrixRow, storm::utility::one<storm::storage::sparse::state_type>());
-                        ++p1MatrixRow;
-                    }
-                }
-                player1Matrix = matrixBuilder.build();
-            }
-    
-            template <typename SparseModelType, typename ConstantType>
-            void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::reset() {
-                maybeStates.resize(0);
-                resultsForNonMaybeStates.clear();
-                stepBound = boost::none;
-                player1Matrix = storm::storage::SparseMatrix<storm::storage::sparse::state_type>();
-                parameterLifter = nullptr;
-                minSchedChoices = boost::none;
-                maxSchedChoices = boost::none;
-                x.clear();
-                lowerResultBound = boost::none;
-                upperResultBound = boost::none;
-                applyPreviousResultAsHint = false;
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMinScheduler() {
-                if (!minSchedChoices) {
-                    return boost::none;
-                }
-                
-                storm::storage::Scheduler<ConstantType> result(minSchedChoices->size());
-                uint_fast64_t state = 0;
-                for (auto const& schedulerChoice : minSchedChoices.get()) {
-                    result.setChoice(schedulerChoice, state);
-                    ++state;
-                }
-                
-                return result;
-            }
-                    
-            template <typename SparseModelType, typename ConstantType>
-            boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMaxScheduler() {
-                if (!maxSchedChoices) {
-                    return boost::none;
-                }
-                
-                storm::storage::Scheduler<ConstantType> result(maxSchedChoices->size());
-                uint_fast64_t state = 0;
-                for (auto const& schedulerChoice : maxSchedChoices.get()) {
-                    result.setChoice(schedulerChoice, state);
-                    ++state;
-                }
-                
-                return result;
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentPlayer1Scheduler() {
-                if (!player1SchedChoices) {
-                    return boost::none;
-                }
-                
-                storm::storage::Scheduler<ConstantType> result(player1SchedChoices->size());
-                uint_fast64_t state = 0;
-                for (auto const& schedulerChoice : player1SchedChoices.get()) {
-                    result.setChoice(schedulerChoice, state);
-                    ++state;
-                }
-                
-                return result;
-            }
-    
-            template class SparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>;
-            template class SparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>;
-        }
-    }
-}
diff --git a/src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.h b/src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.h
deleted file mode 100644
index 4e0b6e068..000000000
--- a/src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#pragma once
-
-#include <vector>
-#include <memory>
-#include <boost/optional.hpp>
-
-#include "storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h"
-#include "storm/storage/BitVector.h"
-#include "storm/storage/SparseMatrix.h"
-#include "storm/storage/sparse/StateType.h"
-#include "storm/solver/GameSolver.h"
-#include "storm/transformer/ParameterLifter.h"
-#include "storm/storage/Scheduler.h"
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-            
-            template <typename SparseModelType, typename ConstantType>
-            class SparseMdpParameterLiftingModelChecker : public SparseParameterLiftingModelChecker<SparseModelType, ConstantType> {
-            public:
-                SparseMdpParameterLiftingModelChecker(SparseModelType const& parametricModel);
-                SparseMdpParameterLiftingModelChecker(SparseModelType const& parametricModel, std::unique_ptr<storm::solver::GameSolverFactory<ConstantType>>&& solverFactory);
-                
-                virtual bool canHandle(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const override;
-                
-                boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMinScheduler();
-                boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMaxScheduler();
-                boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentPlayer1Scheduler();
-                
-            protected:
-                
-                virtual void specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask) override;
-                virtual void specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask) override;
-                virtual void specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask) override;
-                virtual void specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask) override;
-                
-                virtual std::unique_ptr<CheckResult> computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) override;
-                
-                virtual void reset() override;
-                
-
-            private:
-                void computePlayer1Matrix();
-                
-                storm::storage::BitVector maybeStates;
-                std::vector<ConstantType> resultsForNonMaybeStates;
-                boost::optional<uint_fast64_t> stepBound;
-                
-                storm::storage::SparseMatrix<storm::storage::sparse::state_type> player1Matrix;
-                std::unique_ptr<storm::transformer::ParameterLifter<typename SparseModelType::ValueType, ConstantType>> parameterLifter;
-                std::unique_ptr<storm::solver::GameSolverFactory<ConstantType>> solverFactory;
-                
-                // Results from the most recent solver call.
-                boost::optional<std::vector<uint_fast64_t>> minSchedChoices, maxSchedChoices;
-                boost::optional<std::vector<uint_fast64_t>> player1SchedChoices;
-                std::vector<ConstantType> x;
-                boost::optional<ConstantType> lowerResultBound, upperResultBound;
-                bool applyPreviousResultAsHint;
-            };
-        }
-    }
-}
diff --git a/src/storm/modelchecker/parametric/SparseMdpRegionChecker.cpp b/src/storm/modelchecker/parametric/SparseMdpRegionChecker.cpp
deleted file mode 100644
index 9ffa707fa..000000000
--- a/src/storm/modelchecker/parametric/SparseMdpRegionChecker.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-#include "storm/modelchecker/parametric/SparseMdpRegionChecker.h"
-
-#include "storm/adapters/RationalFunctionAdapter.h"
-
-#include "storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.h"
-#include "storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.h"
-#include "storm/transformer/SparseParametricMdpSimplifier.h"
-#include "storm/models/sparse/StandardRewardModel.h"
-#include "storm/models/sparse/Mdp.h"
-#include "storm/utility/NumberTraits.h"
-
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            SparseMdpRegionChecker<SparseModelType, ConstantType, ExactConstantType>::SparseMdpRegionChecker(SparseModelType const& parametricModel) : RegionChecker<SparseModelType, ConstantType, ExactConstantType>(parametricModel) {
-                // Intentionally left empty
-            }
-    
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            void SparseMdpRegionChecker<SparseModelType, ConstantType, ExactConstantType>::simplifyParametricModel(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) {
-                storm::transformer::SparseParametricMdpSimplifier<SparseModelType> simplifier(this->parametricModel);
-                if(simplifier.simplify(checkTask.getFormula())) {
-                    this->simplifiedModel = simplifier.getSimplifiedModel();
-                    this->currentFormula = simplifier.getSimplifiedFormula();
-                } else {
-                    this->simplifiedModel = nullptr;
-                    this->currentFormula = checkTask.getFormula().asSharedPointer();
-                }
-            }
-            
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            void SparseMdpRegionChecker<SparseModelType, ConstantType, ExactConstantType>::initializeUnderlyingCheckers() {
-                if (this->settings.applyExactValidation) {
-                    STORM_LOG_WARN_COND(!storm::NumberTraits<ConstantType>::IsExact, "Exact validation is not necessarry if the original computation is already exact");
-                    this->exactParameterLiftingChecker = std::make_unique<SparseMdpParameterLiftingModelChecker<SparseModelType, ExactConstantType>>(this->getConsideredParametricModel());
-                }
-                this->parameterLiftingChecker = std::make_unique<SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>>(this->getConsideredParametricModel());
-                this->instantiationChecker = std::make_unique<SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>>(this->getConsideredParametricModel());
-                this->instantiationChecker->setInstantiationsAreGraphPreserving(true);
-            }
-    
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType>
-            void SparseMdpRegionChecker<SparseModelType, ConstantType, ExactConstantType>::applyHintsToExactChecker() {
-                auto MdpPLChecker = dynamic_cast<storm::modelchecker::parametric::SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>*>(this->parameterLiftingChecker.get());
-                STORM_LOG_ASSERT(MdpPLChecker, "Underlying Parameter lifting checker has unexpected type");
-                auto exactMdpPLChecker = dynamic_cast<storm::modelchecker::parametric::SparseMdpParameterLiftingModelChecker<SparseModelType, ExactConstantType>*>(this->exactParameterLiftingChecker.get());
-                STORM_LOG_ASSERT(exactMdpPLChecker, "Underlying exact parameter lifting checker has unexpected type");
-                if (MdpPLChecker->getCurrentMaxScheduler()) {
-                    exactMdpPLChecker->getCurrentMaxScheduler() = MdpPLChecker->getCurrentMaxScheduler()->template toValueType<ExactConstantType>();
-                }
-                if (MdpPLChecker->getCurrentMinScheduler()) {
-                    exactMdpPLChecker->getCurrentMinScheduler() = MdpPLChecker->getCurrentMinScheduler()->template toValueType<ExactConstantType>();
-                }
-                if (MdpPLChecker->getCurrentPlayer1Scheduler()) {
-                    exactMdpPLChecker->getCurrentPlayer1Scheduler() = MdpPLChecker->getCurrentPlayer1Scheduler()->template toValueType<ExactConstantType>();
-                }
-            }
-            
-       
-#ifdef STORM_HAVE_CARL
-            template class SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber>;
-            template class SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>;
-#endif
-        } // namespace parametric
-    } //namespace modelchecker
-} //namespace storm
-
diff --git a/src/storm/modelchecker/parametric/SparseMdpRegionChecker.h b/src/storm/modelchecker/parametric/SparseMdpRegionChecker.h
deleted file mode 100644
index 72c355eee..000000000
--- a/src/storm/modelchecker/parametric/SparseMdpRegionChecker.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#pragma once
-
-#include <memory>
-
-#include "storm/modelchecker/parametric/RegionChecker.h"
-
-namespace storm {
-    namespace modelchecker{
-        namespace parametric{
-            
-
-            template <typename SparseModelType, typename ConstantType, typename ExactConstantType = ConstantType>
-            class SparseMdpRegionChecker : public RegionChecker<SparseModelType, ConstantType, ExactConstantType> {
-                
-            public:
-                SparseMdpRegionChecker(SparseModelType const& parametricModel);
-                
-            protected:
-
-                virtual void initializeUnderlyingCheckers() override;
-                virtual void simplifyParametricModel(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) override;
-                virtual void applyHintsToExactChecker() override;
-                
-            };
-    
-        } //namespace parametric
-    } //namespace modelchecker
-} //namespace storm
diff --git a/src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.cpp b/src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.cpp
deleted file mode 100644
index 8c9af8957..000000000
--- a/src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-#include "SparseParameterLiftingModelChecker.h"
-
-#include "storm/adapters/RationalFunctionAdapter.h"
-#include "storm/logic/FragmentSpecification.h"
-#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
-#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
-#include "storm/models/sparse/Dtmc.h"
-#include "storm/models/sparse/Mdp.h"
-#include "storm/models/sparse/StandardRewardModel.h"
-
-#include "storm/exceptions/InvalidArgumentException.h"
-#include "storm/exceptions/NotSupportedException.h"
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-            
-            template <typename SparseModelType, typename ConstantType>
-            SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::SparseParameterLiftingModelChecker(SparseModelType const& parametricModel) : parametricModel(parametricModel) {
-                //Intentionally left empty
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) {
-                reset();
-                currentFormula = checkTask.getFormula().asSharedPointer();
-                currentCheckTask = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, ConstantType>>(checkTask.substituteFormula(*currentFormula).template convertValueType<ConstantType>());
-                
-                if(currentCheckTask->getFormula().isProbabilityOperatorFormula()) {
-                    auto const& probOpFormula = currentCheckTask->getFormula().asProbabilityOperatorFormula();
-                    if(probOpFormula.getSubformula().isBoundedUntilFormula()) {
-                        specifyBoundedUntilFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asBoundedUntilFormula()));
-                    } else if(probOpFormula.getSubformula().isUntilFormula()) {
-                        specifyUntilFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asUntilFormula()));
-                    } else if (probOpFormula.getSubformula().isEventuallyFormula()) {
-                        specifyReachabilityProbabilityFormula(currentCheckTask->substituteFormula(probOpFormula.getSubformula().asEventuallyFormula()));
-                    } else {
-                        STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
-                    }
-                } else if (currentCheckTask->getFormula().isRewardOperatorFormula()) {
-                    auto const& rewOpFormula = currentCheckTask->getFormula().asRewardOperatorFormula();
-                    if(rewOpFormula.getSubformula().isEventuallyFormula()) {
-                        specifyReachabilityRewardFormula(currentCheckTask->substituteFormula(rewOpFormula.getSubformula().asEventuallyFormula()));
-                    } else if (rewOpFormula.getSubformula().isCumulativeRewardFormula()) {
-                        specifyCumulativeRewardFormula(currentCheckTask->substituteFormula(rewOpFormula.getSubformula().asCumulativeRewardFormula()));
-                    }
-                }
-            }
-            
-            template <typename SparseModelType, typename ConstantType>
-            std::unique_ptr<CheckResult> SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::check(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) {
-                auto quantitativeResult = computeQuantitativeValues(region, dirForParameters);
-                if(currentCheckTask->getFormula().hasQuantitativeResult()) {
-                    return quantitativeResult;
-                } else {
-                    return quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
-                }
-            }
-    
-            template <typename SparseModelType, typename ConstantType>
-            void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyBoundedUntilFormula(CheckTask<logic::BoundedUntilFormula, ConstantType> const& checkTask) {
-                STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
-            }
-    
-            template <typename SparseModelType, typename ConstantType>
-            void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyUntilFormula(CheckTask<logic::UntilFormula, ConstantType> const& checkTask) {
-                STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
-            }
-    
-            template <typename SparseModelType, typename ConstantType>
-            void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityProbabilityFormula(CheckTask<logic::EventuallyFormula, ConstantType> const& checkTask) {
-                // transform to until formula
-                auto untilFormula = std::make_shared<storm::logic::UntilFormula const>(storm::logic::Formula::getTrueFormula(), checkTask.getFormula().getSubformula().asSharedPointer());
-                specifyUntilFormula(currentCheckTask->substituteFormula(*untilFormula));
-            }
-    
-            template <typename SparseModelType, typename ConstantType>
-            void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyReachabilityRewardFormula(CheckTask<logic::EventuallyFormula, ConstantType> const& checkTask) {
-                STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
-            }
-    
-            template <typename SparseModelType, typename ConstantType>
-            void SparseParameterLiftingModelChecker<SparseModelType, ConstantType>::specifyCumulativeRewardFormula(CheckTask<logic::CumulativeRewardFormula, ConstantType> const& checkTask) {
-                STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameter lifting is not supported for the given property.");
-            }
-    
-            template class SparseParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>;
-            template class SparseParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>;
-            template class SparseParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::RationalNumber>;
-            template class SparseParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, storm::RationalNumber>;
-
-        }
-    }
-}
diff --git a/src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h b/src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h
deleted file mode 100644
index c71d0d25d..000000000
--- a/src/storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#pragma once
-
-#include "storm/logic/Formulas.h"
-#include "storm/modelchecker/CheckTask.h"
-#include "storm/modelchecker/results/CheckResult.h"
-#include "storm/storage/ParameterRegion.h"
-#include "storm/solver/OptimizationDirection.h"
-#include "storm/utility/parametric.h"
-
-namespace storm {
-    namespace modelchecker {
-        namespace parametric {
-            
-            /*!
-             * Class to approximatively check a formula on a parametric model for all parameter valuations within a region
-             * It is assumed that all considered valuations are graph-preserving and well defined, i.e.,
-             * * all non-const transition probabilities evaluate to some non-zero value
-             * * the sum of all outgoing transitions is one
-             */
-            template <typename SparseModelType, typename ConstantType>
-            class SparseParameterLiftingModelChecker {
-            public:
-                SparseParameterLiftingModelChecker(SparseModelType const& parametricModel);
-                virtual ~SparseParameterLiftingModelChecker() = default;
-                
-                virtual bool canHandle(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const = 0;
-                
-                void specifyFormula(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask);
-    
-                /*!
-                 * Checks the specified formula on the given region by applying parameter lifting (Parameter choices are lifted to nondeterministic choices)
-                 * This yields a (sound) approximative model checking result.
-
-                 * @param region the region on which parameter lifting is applied
-                 * @param dirForParameters  The optimization direction for the parameter choices. If this is, e.g., minimize, then the returned result will be a lower bound for all results induced by the parameter evaluations inside the region.
-                 */
-                std::unique_ptr<CheckResult> check(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters);
-                
-            protected:
-                
-                virtual void specifyBoundedUntilFormula(CheckTask<storm::logic::BoundedUntilFormula, ConstantType> const& checkTask);
-                virtual void specifyUntilFormula(CheckTask<storm::logic::UntilFormula, ConstantType> const& checkTask);
-                virtual void specifyReachabilityProbabilityFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask);
-                virtual void specifyReachabilityRewardFormula(CheckTask<storm::logic::EventuallyFormula, ConstantType> const& checkTask);
-                virtual void specifyCumulativeRewardFormula(CheckTask<storm::logic::CumulativeRewardFormula, ConstantType> const& checkTask);
-                
-                virtual std::unique_ptr<CheckResult> computeQuantitativeValues(storm::storage::ParameterRegion<typename SparseModelType::ValueType> const& region, storm::solver::OptimizationDirection const& dirForParameters) = 0;
-                
-                virtual void reset() = 0;
-                
-                SparseModelType const& parametricModel;
-                std::unique_ptr<CheckTask<storm::logic::Formula, ConstantType>> currentCheckTask;
-              
-            private:
-                // store the current formula. Note that currentCheckTask only stores a reference to the formula.
-                std::shared_ptr<storm::logic::Formula const> currentFormula;
-            };
-        }
-    }
-}
diff --git a/src/storm/settings/SettingsManager.cpp b/src/storm/settings/SettingsManager.cpp
index a386dc94c..493ea71a2 100644
--- a/src/storm/settings/SettingsManager.cpp
+++ b/src/storm/settings/SettingsManager.cpp
@@ -30,7 +30,6 @@
 #include "storm/settings/modules/GlpkSettings.h"
 #include "storm/settings/modules/GurobiSettings.h"
 #include "storm/settings/modules/Smt2SmtSolverSettings.h"
-#include "storm/settings/modules/ParametricSettings.h"
 #include "storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h"
 #include "storm/settings/modules/ExplorationSettings.h"
 #include "storm/settings/modules/ResourceSettings.h"
@@ -527,7 +526,6 @@ namespace storm {
             storm::settings::addModule<storm::settings::modules::GlpkSettings>();
             storm::settings::addModule<storm::settings::modules::GurobiSettings>();
             storm::settings::addModule<storm::settings::modules::TopologicalValueIterationEquationSolverSettings>();
-            storm::settings::addModule<storm::settings::modules::ParametricSettings>();
             storm::settings::addModule<storm::settings::modules::Smt2SmtSolverSettings>();
             storm::settings::addModule<storm::settings::modules::ExplorationSettings>();
             storm::settings::addModule<storm::settings::modules::ResourceSettings>();
diff --git a/src/storm/settings/modules/CoreSettings.cpp b/src/storm/settings/modules/CoreSettings.cpp
index cb42bfd4b..964518b64 100644
--- a/src/storm/settings/modules/CoreSettings.cpp
+++ b/src/storm/settings/modules/CoreSettings.cpp
@@ -24,7 +24,6 @@ namespace storm {
             const std::string CoreSettings::dontFixDeadlockOptionShortName = "ndl";
             const std::string CoreSettings::eqSolverOptionName = "eqsolver";
             const std::string CoreSettings::lpSolverOptionName = "lpsolver";
-            const std::string CoreSettings::parameterLiftingOptionName = "parameterlifting";
             const std::string CoreSettings::smtSolverOptionName = "smtsolver";
             const std::string CoreSettings::statisticsOptionName = "statistics";
             const std::string CoreSettings::statisticsOptionShortName = "stats";
@@ -53,8 +52,6 @@ namespace storm {
                 this->addOption(storm::settings::OptionBuilder(moduleName, lpSolverOptionName, false, "Sets which LP solver is preferred.")
                                 .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of an LP solver.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(lpSolvers)).setDefaultValueString("glpk").build()).build());
                 
-                this->addOption(storm::settings::OptionBuilder(moduleName, parameterLiftingOptionName, false, "Sets whether parameter lifting is applied.").build());
-                
                 std::vector<std::string> smtSolvers = {"z3", "mathsat"};
                 this->addOption(storm::settings::OptionBuilder(moduleName, smtSolverOptionName, false, "Sets which SMT solver is preferred.")
                                 .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of an SMT solver.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(smtSolvers)).setDefaultValueString("z3").build()).build());
@@ -92,10 +89,6 @@ namespace storm {
                 return this->getOption(eqSolverOptionName).getHasOptionBeenSet();
             }
             
-            bool CoreSettings::isParameterLiftingSet() const {
-                return this->getOption(parameterLiftingOptionName).getHasOptionBeenSet();
-            }
-            
             storm::solver::LpSolverType CoreSettings::getLpSolver() const {
                 std::string lpSolverName = this->getOption(lpSolverOptionName).getArgumentByName("name").getValueAsString();
                 if (lpSolverName == "gurobi") {
diff --git a/src/storm/settings/modules/CoreSettings.h b/src/storm/settings/modules/CoreSettings.h
index 719449dd2..4f275b3d0 100644
--- a/src/storm/settings/modules/CoreSettings.h
+++ b/src/storm/settings/modules/CoreSettings.h
@@ -81,12 +81,6 @@ namespace storm {
                  */
                 bool isEquationSolverSet() const;
 
-                /*!
-                 * Retrieves whether parameter lifting should be applied.
-                 * @return True iff parameter lifting should be applied.
-                 */
-                bool isParameterLiftingSet() const;
-                
                 /*!
                  * Retrieves the selected LP solver.
                  *
@@ -150,7 +144,6 @@ namespace storm {
                 static const std::string dontFixDeadlockOptionShortName;
                 static const std::string eqSolverOptionName;
                 static const std::string lpSolverOptionName;
-                static const std::string parameterLiftingOptionName;
                 static const std::string smtSolverOptionName;
                 static const std::string statisticsOptionName;
                 static const std::string statisticsOptionShortName;
diff --git a/src/storm/settings/modules/ParametricSettings.cpp b/src/storm/settings/modules/ParametricSettings.cpp
deleted file mode 100644
index e7e764426..000000000
--- a/src/storm/settings/modules/ParametricSettings.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#include "storm/settings/modules/ParametricSettings.h"
-
-#include "storm/settings/Option.h"
-#include "storm/settings/OptionBuilder.h"
-#include "storm/settings/ArgumentBuilder.h"
-#include "storm/settings/Argument.h"
-
-#include "storm/utility/macros.h"
-#include "storm/exceptions/IllegalArgumentValueException.h"
-
-namespace storm {
-    namespace settings {
-        namespace modules {
-            
-            const std::string ParametricSettings::moduleName = "parametric";
-            const std::string ParametricSettings::encodeSmt2StrategyOptionName = "smt2strategy";
-            const std::string ParametricSettings::exportSmt2DestinationPathOptionName = "smt2path";
-            const std::string ParametricSettings::exportResultDestinationPathOptionName = "resultfile";
-            const std::string ParametricSettings::parameterSpaceOptionName = "parameterspace";
-            const std::string ParametricSettings::refinementThresholdOptionName = "refinementthreshold";
-            const std::string ParametricSettings::exactValidationOptionName = "exactvalidation";
-            const std::string ParametricSettings::derivativesOptionName = "derivatives";
-            
-            ParametricSettings::ParametricSettings() : ModuleSettings(moduleName) {
-                this->addOption(storm::settings::OptionBuilder(moduleName, encodeSmt2StrategyOptionName, true, "Set the smt2 encoding strategy.")
-                                .addArgument(storm::settings::ArgumentBuilder::createStringArgument("strategy", "the used strategy").build()).build());
-                this->addOption(storm::settings::OptionBuilder(moduleName, exportSmt2DestinationPathOptionName, true, "A path to a file where the result should be saved.")
-                                .addArgument(storm::settings::ArgumentBuilder::createStringArgument("path", "the location.").addValidatorString(ArgumentValidatorFactory::createWritableFileValidator()).build()).build());
-                this->addOption(storm::settings::OptionBuilder(moduleName, exportResultDestinationPathOptionName, true, "A path to a file where the smt2 encoding should be saved.")
-                                .addArgument(storm::settings::ArgumentBuilder::createStringArgument("path", "the location.").addValidatorString(ArgumentValidatorFactory::createWritableFileValidator()).build()).build());
-                this->addOption(storm::settings::OptionBuilder(moduleName, parameterSpaceOptionName, true, "Sets the considered parameter-space (i.e., the initial region) for parameter lifting.")
-                                .addArgument(storm::settings::ArgumentBuilder::createStringArgument("region", "The parameter-space (given in format a<=x<=b,c<=y<=d).").build()).build());
-                this->addOption(storm::settings::OptionBuilder(moduleName, refinementThresholdOptionName, true, "Parameter space refinement converges if the fraction of unknown area falls below this threshold.")
-                                .addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("threshold", "The threshold").setDefaultValueDouble(0.05).addValidatorDouble(storm::settings::ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0,1.0)).build()).build());
-                this->addOption(storm::settings::OptionBuilder(moduleName, exactValidationOptionName, true, "Sets whether numerical results from Parameter lifting should be validated with exact techniques.").build());
-                this->addOption(storm::settings::OptionBuilder(moduleName, derivativesOptionName, true, "Sets whether to generate the derivatives of the resulting rational function.").build());
-            }
-            
-            bool ParametricSettings::exportResultToFile() const {
-                return this->getOption(exportResultDestinationPathOptionName).getHasOptionBeenSet();
-            }
-            
-            std::string ParametricSettings::exportResultPath() const {
-                return this->getOption(exportResultDestinationPathOptionName).getArgumentByName("path").getValueAsString();
-            }
-            
-            bool ParametricSettings::isParameterSpaceSet() const {
-                return this->getOption(parameterSpaceOptionName).getHasOptionBeenSet();
-            }
-            
-            std::string ParametricSettings::getParameterSpace() const {
-                return this->getOption(parameterSpaceOptionName).getArgumentByName("region").getValueAsString();
-            }
-            
-            double ParametricSettings::getRefinementThreshold() const {
-                return this->getOption(refinementThresholdOptionName).getArgumentByName("threshold").getValueAsDouble();
-            }
-            
-            bool ParametricSettings::isExactValidationSet() const {
-                return this->getOption(exactValidationOptionName).getHasOptionBeenSet();
-            }
-            
-            bool ParametricSettings::exportToSmt2File() const {
-                return this->getOption(exportSmt2DestinationPathOptionName).getHasOptionBeenSet();
-            }
-            
-            std::string ParametricSettings::exportSmt2Path() const {
-                return this->getOption(exportSmt2DestinationPathOptionName).getArgumentByName("path").getValueAsString();
-            }
-            
-            ParametricSettings::Smt2EncodingStrategy ParametricSettings::smt2EncodingStrategy() const {
-                std::string strategy = this->getOption(encodeSmt2StrategyOptionName).getArgumentByName("strategy").getValueAsString();
-                
-                if(strategy == "fts") {
-                    return Smt2EncodingStrategy::FULL_TRANSITION_SYSTEM;
-                } else if(strategy == "rf") {
-                    return Smt2EncodingStrategy::RATIONAL_FUNCTION;
-                } else {
-                    STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown smt2encoding strategy '" << strategy << "'.");
-                }
-            }
-            
-            bool ParametricSettings::isDerivativesSet() const {
-                return this->getOption(derivativesOptionName).getHasOptionBeenSet();
-            }
-
-        } // namespace modules
-    } // namespace settings
-} // namespace storm
diff --git a/src/storm/settings/modules/ParametricSettings.h b/src/storm/settings/modules/ParametricSettings.h
deleted file mode 100644
index 54f2bbf86..000000000
--- a/src/storm/settings/modules/ParametricSettings.h
+++ /dev/null
@@ -1,104 +0,0 @@
-#ifndef STORM_SETTINGS_MODULES_PARAMETRICSETTINGS_H_
-#define STORM_SETTINGS_MODULES_PARAMETRICSETTINGS_H_
-
-#include "storm/settings/modules/ModuleSettings.h"
-
-namespace storm {
-    namespace settings {
-        namespace modules {
-
-            /*!
-             * This class represents the settings for parametric model checking.
-             */
-            class ParametricSettings : public ModuleSettings {
-            public:
-				/**
-				 * A type for saving the Smt2EncondingStrategy.
-				 * 
-				 * FULL_TRANSITION_SYSTEM: The transition system should be reduced only with very basic operations.
-				 * ONLY_SCC_ENTRY_STATES: Scc elimination should be performed, but no further reduction.
-				 * HIGH_INDEGREE:  State elimination but for states with a high indegree.
-				 * RATIONAL_FUNCTION: The smt file should contain only the rational function.
-				 */
-				enum class Smt2EncodingStrategy {FULL_TRANSITION_SYSTEM, ONLY_SCC_ENTRY_STATES, HIGH_INDEGREE, RATIONAL_FUNCTION};
-                
-                /*!
-                 * Creates a new set of parametric model checking settings.
-                 */
-                ParametricSettings();
-				
-				/**
-				 * Retrieves whether the model checking result should be exported to a file.
-                 * @return  True iff the result should be exported to a file.
-                 */
-				bool exportResultToFile() const;
-				
-				/**
-				 * The path to a file location which should contain the model checking result.
-                 * @return A path to a file location.
-                 */
-				std::string exportResultPath() const;
-				
-				/*!
-				 * Retrieves whether the parameter space was declared
-				 */
-				bool isParameterSpaceSet() const;
-				
-				/*!
-				 * Retrieves the given parameter spcae
-				 */
-				std::string getParameterSpace() const;
-				
-				/*!
-				 * Retrieves the threshold considered for iterative region refinement.
-				 * The refinement converges as soon as the fraction of unknown area falls below this threshold
-				 */
-				double getRefinementThreshold() const;
-				
-				/*!
-				 * Retrieves whether exact validation should be performed
-				 */
-				bool isExactValidationSet() const;
-				
-				/**
-				 * Retrieves whether the encoding of the transition system should be exported to a file. 
-				 * @return True iff the smt file should be encoded.
-				 */
-				bool exportToSmt2File() const;
-				
-				/**
-				 * The path to a file location which should contain the smt2 encoding.
-                 * @return A path to a file location.
-                 */
-				std::string exportSmt2Path() const;
-				
-				/**
-				 * Retrieves which encoding strategy should be used for generating the smt2 file.
-                 * @return The encoding strategy to be used.
-                 */
-				Smt2EncodingStrategy smt2EncodingStrategy() const;
-                
-                /*!
-                 * Retrieves whether or not derivatives of the resulting rational function are to be generated.
-                 *
-                 * @return True if the derivatives are to be generated.
-                 */
-                bool isDerivativesSet() const;
-				
-                const static std::string moduleName;
-                
-            private:
-				const static std::string encodeSmt2StrategyOptionName;
-				const static std::string exportSmt2DestinationPathOptionName;
-				const static std::string exportResultDestinationPathOptionName;
-				const static std::string parameterSpaceOptionName;
-				const static std::string refinementThresholdOptionName;
-				const static std::string exactValidationOptionName;
-                const static std::string derivativesOptionName;
-            };
-            
-        } // namespace modules
-    } // namespace settings
-} // namespace storm
-
-#endif /* STORM_SETTINGS_MODULES_PARAMETRICSETTINGS_H_ */
diff --git a/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.cpp b/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.cpp
index 0a1c03e4b..20357f400 100644
--- a/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.cpp
+++ b/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.cpp
@@ -14,72 +14,10 @@
 
 namespace storm {
     namespace transformer {
-        
-        template <typename ValueType, typename RewardModelType>
-        std::shared_ptr<storm::models::sparse::Model<ValueType>> transformContinuousToDiscreteModel(std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> markovModel, std::shared_ptr<storm::logic::Formula const>& formula) {
-            boost::optional<std::string> timeRewardModelName;
-            if (formula->isTimeOperatorFormula()) {
-                auto const& timeOpFormula = formula->asTimeOperatorFormula();
-                if (timeOpFormula.getSubformula().isReachabilityTimeFormula()) {
-                    auto reachabilityRewardFormula = std::make_shared<storm::logic::EventuallyFormula>(storm::logic::CloneVisitor().clone(timeOpFormula.getSubformula().asReachabilityTimeFormula().getSubformula()), storm::logic::FormulaContext::Reward);
-                    timeRewardModelName = "time";
-                    // make sure that the reward model name is not already in use
-                    while (markovModel->hasRewardModel(*timeRewardModelName)) *timeRewardModelName += "_";
-                    formula = std::make_shared<storm::logic::RewardOperatorFormula const>(reachabilityRewardFormula, timeRewardModelName, timeOpFormula.getOperatorInformation());
-                }
-            }
-        
-            if (markovModel->isOfType(storm::models::ModelType::Ctmc)) {
-                SparseCtmcToSparseDtmcTransformer<ValueType, RewardModelType> transformer;
-                if (transformer.transformationPreservesProperty(*formula)) {
-                    STORM_LOG_INFO("Transforming Ctmc to embedded Dtmc...");
-                    return transformer.translate(*markovModel->template as<storm::models::sparse::Ctmc<ValueType>>(), timeRewardModelName);
-                }
-            } else if (markovModel->isOfType(storm::models::ModelType::MarkovAutomaton)) {
-                SparseMaToSparseMdpTransformer<ValueType, RewardModelType> transformer;
-                if (transformer.transformationPreservesProperty(*formula)) {
-                    STORM_LOG_INFO("Transforming Markov automaton to embedded Mdp...");
-                    return transformer.translate(*markovModel->template as<storm::models::sparse::MarkovAutomaton<ValueType>>(), timeRewardModelName);
-                }
-            } else {
-                STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Model type " << markovModel->getType() << " not expected.");
-            }
-            return nullptr;
-        }
-        
-       template <typename ValueType, typename RewardModelType>
-        void transformContinuousToDiscreteModelInPlace(std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>>& markovModel, std::shared_ptr<storm::logic::Formula const>& formula) {
-            boost::optional<std::string> timeRewardModelName;
-            if (formula->isTimeOperatorFormula()) {
-                auto const& timeOpFormula = formula->asTimeOperatorFormula();
-                if (timeOpFormula.getSubformula().isReachabilityTimeFormula()) {
-                    auto reachabilityRewardFormula = std::make_shared<storm::logic::EventuallyFormula>(storm::logic::CloneVisitor().clone(timeOpFormula.getSubformula().asReachabilityTimeFormula().getSubformula()), storm::logic::FormulaContext::Reward);
-                    timeRewardModelName = "time";
-                    // make sure that the reward model name is not already in use
-                    while (markovModel->hasRewardModel(*timeRewardModelName)) *timeRewardModelName += "_";
-                    formula = std::make_shared<storm::logic::RewardOperatorFormula const>(reachabilityRewardFormula, timeRewardModelName, timeOpFormula.getOperatorInformation());
-                }
-            }
-        
-            if (markovModel->isOfType(storm::models::ModelType::Ctmc)) {
-                SparseCtmcToSparseDtmcTransformer<ValueType, RewardModelType> transformer;
-                if (transformer.transformationPreservesProperty(*formula)) {
-                    STORM_LOG_INFO("Transforming Ctmc to embedded Dtmc...");
-                    markovModel = transformer.translate(std::move(*markovModel->template as<storm::models::sparse::Ctmc<ValueType>>()), timeRewardModelName);
-                }
-            } else if (markovModel->isOfType(storm::models::ModelType::MarkovAutomaton)) {
-                SparseMaToSparseMdpTransformer<ValueType, RewardModelType> transformer;
-                if (transformer.transformationPreservesProperty(*formula)) {
-                    STORM_LOG_INFO("Transforming Markov automaton to embedded Mdp...");
-                    markovModel = transformer.translate(std::move(*markovModel->template as<storm::models::sparse::MarkovAutomaton<ValueType>>()), timeRewardModelName);
-                }
-            } else {
-                STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Model type " << markovModel->getType() << " not expected.");
-            }
-        }
+
         
        template <typename ValueType, typename RewardModelType>
-        std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> SparseCtmcToSparseDtmcTransformer<ValueType, RewardModelType>::translate(storm::models::sparse::Ctmc<ValueType, RewardModelType> const& ctmc, boost::optional<std::string> const& timeRewardModelName) {
+        std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> ContinuousToDiscreteTimeModelTransformer<ValueType, RewardModelType>::transform(storm::models::sparse::Ctmc<ValueType, RewardModelType> const& ctmc, boost::optional<std::string> const& timeRewardModelName) {
             // Init the dtmc components
             storm::storage::sparse::ModelComponents<ValueType, RewardModelType> dtmcComponents(ctmc.getTransitionMatrix(), ctmc.getStateLabeling(), ctmc.getRewardModels());
             dtmcComponents.choiceLabeling = ctmc.getOptionalChoiceLabeling();
@@ -113,7 +51,7 @@ namespace storm {
         }
        
         template <typename ValueType, typename RewardModelType>
-        std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> SparseCtmcToSparseDtmcTransformer<ValueType, RewardModelType>::translate(storm::models::sparse::Ctmc<ValueType, RewardModelType>&& ctmc, boost::optional<std::string> const& timeRewardModelName) {
+        std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> ContinuousToDiscreteTimeModelTransformer<ValueType, RewardModelType>::transform(storm::models::sparse::Ctmc<ValueType, RewardModelType>&& ctmc, boost::optional<std::string> const& timeRewardModelName) {
             // Init the dtmc components
             storm::storage::sparse::ModelComponents<ValueType, RewardModelType> dtmcComponents(std::move(ctmc.getTransitionMatrix()), std::move(ctmc.getStateLabeling()), std::move(ctmc.getRewardModels()));
             dtmcComponents.choiceLabeling = std::move(ctmc.getOptionalChoiceLabeling());
@@ -144,7 +82,7 @@ namespace storm {
         }
        
         template <typename ValueType, typename RewardModelType>
-        bool SparseCtmcToSparseDtmcTransformer<ValueType, RewardModelType>::transformationPreservesProperty(storm::logic::Formula const& formula) {
+        bool ContinuousToDiscreteTimeModelTransformer<ValueType, RewardModelType>::preservesFormula(storm::logic::Formula const& formula) {
             storm::logic::FragmentSpecification fragment = storm::logic::propositional();
             fragment.setProbabilityOperatorsAllowed(true);
             fragment.setGloballyFormulasAllowed(true);
@@ -158,7 +96,7 @@ namespace storm {
         
   
         template <typename ValueType, typename RewardModelType>
-        std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> SparseMaToSparseMdpTransformer<ValueType, RewardModelType>::translate(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType> const& ma, boost::optional<std::string> const& timeRewardModelName) {
+        std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> ContinuousToDiscreteTimeModelTransformer<ValueType, RewardModelType>::transform(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType> const& ma, boost::optional<std::string> const& timeRewardModelName) {
             STORM_LOG_THROW(ma.isClosed(), storm::exceptions::InvalidArgumentException, "Transformation of MA to its underlying MDP is only possible for closed MAs");
 
             // Init the mdp components
@@ -174,8 +112,12 @@ namespace storm {
             for (auto& rewardModel : mdpComponents.rewardModels) {
                 if (rewardModel.second.hasStateRewards()) {
                     auto& stateRewards = rewardModel.second.getStateRewardVector();
-                    for (auto state : ma.getMarkovianStates()) {
-                        stateRewards[state] /= exitRates[state];
+                    for (uint_fast64_t state = 0; state < stateRewards.size(); ++state) {
+                        if (ma.getMarkovianStates().get(state)) {
+                            stateRewards[state] /= exitRates[state];
+                        } else {
+                            stateRewards[state] = storm::utility::zero<ValueType>();
+                        }
                     }
                 }
             }
@@ -195,7 +137,7 @@ namespace storm {
         }
 
         template <typename ValueType, typename RewardModelType>
-        std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> SparseMaToSparseMdpTransformer<ValueType, RewardModelType>::translate(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType>&& ma, boost::optional<std::string> const& timeRewardModelName) {
+        std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> ContinuousToDiscreteTimeModelTransformer<ValueType, RewardModelType>::transform(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType>&& ma, boost::optional<std::string> const& timeRewardModelName) {
             STORM_LOG_THROW(ma.isClosed(), storm::exceptions::InvalidArgumentException, "Transformation of MA to its underlying MDP is only possible for closed MAs");
             std::vector<ValueType>& exitRates = ma.getExitRates();
 
@@ -211,8 +153,12 @@ namespace storm {
             for (auto& rewardModel : mdpComponents.rewardModels) {
                 if (rewardModel.second.hasStateRewards()) {
                     auto& stateRewards = rewardModel.second.getStateRewardVector();
-                    for (auto state : ma.getMarkovianStates()) {
-                        stateRewards[state] /= exitRates[state];
+                    for (uint_fast64_t state = 0; state < stateRewards.size(); ++state) {
+                        if (ma.getMarkovianStates().get(state)) {
+                            stateRewards[state] /= exitRates[state];
+                        } else {
+                            stateRewards[state] = storm::utility::zero<ValueType>();
+                        }
                     }
                 }
             }
@@ -231,31 +177,8 @@ namespace storm {
             return std::make_shared<storm::models::sparse::Mdp<ValueType, RewardModelType>>(std::move(mdpComponents));
         }
         
-        template <typename ValueType, typename RewardModelType>
-        bool SparseMaToSparseMdpTransformer<ValueType, RewardModelType>::transformationPreservesProperty(storm::logic::Formula const& formula) {
-            storm::logic::FragmentSpecification fragment = storm::logic::propositional();
-            fragment.setProbabilityOperatorsAllowed(true);
-            fragment.setGloballyFormulasAllowed(true);
-            fragment.setReachabilityProbabilityFormulasAllowed(true);
-            fragment.setNextFormulasAllowed(true);
-            fragment.setUntilFormulasAllowed(true);
-            fragment.setRewardOperatorsAllowed(true);
-            fragment.setReachabilityRewardFormulasAllowed(true);
-            
-            return formula.isInFragment(fragment);
-        }
-    
-        template std::shared_ptr<storm::models::sparse::Model<double>> transformContinuousToDiscreteModel(std::shared_ptr<storm::models::sparse::Model<double>> markovModel, std::shared_ptr<storm::logic::Formula const>& formula);
-        template std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> transformContinuousToDiscreteModel(std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> markovModel, std::shared_ptr<storm::logic::Formula const>& formula);
-        template std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> transformContinuousToDiscreteModel(std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> markovModel, std::shared_ptr<storm::logic::Formula const>& formula);
-        template void transformContinuousToDiscreteModelInPlace<double>(std::shared_ptr<storm::models::sparse::Model<double>>& markovModel, std::shared_ptr<storm::logic::Formula const>& formula);
-        template void transformContinuousToDiscreteModelInPlace<storm::RationalNumber>(std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>>& markovModel, std::shared_ptr<storm::logic::Formula const>& formula);
-        template void transformContinuousToDiscreteModelInPlace<storm::RationalFunction>(std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>>& markovModel, std::shared_ptr<storm::logic::Formula const>& formula);
-        template class SparseCtmcToSparseDtmcTransformer<double>;
-        template class SparseCtmcToSparseDtmcTransformer<storm::RationalNumber>;
-        template class SparseCtmcToSparseDtmcTransformer<storm::RationalFunction>;
-        template class SparseMaToSparseMdpTransformer<double>;
-        template class SparseMaToSparseMdpTransformer<storm::RationalNumber>;
-        template class SparseMaToSparseMdpTransformer<storm::RationalFunction>;
+        template class ContinuousToDiscreteTimeModelTransformer<double>;
+        template class ContinuousToDiscreteTimeModelTransformer<storm::RationalNumber>;
+        template class ContinuousToDiscreteTimeModelTransformer<storm::RationalFunction>;
     }
 }
diff --git a/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.h b/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.h
index cea1bf367..d26b96c1f 100644
--- a/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.h
+++ b/src/storm/transformer/ContinuousToDiscreteTimeModelTransformer.h
@@ -12,41 +12,23 @@
 namespace storm {
     namespace transformer {
 
-        
-        // Transforms the given continuous model to a discrete time model.
-        // If such a transformation does not preserve the given formula, the transformation does not take place and the original model is returned
-        // Moreover, the given formula might be changed (e.g. TimeOperatorFormulas become RewardOperatorFormulas).
-        template <typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>>
-        std::shared_ptr<storm::models::sparse::Model<ValueType>> transformContinuousToDiscreteModel(std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> markovModel, std::shared_ptr<storm::logic::Formula const>& formula);
-        
-        // Transforms the given continuous model to a discrete time model IN PLACE (i.e., the continuous model will be invalidated).
-        // If such a transformation does not preserve the given formula, the transformation does not take place.
-        // Moreover, the given formula might be changed (e.g. TimeOperatorFormulas become RewardOperatorFormulas).
         template <typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>>
-        void transformContinuousToDiscreteModelInPlace(std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>>& markovModel, std::shared_ptr<storm::logic::Formula const>& formula);
-        
-        template <typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>>
-        class SparseCtmcToSparseDtmcTransformer {
+        class ContinuousToDiscreteTimeModelTransformer {
         public:
+
+            // If this method returns true, the given formula is preserced by the transformation
+            static bool preservesFormula(storm::logic::Formula const& formula);
+        
             // Transforms the given CTMC to its underlying (aka embedded) DTMC.
             // A reward model for time is added if a corresponding reward model name is given
-            static std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> translate(storm::models::sparse::Ctmc<ValueType, RewardModelType> const& ctmc, boost::optional<std::string> const& timeRewardModelName = boost::none);
-            static std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> translate(storm::models::sparse::Ctmc<ValueType, RewardModelType>&& ctmc, boost::optional<std::string> const& timeRewardModelName = boost::none);
+            static std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> transform(storm::models::sparse::Ctmc<ValueType, RewardModelType> const& ctmc, boost::optional<std::string> const& timeRewardModelName = boost::none);
+            static std::shared_ptr<storm::models::sparse::Dtmc<ValueType, RewardModelType>> transform(storm::models::sparse::Ctmc<ValueType, RewardModelType>&& ctmc, boost::optional<std::string> const& timeRewardModelName = boost::none);
             
-            // If this method returns true, the given formula is preserced by the transformation
-            static bool transformationPreservesProperty(storm::logic::Formula const& formula);
-        };
-        
-        template <typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>>
-        class SparseMaToSparseMdpTransformer {
-        public:
             // Transforms the given MA to its underlying (aka embedded) MDP.
             // A reward model for time is added if a corresponding reward model name is given
-            static std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> translate(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType> const& ma, boost::optional<std::string> const& timeRewardModelName = boost::none);
-            static std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> translate(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType>&& ma, boost::optional<std::string> const& timeRewardModelName = boost::none);
+            static std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> transform(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType> const& ma, boost::optional<std::string> const& timeRewardModelName = boost::none);
+            static std::shared_ptr<storm::models::sparse::Mdp<ValueType, RewardModelType>> transform(storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType>&& ma, boost::optional<std::string> const& timeRewardModelName = boost::none);
             
-            // If this method returns true, the given formula is preserved by the transformation
-            static bool transformationPreservesProperty(storm::logic::Formula const& formula);
         };
     }
 }
diff --git a/src/storm/transformer/SymbolicToSparseTransformer.cpp b/src/storm/transformer/SymbolicToSparseTransformer.cpp
index ec026968f..69b02acfb 100644
--- a/src/storm/transformer/SymbolicToSparseTransformer.cpp
+++ b/src/storm/transformer/SymbolicToSparseTransformer.cpp
@@ -11,22 +11,6 @@
 namespace storm {
     namespace transformer {
 
-        template<storm::dd::DdType Type, typename ValueType>
-        std::shared_ptr<storm::models::sparse::Model<ValueType>> transformSymbolicToSparseModel(std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> const& symbolicModel) {
-            switch (symbolicModel->getType()) {
-                case storm::models::ModelType::Dtmc:
-                    return SymbolicDtmcToSparseDtmcTransformer<Type, ValueType>().translate(*symbolicModel->template as<storm::models::symbolic::Dtmc<Type, ValueType>>());
-                case storm::models::ModelType::Mdp:
-                    return SymbolicMdpToSparseMdpTransformer<Type, ValueType>::translate(*symbolicModel->template as<storm::models::symbolic::Mdp<Type, ValueType>>());
-                case storm::models::ModelType::Ctmc:
-                    return SymbolicCtmcToSparseCtmcTransformer<Type, ValueType>::translate(*symbolicModel->template as<storm::models::symbolic::Ctmc<Type, ValueType>>());
-                default:
-                    STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Transformation of symbolic " << symbolicModel->getType() << " to sparse model is not implemented.");
-            }
-            return nullptr;
-        }
-        
-
         template<storm::dd::DdType Type, typename ValueType>
         std::shared_ptr<storm::models::sparse::Dtmc<ValueType>> SymbolicDtmcToSparseDtmcTransformer<Type, ValueType>::translate(storm::models::symbolic::Dtmc<Type, ValueType> const& symbolicDtmc) {
             this->odd = symbolicDtmc.getReachableStates().createOdd();
@@ -121,11 +105,6 @@ namespace storm {
             return std::make_shared<storm::models::sparse::Ctmc<ValueType>>(transitionMatrix, labelling, rewardModels);
         }
 
-        template std::shared_ptr<storm::models::sparse::Model<double>> transformSymbolicToSparseModel<storm::dd::DdType::CUDD, double>(std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::CUDD, double>> const& symbolicModel);
-        template std::shared_ptr<storm::models::sparse::Model<double>> transformSymbolicToSparseModel<storm::dd::DdType::Sylvan, double>(std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::Sylvan, double>> const& symbolicModel);
-        template std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> transformSymbolicToSparseModel<storm::dd::DdType::Sylvan, storm::RationalNumber>(std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::Sylvan, storm::RationalNumber>> const& symbolicModel);
-        template std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> transformSymbolicToSparseModel<storm::dd::DdType::Sylvan, storm::RationalFunction>(std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::Sylvan, storm::RationalFunction>> const& symbolicModel);
-        
         template class SymbolicDtmcToSparseDtmcTransformer<storm::dd::DdType::CUDD, double>;
         template class SymbolicDtmcToSparseDtmcTransformer<storm::dd::DdType::Sylvan, double>;
         template class SymbolicDtmcToSparseDtmcTransformer<storm::dd::DdType::Sylvan, storm::RationalNumber>;
diff --git a/src/storm/transformer/SymbolicToSparseTransformer.h b/src/storm/transformer/SymbolicToSparseTransformer.h
index b55eb7ea9..5f4bed6c4 100644
--- a/src/storm/transformer/SymbolicToSparseTransformer.h
+++ b/src/storm/transformer/SymbolicToSparseTransformer.h
@@ -12,9 +12,6 @@
 namespace storm {
     namespace transformer {
 
-        template<storm::dd::DdType Type, typename ValueType>
-        std::shared_ptr<storm::models::sparse::Model<ValueType>> transformSymbolicToSparseModel(std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> const& symbolicModel);
-        
         template<storm::dd::DdType Type, typename ValueType>
         class SymbolicDtmcToSparseDtmcTransformer {
         public:
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
index d6dbe8207..d870d2b21 100644
--- a/src/test/CMakeLists.txt
+++ b/src/test/CMakeLists.txt
@@ -1,23 +1,2 @@
-# Base path for test files
-set(STORM_TESTS_BASE_PATH "${PROJECT_SOURCE_DIR}/src/test")
-
-# Test Sources
-file(GLOB_RECURSE ALL_FILES ${STORM_TESTS_BASE_PATH}/*.h ${STORM_TESTS_BASE_PATH}/*.cpp)
-
-register_source_groups_from_filestructure("${ALL_FILES}" test)
-
-# Note that the tests also need the source files, except for the main file
-include_directories(${GTEST_INCLUDE_DIR})
-
-foreach (testsuite abstraction adapter builder logic modelchecker parser permissiveschedulers solver storage transformer utility)
-
-	  file(GLOB_RECURSE TEST_${testsuite}_FILES ${STORM_TESTS_BASE_PATH}/${testsuite}/*.h ${STORM_TESTS_BASE_PATH}/${testsuite}/*.cpp)
-      add_executable (test-${testsuite} ${TEST_${testsuite}_FILES} ${STORM_TESTS_BASE_PATH}/storm-test.cpp)
-	  target_link_libraries(test-${testsuite} storm)
-	  target_link_libraries(test-${testsuite} ${STORM_TEST_LINK_LIBRARIES})
-
-	  add_dependencies(test-${testsuite} test-resources)
-	  add_test(NAME run-test-${testsuite} COMMAND $<TARGET_FILE:test-${testsuite}>)
-      add_dependencies(tests test-${testsuite})
-	
-endforeach ()
+add_subdirectory(storm)
+add_subdirectory(storm-pars)
\ No newline at end of file
diff --git a/src/test/modelchecker/SparseDtmcParameterLiftingTest.cpp b/src/test/modelchecker/SparseDtmcParameterLiftingTest.cpp
deleted file mode 100644
index e4fa1d161..000000000
--- a/src/test/modelchecker/SparseDtmcParameterLiftingTest.cpp
+++ /dev/null
@@ -1,385 +0,0 @@
-#include "gtest/gtest.h"
-#include "storm-config.h"
-
-#ifdef STORM_HAVE_CARL
-
-#include "storm/adapters/RationalFunctionAdapter.h"
-
-#include "storm/modelchecker/parametric/SparseDtmcRegionChecker.h"
-#include "storm/storage/ParameterRegion.h"
-
-#include "storm/api/storm.h"
-
-TEST(SparseDtmcParameterLiftingTest, Brp_Prob) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
-    std::string formulaAsString = "P<=0.84 [F s=5 ]";
-    std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
-
-    // Program and formula
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pL<=0.9,0.75<=pK<=0.95", modelParameters);
-    auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.4<=pL<=0.65,0.75<=pK<=0.95", modelParameters);
-    auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pL<=0.73,0.2<=pK<=0.715", modelParameters);
-
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseDtmcParameterLiftingTest, Brp_Rew) {
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm";
-    std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]";
-    std::string constantsAsString = "pL=0.9,TOAck=0.5";
-    carl::VariablePool::getInstance().clear();
-    
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters);
-    auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters);
-    auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters);
-
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseDtmcParameterLiftingTest, Brp_Rew_Bounded) {
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm";
-    std::string formulaAsString = "R>2.5 [ C<=300]";
-    std::string constantsAsString = "pL=0.9,TOAck=0.5";
-    carl::VariablePool::getInstance().clear();
-    
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters);
-    auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters);
-    auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters);
-
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseDtmcParameterLiftingTest, Brp_Prob_exactValidation) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
-    std::string formulaAsString = "P<=0.84 [F s=5 ]";
-    std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
-
-    // Program and formula
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    auto settings = regionChecker.getSettings();
-    settings.applyExactValidation = true;
-    regionChecker.setSettings(settings);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pL<=0.9,0.75<=pK<=0.95", modelParameters);
-    auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.4<=pL<=0.65,0.75<=pK<=0.95", modelParameters);
-    auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pL<=0.73,0.2<=pK<=0.715", modelParameters);
-
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseDtmcParameterLiftingTest, Brp_Rew_exactValidation) {
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm";
-    std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]";
-    std::string constantsAsString = "pL=0.9,TOAck=0.5";
-    carl::VariablePool::getInstance().clear();
-    
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    auto settings = regionChecker.getSettings();
-    settings.applyExactValidation = true;
-    regionChecker.setSettings(settings);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters);
-    auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters);
-    auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters);
-
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseDtmcParameterLiftingTest, Brp_Rew_Bounded_exactValidation) {
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm";
-    std::string formulaAsString = "R>2.5 [ C<=300]";
-    std::string constantsAsString = "pL=0.9,TOAck=0.5";
-    carl::VariablePool::getInstance().clear();
-    
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    auto settings = regionChecker.getSettings();
-    settings.applyExactValidation = true;
-    regionChecker.setSettings(settings);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters);
-    auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters);
-    auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters);
-
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseDtmcParameterLiftingTest, Brp_Rew_Infty) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm";
-    std::string formulaAsString = "R>2.5 [F (s=0&srep=3) ]";
-    std::string constantsAsString = "";
-    carl::VariablePool::getInstance().clear();
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters);
-    
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseDtmcParameterLiftingTest, Brp_Rew_4Par) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm";
-    std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]";
-    std::string constantsAsString = ""; //!! this model will have 4 parameters
-    carl::VariablePool::getInstance().clear();
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters);
-    auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.7,0.2<=pL<=0.8,0.15<=TOMsg<=0.65,0.3<=TOAck<=0.9", modelParameters);
-    auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.4,0.2<=pL<=0.3,0.15<=TOMsg<=0.3,0.1<=TOAck<=0.2", modelParameters);
-
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseDtmcParameterLiftingTest, Crowds_Prob) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm";
-    std::string formulaAsString = "P<0.5 [F \"observe0Greater1\" ]";
-    std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
-    carl::VariablePool::getInstance().clear();
-
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-   
-    storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=PF<=0.75,0.15<=badC<=0.2", modelParameters);
-    auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.75<=PF<=0.8,0.2<=badC<=0.3", modelParameters);
-    auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.8<=PF<=0.95,0.2<=badC<=0.2", modelParameters);
-    auto allVioHardRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.8<=PF<=0.95,0.2<=badC<=0.9", modelParameters);
-
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::CenterViolated, regionChecker.analyzeRegion(allVioHardRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseDtmcParameterLiftingTest, Crowds_Prob_stepBounded) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm";
-    std::string formulaAsString = "P<0.5 [F<=300 \"observe0Greater1\" ]";
-    std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
-    carl::VariablePool::getInstance().clear();
-
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-   
-    storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=PF<=0.75,0.15<=badC<=0.2", modelParameters);
-    auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.75<=PF<=0.8,0.2<=badC<=0.3", modelParameters);
-    auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.8<=PF<=0.95,0.2<=badC<=0.2", modelParameters);
-    auto allVioHardRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.8<=PF<=0.95,0.2<=badC<=0.9", modelParameters);
-
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::CenterViolated, regionChecker.analyzeRegion(allVioHardRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseDtmcParameterLiftingTest, Crowds_Prob_1Par) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm";
-    std::string formulaAsString = "P>0.75 [F \"observe0Greater1\" ]";
-    std::string constantsAsString = "badC=0.3"; //e.g. pL=0.9,TOACK=0.5
-    carl::VariablePool::getInstance().clear();
-
-    
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.9<=PF<=0.99", modelParameters);
-    auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.8<=PF<=0.9", modelParameters);
-    auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.01<=PF<=0.8", modelParameters);
-
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseDtmcParameterLiftingTest, Crowds_Prob_Const) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm";
-    std::string formulaAsString = "P>0.6 [F \"observe0Greater1\" ]";
-    std::string constantsAsString = "PF=0.9,badC=0.2";
-    carl::VariablePool::getInstance().clear();
-    
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseDtmcRegionChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("", modelParameters);
-    
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-
-    carl::VariablePool::getInstance().clear();
-}
-
-#endif
diff --git a/src/test/modelchecker/SparseMdpParameterLiftingTest.cpp b/src/test/modelchecker/SparseMdpParameterLiftingTest.cpp
deleted file mode 100644
index b51b33df0..000000000
--- a/src/test/modelchecker/SparseMdpParameterLiftingTest.cpp
+++ /dev/null
@@ -1,313 +0,0 @@
-#include "gtest/gtest.h"
-#include "storm-config.h"
-
-#ifdef STORM_HAVE_CARL
-
-#include "storm/adapters/RationalFunctionAdapter.h"
-
-#include "storm/modelchecker/parametric/SparseMdpRegionChecker.h"
-#include "storm/storage/ParameterRegion.h"
-
-#include "storm/api/storm.h"
-
-TEST(SparseMdpParameterLiftingTest, two_dice_Prob) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm";
-    std::string formulaFile = "P<=0.17 [ F \"doubles\" ]";
-    
-    carl::VariablePool::getInstance().clear();
-
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program));
-    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-    auto allSatRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters);
-    auto exBothRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters);
-    auto allVioRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters);
-
-    
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseMdpParameterLiftingTest, two_dice_Prob_bounded) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm";
-    std::string formulaFile = "P<=0.17 [ F<100 \"doubles\" ]";
-    
-    carl::VariablePool::getInstance().clear();
-
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program));
-    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-    auto allSatRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters);
-    auto exBothRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters);
-    auto allVioRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters);
-
-    
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseMdpParameterLiftingTest, two_dice_Prob_exactValidation) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm";
-    std::string formulaFile = "P<=0.17 [ F \"doubles\" ]";
-    
-    carl::VariablePool::getInstance().clear();
-
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program));
-    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-    auto allSatRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters);
-    auto exBothRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters);
-    auto allVioRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters);
-
-    
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseMdpParameterLiftingTest, two_dice_Prob_bounded_exactValidation) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm";
-    std::string formulaFile = "P<=0.17 [ F<100 \"doubles\" ]";
-    
-    carl::VariablePool::getInstance().clear();
-
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program));
-    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-    auto allSatRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters);
-    auto exBothRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters);
-    auto allVioRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters);
-
-    
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseMdpParameterLiftingTest, coin_Prob) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/coin2_2.nm";
-    std::string formulaAsString = "P>0.25 [F \"finished\"&\"all_coins_equal_1\" ]";
-    
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-    //start testing
-    auto allSatRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.3<=p1<=0.45,0.2<=p2<=0.54", modelParameters);
-    auto exBothRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.4<=p1<=0.65,0.5<=p2<=0.7", modelParameters);
-    auto allVioRegion = storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.4<=p1<=0.7,0.55<=p2<=0.6", modelParameters);
-        
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseMdpParameterLiftingTest, brp_Prop) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm";
-    std::string formulaAsString = "P<=0.84 [ F (s=5 & T) ]";
-    std::string constantsAsString = "TOMsg=0.0,TOAck=0.0";
-
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pL<=0.9,0.75<=pK<=0.95", modelParameters);
-    auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.4<=pL<=0.65,0.75<=pK<=0.95", modelParameters);
-    auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pL<=0.73,0.2<=pK<=0.715", modelParameters);
-        
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseMdpParameterLiftingTest, brp_Rew) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm";
-    std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]";
-    std::string constantsAsString = "pL=0.9,TOAck=0.5";
-
-
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-   //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters);
-    auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters);
-    auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters);
-
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseMdpParameterLiftingTest, brp_Rew_bounded) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm";
-    std::string formulaAsString = "R>2.5 [ C<=300 ]";
-    std::string constantsAsString = "pL=0.9,TOAck=0.5";
-
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-   //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters);
-    auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters);
-    auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters);
-
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-
-    carl::VariablePool::getInstance().clear();
-}
-
-
-TEST(SparseMdpParameterLiftingTest, Brp_Rew_Infty) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm";
-    std::string formulaAsString = "R>2.5 [F (s=0&srep=3) ]";
-    std::string constantsAsString = "";
-    carl::VariablePool::getInstance().clear();
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters);
-    
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-
-    carl::VariablePool::getInstance().clear();
-}
-
-TEST(SparseMdpParameterLiftingTest, Brp_Rew_4Par) {
-    
-    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm";
-    std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]";
-    std::string constantsAsString = ""; //!! this model will have 4 parameters
-    carl::VariablePool::getInstance().clear();
-    storm::prism::Program program = storm::api::parseProgram(programFile);
-    program = storm::utility::prism::preprocess(program, constantsAsString);
-    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
-    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
-    
-    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
-    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
-    modelParameters.insert(rewParameters.begin(), rewParameters.end());
-    
-    storm::modelchecker::parametric::SparseMdpRegionChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double, storm::RationalNumber> regionChecker(*model);
-    regionChecker.specifyFormula(storm::modelchecker::CheckTask<storm::logic::Formula, storm::RationalFunction>(*formulas[0], true));
-    
-    //start testing
-    auto allSatRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters);
-    auto exBothRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.7,0.2<=pL<=0.8,0.15<=TOMsg<=0.65,0.3<=TOAck<=0.9", modelParameters);
-    auto allVioRegion=storm::storage::ParameterRegion<storm::RationalFunction>::parseRegion("0.1<=pK<=0.4,0.2<=pL<=0.3,0.15<=TOMsg<=0.3,0.1<=TOAck<=0.2", modelParameters);
-
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllSat, regionChecker.analyzeRegion(allSatRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::ExistsBoth, regionChecker.analyzeRegion(exBothRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    EXPECT_EQ(storm::modelchecker::parametric::RegionCheckResult::AllViolated, regionChecker.analyzeRegion(allVioRegion, storm::modelchecker::parametric::RegionCheckResult::Unknown, true));
-    
-    carl::VariablePool::getInstance().clear();
-}
-
-
-
-
-
-#endif
diff --git a/src/test/storm-pars/CMakeLists.txt b/src/test/storm-pars/CMakeLists.txt
new file mode 100644
index 000000000..0f2793553
--- /dev/null
+++ b/src/test/storm-pars/CMakeLists.txt
@@ -0,0 +1,23 @@
+# Base path for test files
+set(STORM_TESTS_BASE_PATH "${PROJECT_SOURCE_DIR}/src/test/storm-pars")
+
+# Test Sources
+file(GLOB_RECURSE ALL_FILES ${STORM_TESTS_BASE_PATH}/*.h ${STORM_TESTS_BASE_PATH}/*.cpp)
+
+register_source_groups_from_filestructure("${ALL_FILES}" test)
+
+# Note that the tests also need the source files, except for the main file
+include_directories(${GTEST_INCLUDE_DIR})
+
+foreach (testsuite modelchecker utility)
+
+	  file(GLOB_RECURSE TEST_${testsuite}_FILES ${STORM_TESTS_BASE_PATH}/${testsuite}/*.h ${STORM_TESTS_BASE_PATH}/${testsuite}/*.cpp)
+      add_executable (test-pars-${testsuite} ${TEST_${testsuite}_FILES} ${STORM_TESTS_BASE_PATH}/storm-test.cpp)
+	  target_link_libraries(test-pars-${testsuite} storm-pars)
+	  target_link_libraries(test-pars-${testsuite} ${STORM_TEST_LINK_LIBRARIES})
+
+	  add_dependencies(test-pars-${testsuite} test-resources)
+	  add_test(NAME run-test-pars-${testsuite} COMMAND $<TARGET_FILE:test-pars-${testsuite}>)
+      add_dependencies(tests test-pars-${testsuite})
+	
+endforeach ()
diff --git a/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp b/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp
new file mode 100644
index 000000000..31def397a
--- /dev/null
+++ b/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp
@@ -0,0 +1,362 @@
+#include "gtest/gtest.h"
+#include "storm-config.h"
+
+#ifdef STORM_HAVE_CARL
+
+#include "storm/adapters/RationalFunctionAdapter.h"
+
+#include "storm-pars/api/storm-pars.h"
+#include "storm/api/storm.h"
+
+TEST(SparseDtmcParameterLiftingTest, Brp_Prob) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
+    std::string formulaAsString = "P<=0.84 [F s=5 ]";
+    std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
+
+    // Program and formula
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pL<=0.9,0.75<=pK<=0.95", modelParameters);
+    auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.4<=pL<=0.65,0.75<=pK<=0.95", modelParameters);
+    auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.73,0.2<=pK<=0.715", modelParameters);
+
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseDtmcParameterLiftingTest, Brp_Rew) {
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm";
+    std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]";
+    std::string constantsAsString = "pL=0.9,TOAck=0.5";
+    carl::VariablePool::getInstance().clear();
+    
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters);
+    auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters);
+    auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters);
+
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+    
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseDtmcParameterLiftingTest, Brp_Rew_Bounded) {
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm";
+    std::string formulaAsString = "R>2.5 [ C<=300]";
+    std::string constantsAsString = "pL=0.9,TOAck=0.5";
+    carl::VariablePool::getInstance().clear();
+    
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters);
+    auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters);
+    auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters);
+
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+    
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseDtmcParameterLiftingTest, Brp_Prob_exactValidation) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
+    std::string formulaAsString = "P<=0.84 [F s=5 ]";
+    std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
+
+    // Program and formula
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
+    
+    auto regionChecker = storm::api::initializeValidatingRegionModelChecker<storm::RationalFunction, double, storm::RationalNumber>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pL<=0.9,0.75<=pK<=0.95", modelParameters);
+    auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.4<=pL<=0.65,0.75<=pK<=0.95", modelParameters);
+    auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.73,0.2<=pK<=0.715", modelParameters);
+
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseDtmcParameterLiftingTest, Brp_Rew_exactValidation) {
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm";
+    std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]";
+    std::string constantsAsString = "pL=0.9,TOAck=0.5";
+    carl::VariablePool::getInstance().clear();
+    
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeValidatingRegionModelChecker<storm::RationalFunction, double, storm::RationalNumber>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters);
+    auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters);
+    auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters);
+
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+    
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseDtmcParameterLiftingTest, Brp_Rew_Bounded_exactValidation) {
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm";
+    std::string formulaAsString = "R>2.5 [ C<=300]";
+    std::string constantsAsString = "pL=0.9,TOAck=0.5";
+    carl::VariablePool::getInstance().clear();
+    
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeValidatingRegionModelChecker<storm::RationalFunction, double, storm::RationalNumber>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters);
+    auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters);
+    auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters);
+
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+    
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseDtmcParameterLiftingTest, Brp_Rew_Infty) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm";
+    std::string formulaAsString = "R>2.5 [F (s=0&srep=3) ]";
+    std::string constantsAsString = "";
+    carl::VariablePool::getInstance().clear();
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters);
+    
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseDtmcParameterLiftingTest, Brp_Rew_4Par) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp_rewards16_2.pm";
+    std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]";
+    std::string constantsAsString = ""; //!! this model will have 4 parameters
+    carl::VariablePool::getInstance().clear();
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters);
+    auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.7,0.2<=pL<=0.8,0.15<=TOMsg<=0.65,0.3<=TOAck<=0.9", modelParameters);
+    auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.4,0.2<=pL<=0.3,0.15<=TOMsg<=0.3,0.1<=TOAck<=0.2", modelParameters);
+
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+    
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseDtmcParameterLiftingTest, Crowds_Prob) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm";
+    std::string formulaAsString = "P<0.5 [F \"observe0Greater1\" ]";
+    std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
+    carl::VariablePool::getInstance().clear();
+
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+   
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=PF<=0.75,0.15<=badC<=0.2", modelParameters);
+    auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.75<=PF<=0.8,0.2<=badC<=0.3", modelParameters);
+    auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.8<=PF<=0.95,0.2<=badC<=0.2", modelParameters);
+    auto allVioHardRegion=storm::api::parseRegion<storm::RationalFunction>("0.8<=PF<=0.95,0.2<=badC<=0.9", modelParameters);
+
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::CenterViolated, regionChecker->analyzeRegion(allVioHardRegion, storm::modelchecker::RegionResult::Unknown, true));
+
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseDtmcParameterLiftingTest, Crowds_Prob_stepBounded) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm";
+    std::string formulaAsString = "P<0.5 [F<=300 \"observe0Greater1\" ]";
+    std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
+    carl::VariablePool::getInstance().clear();
+
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+   
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=PF<=0.75,0.15<=badC<=0.2", modelParameters);
+    auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.75<=PF<=0.8,0.2<=badC<=0.3", modelParameters);
+    auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.8<=PF<=0.95,0.2<=badC<=0.2", modelParameters);
+    auto allVioHardRegion=storm::api::parseRegion<storm::RationalFunction>("0.8<=PF<=0.95,0.2<=badC<=0.9", modelParameters);
+
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::CenterViolated, regionChecker->analyzeRegion(allVioHardRegion, storm::modelchecker::RegionResult::Unknown, true));
+
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseDtmcParameterLiftingTest, Crowds_Prob_1Par) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm";
+    std::string formulaAsString = "P>0.75 [F \"observe0Greater1\" ]";
+    std::string constantsAsString = "badC=0.3"; //e.g. pL=0.9,TOACK=0.5
+    carl::VariablePool::getInstance().clear();
+
+    
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.9<=PF<=0.99", modelParameters);
+    auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.8<=PF<=0.9", modelParameters);
+    auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.01<=PF<=0.8", modelParameters);
+
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+    
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseDtmcParameterLiftingTest, Crowds_Prob_Const) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/crowds3_5.pm";
+    std::string formulaAsString = "P>0.6 [F \"observe0Greater1\" ]";
+    std::string constantsAsString = "PF=0.9,badC=0.2";
+    carl::VariablePool::getInstance().clear();
+    
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("", modelParameters);
+    
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+
+    carl::VariablePool::getInstance().clear();
+}
+
+#endif
diff --git a/src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp b/src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp
new file mode 100644
index 000000000..fd690b876
--- /dev/null
+++ b/src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp
@@ -0,0 +1,301 @@
+#include "gtest/gtest.h"
+#include "storm-config.h"
+
+#ifdef STORM_HAVE_CARL
+
+#include "storm/adapters/RationalFunctionAdapter.h"
+
+#include "storm-pars/api/storm-pars.h"
+#include "storm/api/storm.h"
+
+TEST(SparseMdpParameterLiftingTest, two_dice_Prob) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm";
+    std::string formulaFile = "P<=0.17 [ F \"doubles\" ]";
+    
+    carl::VariablePool::getInstance().clear();
+
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program));
+    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+    auto allSatRegion = storm::api::parseRegion<storm::RationalFunction>("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters);
+    auto exBothRegion = storm::api::parseRegion<storm::RationalFunction>("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters);
+    auto allVioRegion = storm::api::parseRegion<storm::RationalFunction>("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters);
+
+    
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+    
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseMdpParameterLiftingTest, two_dice_Prob_bounded) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm";
+    std::string formulaFile = "P<=0.17 [ F<100 \"doubles\" ]";
+    
+    carl::VariablePool::getInstance().clear();
+
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program));
+    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+    auto allSatRegion = storm::api::parseRegion<storm::RationalFunction>("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters);
+    auto exBothRegion = storm::api::parseRegion<storm::RationalFunction>("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters);
+    auto allVioRegion = storm::api::parseRegion<storm::RationalFunction>("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters);
+
+    
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+    
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseMdpParameterLiftingTest, two_dice_Prob_exactValidation) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm";
+    std::string formulaFile = "P<=0.17 [ F \"doubles\" ]";
+    
+    carl::VariablePool::getInstance().clear();
+
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program));
+    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeValidatingRegionModelChecker<storm::RationalFunction, double, storm::RationalNumber>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+    auto allSatRegion = storm::api::parseRegion<storm::RationalFunction>("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters);
+    auto exBothRegion = storm::api::parseRegion<storm::RationalFunction>("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters);
+    auto allVioRegion = storm::api::parseRegion<storm::RationalFunction>("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters);
+
+    
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+    
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseMdpParameterLiftingTest, two_dice_Prob_bounded_exactValidation) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/two_dice.nm";
+    std::string formulaFile = "P<=0.17 [ F<100 \"doubles\" ]";
+    
+    carl::VariablePool::getInstance().clear();
+
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaFile, program));
+    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeValidatingRegionModelChecker<storm::RationalFunction, double, storm::RationalNumber>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+    auto allSatRegion = storm::api::parseRegion<storm::RationalFunction>("0.495<=p1<=0.5,0.5<=p2<=0.505", modelParameters);
+    auto exBothRegion = storm::api::parseRegion<storm::RationalFunction>("0.45<=p1<=0.55,0.45<=p2<=0.55", modelParameters);
+    auto allVioRegion = storm::api::parseRegion<storm::RationalFunction>("0.6<=p1<=0.7,0.6<=p2<=0.6", modelParameters);
+
+    
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+    
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseMdpParameterLiftingTest, coin_Prob) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/coin2_2.nm";
+    std::string formulaAsString = "P>0.25 [F \"finished\"&\"all_coins_equal_1\" ]";
+    
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+    //start testing
+    auto allSatRegion = storm::api::parseRegion<storm::RationalFunction>("0.3<=p1<=0.45,0.2<=p2<=0.54", modelParameters);
+    auto exBothRegion = storm::api::parseRegion<storm::RationalFunction>("0.4<=p1<=0.65,0.5<=p2<=0.7", modelParameters);
+    auto allVioRegion = storm::api::parseRegion<storm::RationalFunction>("0.4<=p1<=0.7,0.55<=p2<=0.6", modelParameters);
+        
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseMdpParameterLiftingTest, brp_Prop) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm";
+    std::string formulaAsString = "P<=0.84 [ F (s=5 & T) ]";
+    std::string constantsAsString = "TOMsg=0.0,TOAck=0.0";
+
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pL<=0.9,0.75<=pK<=0.95", modelParameters);
+    auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.4<=pL<=0.65,0.75<=pK<=0.95", modelParameters);
+    auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pL<=0.73,0.2<=pK<=0.715", modelParameters);
+        
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseMdpParameterLiftingTest, brp_Rew) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm";
+    std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]";
+    std::string constantsAsString = "pL=0.9,TOAck=0.5";
+
+
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+   //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters);
+    auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters);
+    auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters);
+
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseMdpParameterLiftingTest, brp_Rew_bounded) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm";
+    std::string formulaAsString = "R>2.5 [ C<=300 ]";
+    std::string constantsAsString = "pL=0.9,TOAck=0.5";
+
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+   //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.875,0.75<=TOMsg<=0.95", modelParameters);
+    auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.6<=pK<=0.9,0.5<=TOMsg<=0.95", modelParameters);
+    auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.3,0.2<=TOMsg<=0.3", modelParameters);
+
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+
+    carl::VariablePool::getInstance().clear();
+}
+
+
+TEST(SparseMdpParameterLiftingTest, Brp_Rew_Infty) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm";
+    std::string formulaAsString = "R>2.5 [F (s=0&srep=3) ]";
+    std::string constantsAsString = "";
+    carl::VariablePool::getInstance().clear();
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters);
+    
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+
+    carl::VariablePool::getInstance().clear();
+}
+
+TEST(SparseMdpParameterLiftingTest, Brp_Rew_4Par) {
+    
+    std::string programFile = STORM_TEST_RESOURCES_DIR "/pmdp/brp16_2.nm";
+    std::string formulaAsString = "R>2.5 [F ((s=5) | (s=0&srep=3)) ]";
+    std::string constantsAsString = ""; //!! this model will have 4 parameters
+    carl::VariablePool::getInstance().clear();
+    storm::prism::Program program = storm::api::parseProgram(programFile);
+    program = storm::utility::prism::preprocess(program, constantsAsString);
+    std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
+    std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
+    
+    auto modelParameters = storm::models::sparse::getProbabilityParameters(*model);
+    auto rewParameters = storm::models::sparse::getRewardParameters(*model);
+    modelParameters.insert(rewParameters.begin(), rewParameters.end());
+    
+    auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker<storm::RationalFunction, double>(model, storm::api::createTask<storm::RationalFunction>(formulas[0], true));
+    
+    //start testing
+    auto allSatRegion=storm::api::parseRegion<storm::RationalFunction>("0.7<=pK<=0.9,0.6<=pL<=0.85,0.9<=TOMsg<=0.95,0.85<=TOAck<=0.9", modelParameters);
+    auto exBothRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.7,0.2<=pL<=0.8,0.15<=TOMsg<=0.65,0.3<=TOAck<=0.9", modelParameters);
+    auto allVioRegion=storm::api::parseRegion<storm::RationalFunction>("0.1<=pK<=0.4,0.2<=pL<=0.3,0.15<=TOMsg<=0.3,0.1<=TOAck<=0.2", modelParameters);
+
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllSat, regionChecker->analyzeRegion(allSatRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::ExistsBoth, regionChecker->analyzeRegion(exBothRegion, storm::modelchecker::RegionResult::Unknown, true));
+    EXPECT_EQ(storm::modelchecker::RegionResult::AllViolated, regionChecker->analyzeRegion(allVioRegion, storm::modelchecker::RegionResult::Unknown, true));
+    
+    carl::VariablePool::getInstance().clear();
+}
+
+
+
+
+
+#endif
diff --git a/src/test/storm-pars/storm-test.cpp b/src/test/storm-pars/storm-test.cpp
new file mode 100644
index 000000000..203c56b40
--- /dev/null
+++ b/src/test/storm-pars/storm-test.cpp
@@ -0,0 +1,8 @@
+#include "gtest/gtest.h"
+#include "storm/settings/SettingsManager.h"
+
+int main(int argc, char **argv) {
+  storm::settings::initializeAll("Storm-pars (Functional) Testing Suite", "test-pars");
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/src/test/utility/ModelInstantiatorTest.cpp b/src/test/storm-pars/utility/ModelInstantiatorTest.cpp
similarity index 99%
rename from src/test/utility/ModelInstantiatorTest.cpp
rename to src/test/storm-pars/utility/ModelInstantiatorTest.cpp
index 07859c600..e66a912d5 100644
--- a/src/test/utility/ModelInstantiatorTest.cpp
+++ b/src/test/storm-pars/utility/ModelInstantiatorTest.cpp
@@ -11,8 +11,8 @@
 #include "storm/settings/SettingsManager.h"
 #include "storm/settings/modules/GeneralSettings.h"
 
+#include "storm-pars/utility/ModelInstantiator.h"
 #include "storm/api/storm.h"
-#include "utility/ModelInstantiator.h"
 #include "storm/models/sparse/Model.h"
 #include "storm/models/sparse/Dtmc.h"
 #include "storm/models/sparse/Mdp.h"
diff --git a/src/test/storm/CMakeLists.txt b/src/test/storm/CMakeLists.txt
new file mode 100644
index 000000000..0ae2fc509
--- /dev/null
+++ b/src/test/storm/CMakeLists.txt
@@ -0,0 +1,23 @@
+# Base path for test files
+set(STORM_TESTS_BASE_PATH "${PROJECT_SOURCE_DIR}/src/test/storm")
+
+# Test Sources
+file(GLOB_RECURSE ALL_FILES ${STORM_TESTS_BASE_PATH}/*.h ${STORM_TESTS_BASE_PATH}/*.cpp)
+
+register_source_groups_from_filestructure("${ALL_FILES}" test)
+
+# Note that the tests also need the source files, except for the main file
+include_directories(${GTEST_INCLUDE_DIR})
+
+foreach (testsuite abstraction adapter builder logic modelchecker parser permissiveschedulers solver storage transformer utility)
+
+	  file(GLOB_RECURSE TEST_${testsuite}_FILES ${STORM_TESTS_BASE_PATH}/${testsuite}/*.h ${STORM_TESTS_BASE_PATH}/${testsuite}/*.cpp)
+      add_executable (test-${testsuite} ${TEST_${testsuite}_FILES} ${STORM_TESTS_BASE_PATH}/storm-test.cpp)
+	  target_link_libraries(test-${testsuite} storm)
+	  target_link_libraries(test-${testsuite} ${STORM_TEST_LINK_LIBRARIES})
+
+	  add_dependencies(test-${testsuite} test-resources)
+	  add_test(NAME run-test-${testsuite} COMMAND $<TARGET_FILE:test-${testsuite}>)
+      add_dependencies(tests test-${testsuite})
+	
+endforeach ()
diff --git a/src/test/abstraction/PrismMenuGameTest.cpp b/src/test/storm/abstraction/PrismMenuGameTest.cpp
similarity index 100%
rename from src/test/abstraction/PrismMenuGameTest.cpp
rename to src/test/storm/abstraction/PrismMenuGameTest.cpp
diff --git a/src/test/adapter/MathsatExpressionAdapterTest.cpp b/src/test/storm/adapter/MathsatExpressionAdapterTest.cpp
similarity index 100%
rename from src/test/adapter/MathsatExpressionAdapterTest.cpp
rename to src/test/storm/adapter/MathsatExpressionAdapterTest.cpp
diff --git a/src/test/adapter/Z3ExpressionAdapterTest.cpp b/src/test/storm/adapter/Z3ExpressionAdapterTest.cpp
similarity index 100%
rename from src/test/adapter/Z3ExpressionAdapterTest.cpp
rename to src/test/storm/adapter/Z3ExpressionAdapterTest.cpp
diff --git a/src/test/builder/DdJaniModelBuilderTest.cpp b/src/test/storm/builder/DdJaniModelBuilderTest.cpp
similarity index 100%
rename from src/test/builder/DdJaniModelBuilderTest.cpp
rename to src/test/storm/builder/DdJaniModelBuilderTest.cpp
diff --git a/src/test/builder/DdPrismModelBuilderTest.cpp b/src/test/storm/builder/DdPrismModelBuilderTest.cpp
similarity index 100%
rename from src/test/builder/DdPrismModelBuilderTest.cpp
rename to src/test/storm/builder/DdPrismModelBuilderTest.cpp
diff --git a/src/test/builder/ExplicitJaniModelBuilderTest.cpp b/src/test/storm/builder/ExplicitJaniModelBuilderTest.cpp
similarity index 100%
rename from src/test/builder/ExplicitJaniModelBuilderTest.cpp
rename to src/test/storm/builder/ExplicitJaniModelBuilderTest.cpp
diff --git a/src/test/builder/ExplicitJitJaniModelBuilderTest.cpp b/src/test/storm/builder/ExplicitJitJaniModelBuilderTest.cpp
similarity index 100%
rename from src/test/builder/ExplicitJitJaniModelBuilderTest.cpp
rename to src/test/storm/builder/ExplicitJitJaniModelBuilderTest.cpp
diff --git a/src/test/builder/ExplicitPrismModelBuilderTest.cpp b/src/test/storm/builder/ExplicitPrismModelBuilderTest.cpp
similarity index 100%
rename from src/test/builder/ExplicitPrismModelBuilderTest.cpp
rename to src/test/storm/builder/ExplicitPrismModelBuilderTest.cpp
diff --git a/src/test/logic/FragmentCheckerTest.cpp b/src/test/storm/logic/FragmentCheckerTest.cpp
similarity index 100%
rename from src/test/logic/FragmentCheckerTest.cpp
rename to src/test/storm/logic/FragmentCheckerTest.cpp
diff --git a/src/test/modelchecker/EigenDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/EigenDtmcPrctlModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/EigenDtmcPrctlModelCheckerTest.cpp
rename to src/test/storm/modelchecker/EigenDtmcPrctlModelCheckerTest.cpp
diff --git a/src/test/modelchecker/GameBasedDtmcModelCheckerTest.cpp b/src/test/storm/modelchecker/GameBasedDtmcModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/GameBasedDtmcModelCheckerTest.cpp
rename to src/test/storm/modelchecker/GameBasedDtmcModelCheckerTest.cpp
diff --git a/src/test/modelchecker/GameBasedMdpModelCheckerTest.cpp b/src/test/storm/modelchecker/GameBasedMdpModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/GameBasedMdpModelCheckerTest.cpp
rename to src/test/storm/modelchecker/GameBasedMdpModelCheckerTest.cpp
diff --git a/src/test/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp b/src/test/storm/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp
rename to src/test/storm/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp
diff --git a/src/test/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp
rename to src/test/storm/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp
diff --git a/src/test/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp b/src/test/storm/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp
rename to src/test/storm/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp
diff --git a/src/test/modelchecker/GmmxxHybridDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/GmmxxHybridDtmcPrctlModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/GmmxxHybridDtmcPrctlModelCheckerTest.cpp
rename to src/test/storm/modelchecker/GmmxxHybridDtmcPrctlModelCheckerTest.cpp
diff --git a/src/test/modelchecker/GmmxxHybridMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/GmmxxHybridMdpPrctlModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/GmmxxHybridMdpPrctlModelCheckerTest.cpp
rename to src/test/storm/modelchecker/GmmxxHybridMdpPrctlModelCheckerTest.cpp
diff --git a/src/test/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp
rename to src/test/storm/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp
diff --git a/src/test/modelchecker/NativeCtmcCslModelCheckerTest.cpp b/src/test/storm/modelchecker/NativeCtmcCslModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/NativeCtmcCslModelCheckerTest.cpp
rename to src/test/storm/modelchecker/NativeCtmcCslModelCheckerTest.cpp
diff --git a/src/test/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp
rename to src/test/storm/modelchecker/NativeDtmcPrctlModelCheckerTest.cpp
diff --git a/src/test/modelchecker/NativeHybridCtmcCslModelCheckerTest.cpp b/src/test/storm/modelchecker/NativeHybridCtmcCslModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/NativeHybridCtmcCslModelCheckerTest.cpp
rename to src/test/storm/modelchecker/NativeHybridCtmcCslModelCheckerTest.cpp
diff --git a/src/test/modelchecker/NativeHybridDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/NativeHybridDtmcPrctlModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/NativeHybridDtmcPrctlModelCheckerTest.cpp
rename to src/test/storm/modelchecker/NativeHybridDtmcPrctlModelCheckerTest.cpp
diff --git a/src/test/modelchecker/NativeHybridMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/NativeHybridMdpPrctlModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/NativeHybridMdpPrctlModelCheckerTest.cpp
rename to src/test/storm/modelchecker/NativeHybridMdpPrctlModelCheckerTest.cpp
diff --git a/src/test/modelchecker/NativeMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/NativeMdpPrctlModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/NativeMdpPrctlModelCheckerTest.cpp
rename to src/test/storm/modelchecker/NativeMdpPrctlModelCheckerTest.cpp
diff --git a/src/test/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp
rename to src/test/storm/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp
diff --git a/src/test/modelchecker/SparseExplorationModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseExplorationModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/SparseExplorationModelCheckerTest.cpp
rename to src/test/storm/modelchecker/SparseExplorationModelCheckerTest.cpp
diff --git a/src/test/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp
rename to src/test/storm/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp
diff --git a/src/test/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp
rename to src/test/storm/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp
diff --git a/src/test/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp
rename to src/test/storm/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp
diff --git a/src/test/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp
rename to src/test/storm/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp
diff --git a/src/test/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp
rename to src/test/storm/modelchecker/SymbolicDtmcPrctlModelCheckerTest.cpp
diff --git a/src/test/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp
rename to src/test/storm/modelchecker/SymbolicMdpPrctlModelCheckerTest.cpp
diff --git a/src/test/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp
similarity index 100%
rename from src/test/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp
rename to src/test/storm/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp
diff --git a/src/test/parser/.gitignore b/src/test/storm/parser/.gitignore
similarity index 100%
rename from src/test/parser/.gitignore
rename to src/test/storm/parser/.gitignore
diff --git a/src/test/parser/AutoParserTest.cpp b/src/test/storm/parser/AutoParserTest.cpp
similarity index 100%
rename from src/test/parser/AutoParserTest.cpp
rename to src/test/storm/parser/AutoParserTest.cpp
diff --git a/src/test/parser/DeterministicModelParserTest.cpp b/src/test/storm/parser/DeterministicModelParserTest.cpp
similarity index 100%
rename from src/test/parser/DeterministicModelParserTest.cpp
rename to src/test/storm/parser/DeterministicModelParserTest.cpp
diff --git a/src/test/parser/DeterministicSparseTransitionParserTest.cpp b/src/test/storm/parser/DeterministicSparseTransitionParserTest.cpp
similarity index 100%
rename from src/test/parser/DeterministicSparseTransitionParserTest.cpp
rename to src/test/storm/parser/DeterministicSparseTransitionParserTest.cpp
diff --git a/src/test/parser/DirectEncodingParserTest.cpp b/src/test/storm/parser/DirectEncodingParserTest.cpp
similarity index 100%
rename from src/test/parser/DirectEncodingParserTest.cpp
rename to src/test/storm/parser/DirectEncodingParserTest.cpp
diff --git a/src/test/parser/FormulaParserTest.cpp b/src/test/storm/parser/FormulaParserTest.cpp
similarity index 100%
rename from src/test/parser/FormulaParserTest.cpp
rename to src/test/storm/parser/FormulaParserTest.cpp
diff --git a/src/test/parser/MappedFileTest.cpp b/src/test/storm/parser/MappedFileTest.cpp
similarity index 100%
rename from src/test/parser/MappedFileTest.cpp
rename to src/test/storm/parser/MappedFileTest.cpp
diff --git a/src/test/parser/MarkovAutomatonParserTest.cpp b/src/test/storm/parser/MarkovAutomatonParserTest.cpp
similarity index 100%
rename from src/test/parser/MarkovAutomatonParserTest.cpp
rename to src/test/storm/parser/MarkovAutomatonParserTest.cpp
diff --git a/src/test/parser/MarkovAutomatonSparseTransitionParserTest.cpp b/src/test/storm/parser/MarkovAutomatonSparseTransitionParserTest.cpp
similarity index 100%
rename from src/test/parser/MarkovAutomatonSparseTransitionParserTest.cpp
rename to src/test/storm/parser/MarkovAutomatonSparseTransitionParserTest.cpp
diff --git a/src/test/parser/NondeterministicModelParserTest.cpp b/src/test/storm/parser/NondeterministicModelParserTest.cpp
similarity index 100%
rename from src/test/parser/NondeterministicModelParserTest.cpp
rename to src/test/storm/parser/NondeterministicModelParserTest.cpp
diff --git a/src/test/parser/NondeterministicSparseTransitionParserTest.cpp b/src/test/storm/parser/NondeterministicSparseTransitionParserTest.cpp
similarity index 100%
rename from src/test/parser/NondeterministicSparseTransitionParserTest.cpp
rename to src/test/storm/parser/NondeterministicSparseTransitionParserTest.cpp
diff --git a/src/test/parser/PrismParserTest.cpp b/src/test/storm/parser/PrismParserTest.cpp
similarity index 100%
rename from src/test/parser/PrismParserTest.cpp
rename to src/test/storm/parser/PrismParserTest.cpp
diff --git a/src/test/parser/SparseItemLabelingParserTest.cpp b/src/test/storm/parser/SparseItemLabelingParserTest.cpp
similarity index 100%
rename from src/test/parser/SparseItemLabelingParserTest.cpp
rename to src/test/storm/parser/SparseItemLabelingParserTest.cpp
diff --git a/src/test/parser/SparseStateRewardParserTest.cpp b/src/test/storm/parser/SparseStateRewardParserTest.cpp
similarity index 100%
rename from src/test/parser/SparseStateRewardParserTest.cpp
rename to src/test/storm/parser/SparseStateRewardParserTest.cpp
diff --git a/src/test/permissiveschedulers/MilpPermissiveSchedulerTest.cpp b/src/test/storm/permissiveschedulers/MilpPermissiveSchedulerTest.cpp
similarity index 100%
rename from src/test/permissiveschedulers/MilpPermissiveSchedulerTest.cpp
rename to src/test/storm/permissiveschedulers/MilpPermissiveSchedulerTest.cpp
diff --git a/src/test/permissiveschedulers/SmtPermissiveSchedulerTest.cpp b/src/test/storm/permissiveschedulers/SmtPermissiveSchedulerTest.cpp
similarity index 100%
rename from src/test/permissiveschedulers/SmtPermissiveSchedulerTest.cpp
rename to src/test/storm/permissiveschedulers/SmtPermissiveSchedulerTest.cpp
diff --git a/src/test/solver/CudaPluginTest.cpp b/src/test/storm/solver/CudaPluginTest.cpp
similarity index 100%
rename from src/test/solver/CudaPluginTest.cpp
rename to src/test/storm/solver/CudaPluginTest.cpp
diff --git a/src/test/solver/EigenLinearEquationSolverTest.cpp b/src/test/storm/solver/EigenLinearEquationSolverTest.cpp
similarity index 100%
rename from src/test/solver/EigenLinearEquationSolverTest.cpp
rename to src/test/storm/solver/EigenLinearEquationSolverTest.cpp
diff --git a/src/test/solver/EliminationLinearEquationSolverTest.cpp b/src/test/storm/solver/EliminationLinearEquationSolverTest.cpp
similarity index 100%
rename from src/test/solver/EliminationLinearEquationSolverTest.cpp
rename to src/test/storm/solver/EliminationLinearEquationSolverTest.cpp
diff --git a/src/test/solver/FullySymbolicGameSolverTest.cpp b/src/test/storm/solver/FullySymbolicGameSolverTest.cpp
similarity index 100%
rename from src/test/solver/FullySymbolicGameSolverTest.cpp
rename to src/test/storm/solver/FullySymbolicGameSolverTest.cpp
diff --git a/src/test/solver/GameSolverTest.cpp b/src/test/storm/solver/GameSolverTest.cpp
similarity index 100%
rename from src/test/solver/GameSolverTest.cpp
rename to src/test/storm/solver/GameSolverTest.cpp
diff --git a/src/test/solver/GlpkLpSolverTest.cpp b/src/test/storm/solver/GlpkLpSolverTest.cpp
similarity index 100%
rename from src/test/solver/GlpkLpSolverTest.cpp
rename to src/test/storm/solver/GlpkLpSolverTest.cpp
diff --git a/src/test/solver/GmmxxLinearEquationSolverTest.cpp b/src/test/storm/solver/GmmxxLinearEquationSolverTest.cpp
similarity index 100%
rename from src/test/solver/GmmxxLinearEquationSolverTest.cpp
rename to src/test/storm/solver/GmmxxLinearEquationSolverTest.cpp
diff --git a/src/test/solver/GmmxxMinMaxLinearEquationSolverTest.cpp b/src/test/storm/solver/GmmxxMinMaxLinearEquationSolverTest.cpp
similarity index 100%
rename from src/test/solver/GmmxxMinMaxLinearEquationSolverTest.cpp
rename to src/test/storm/solver/GmmxxMinMaxLinearEquationSolverTest.cpp
diff --git a/src/test/solver/GurobiLpSolverTest.cpp b/src/test/storm/solver/GurobiLpSolverTest.cpp
similarity index 100%
rename from src/test/solver/GurobiLpSolverTest.cpp
rename to src/test/storm/solver/GurobiLpSolverTest.cpp
diff --git a/src/test/solver/MathsatSmtSolverTest.cpp b/src/test/storm/solver/MathsatSmtSolverTest.cpp
similarity index 100%
rename from src/test/solver/MathsatSmtSolverTest.cpp
rename to src/test/storm/solver/MathsatSmtSolverTest.cpp
diff --git a/src/test/solver/MinMaxTechniqueSelectionTest.cpp b/src/test/storm/solver/MinMaxTechniqueSelectionTest.cpp
similarity index 100%
rename from src/test/solver/MinMaxTechniqueSelectionTest.cpp
rename to src/test/storm/solver/MinMaxTechniqueSelectionTest.cpp
diff --git a/src/test/solver/NativeLinearEquationSolverTest.cpp b/src/test/storm/solver/NativeLinearEquationSolverTest.cpp
similarity index 100%
rename from src/test/solver/NativeLinearEquationSolverTest.cpp
rename to src/test/storm/solver/NativeLinearEquationSolverTest.cpp
diff --git a/src/test/solver/NativeMinMaxLinearEquationSolverTest.cpp b/src/test/storm/solver/NativeMinMaxLinearEquationSolverTest.cpp
similarity index 100%
rename from src/test/solver/NativeMinMaxLinearEquationSolverTest.cpp
rename to src/test/storm/solver/NativeMinMaxLinearEquationSolverTest.cpp
diff --git a/src/test/solver/Z3LpSolverTest.cpp b/src/test/storm/solver/Z3LpSolverTest.cpp
similarity index 100%
rename from src/test/solver/Z3LpSolverTest.cpp
rename to src/test/storm/solver/Z3LpSolverTest.cpp
diff --git a/src/test/solver/Z3SmtSolverTest.cpp b/src/test/storm/solver/Z3SmtSolverTest.cpp
similarity index 100%
rename from src/test/solver/Z3SmtSolverTest.cpp
rename to src/test/storm/solver/Z3SmtSolverTest.cpp
diff --git a/src/test/storage/BitVectorHashMapTest.cpp b/src/test/storm/storage/BitVectorHashMapTest.cpp
similarity index 100%
rename from src/test/storage/BitVectorHashMapTest.cpp
rename to src/test/storm/storage/BitVectorHashMapTest.cpp
diff --git a/src/test/storage/BitVectorTest.cpp b/src/test/storm/storage/BitVectorTest.cpp
similarity index 100%
rename from src/test/storage/BitVectorTest.cpp
rename to src/test/storm/storage/BitVectorTest.cpp
diff --git a/src/test/storage/CuddDdTest.cpp b/src/test/storm/storage/CuddDdTest.cpp
similarity index 100%
rename from src/test/storage/CuddDdTest.cpp
rename to src/test/storm/storage/CuddDdTest.cpp
diff --git a/src/test/storage/DeterministicModelBisimulationDecompositionTest.cpp b/src/test/storm/storage/DeterministicModelBisimulationDecompositionTest.cpp
similarity index 100%
rename from src/test/storage/DeterministicModelBisimulationDecompositionTest.cpp
rename to src/test/storm/storage/DeterministicModelBisimulationDecompositionTest.cpp
diff --git a/src/test/storage/ExpressionEvalutionTest.cpp b/src/test/storm/storage/ExpressionEvalutionTest.cpp
similarity index 100%
rename from src/test/storage/ExpressionEvalutionTest.cpp
rename to src/test/storm/storage/ExpressionEvalutionTest.cpp
diff --git a/src/test/storage/ExpressionTest.cpp b/src/test/storm/storage/ExpressionTest.cpp
similarity index 100%
rename from src/test/storage/ExpressionTest.cpp
rename to src/test/storm/storage/ExpressionTest.cpp
diff --git a/src/test/storage/JaniModelTest.cpp b/src/test/storm/storage/JaniModelTest.cpp
similarity index 100%
rename from src/test/storage/JaniModelTest.cpp
rename to src/test/storm/storage/JaniModelTest.cpp
diff --git a/src/test/storage/MaximalEndComponentDecompositionTest.cpp b/src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp
similarity index 100%
rename from src/test/storage/MaximalEndComponentDecompositionTest.cpp
rename to src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp
diff --git a/src/test/storage/NondeterministicModelBisimulationDecompositionTest.cpp b/src/test/storm/storage/NondeterministicModelBisimulationDecompositionTest.cpp
similarity index 100%
rename from src/test/storage/NondeterministicModelBisimulationDecompositionTest.cpp
rename to src/test/storm/storage/NondeterministicModelBisimulationDecompositionTest.cpp
diff --git a/src/test/storage/PrismProgramTest.cpp b/src/test/storm/storage/PrismProgramTest.cpp
similarity index 100%
rename from src/test/storage/PrismProgramTest.cpp
rename to src/test/storm/storage/PrismProgramTest.cpp
diff --git a/src/test/storage/SchedulerTest.cpp b/src/test/storm/storage/SchedulerTest.cpp
similarity index 100%
rename from src/test/storage/SchedulerTest.cpp
rename to src/test/storm/storage/SchedulerTest.cpp
diff --git a/src/test/storage/SparseMatrixTest.cpp b/src/test/storm/storage/SparseMatrixTest.cpp
similarity index 100%
rename from src/test/storage/SparseMatrixTest.cpp
rename to src/test/storm/storage/SparseMatrixTest.cpp
diff --git a/src/test/storage/StronglyConnectedComponentDecompositionTest.cpp b/src/test/storm/storage/StronglyConnectedComponentDecompositionTest.cpp
similarity index 100%
rename from src/test/storage/StronglyConnectedComponentDecompositionTest.cpp
rename to src/test/storm/storage/StronglyConnectedComponentDecompositionTest.cpp
diff --git a/src/test/storage/SylvanDdTest.cpp b/src/test/storm/storage/SylvanDdTest.cpp
similarity index 100%
rename from src/test/storage/SylvanDdTest.cpp
rename to src/test/storm/storage/SylvanDdTest.cpp
diff --git a/src/test/storm-test.cpp b/src/test/storm/storm-test.cpp
similarity index 100%
rename from src/test/storm-test.cpp
rename to src/test/storm/storm-test.cpp
diff --git a/src/test/transformer/EndComponentEliminatorTest.cpp b/src/test/storm/transformer/EndComponentEliminatorTest.cpp
similarity index 100%
rename from src/test/transformer/EndComponentEliminatorTest.cpp
rename to src/test/storm/transformer/EndComponentEliminatorTest.cpp
diff --git a/src/test/utility/GraphTest.cpp b/src/test/storm/utility/GraphTest.cpp
similarity index 100%
rename from src/test/utility/GraphTest.cpp
rename to src/test/storm/utility/GraphTest.cpp
diff --git a/src/test/utility/KSPTest.cpp b/src/test/storm/utility/KSPTest.cpp
similarity index 100%
rename from src/test/utility/KSPTest.cpp
rename to src/test/storm/utility/KSPTest.cpp
diff --git a/src/test/utility/VectorTest.cpp b/src/test/storm/utility/VectorTest.cpp
similarity index 100%
rename from src/test/utility/VectorTest.cpp
rename to src/test/storm/utility/VectorTest.cpp