From e49582c7cf723fe4df3c6a18c5dcd3fe589fac66 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Wed, 18 May 2016 14:49:04 +0200
Subject: [PATCH 01/65] Replaced assert with STORM_LOG_ASSERT

Former-commit-id: 692ae47b1bc78c9534b153ee3f8194db0c221e04
---
 src/models/sparse/MarkovAutomaton.cpp         | 12 ++---
 src/models/sparse/Model.cpp                   |  4 +-
 src/models/sparse/StandardRewardModel.cpp     | 26 +++++-----
 .../MILPPermissiveSchedulers.h                | 18 +++----
 .../PermissiveSchedulerPenalty.h              |  2 +-
 src/permissivesched/PermissiveSchedulers.cpp  |  4 +-
 src/permissivesched/PermissiveSchedulers.h    |  2 +-
 .../SmtBasedPermissiveSchedulers.h            | 14 +++---
 src/solver/MinMaxLinearEquationSolver.h       |  2 +-
 src/solver/OptimizationDirection.cpp          |  4 +-
 .../stateelimination/StateEliminator.cpp      |  2 +-
 src/storage/FlexibleSparseMatrix.cpp          | 12 ++---
 src/storage/SparseMatrix.cpp                  | 14 +++---
 src/storage/SparseMatrix.h                    |  1 +
 .../bisimulation/BisimulationDecomposition.h  |  2 +-
 src/storage/dft/DFT.cpp                       | 48 +++++++++----------
 src/storage/dft/DFT.h                         | 14 +++---
 src/storage/dft/DFTElementState.h             | 18 +++++--
 src/storage/dft/DFTIsomorphism.h              | 41 ++++++++--------
 src/storage/dft/DFTState.cpp                  | 38 +++++++--------
 src/storage/dft/DFTState.h                    |  3 +-
 .../dft/DFTStateSpaceGenerationQueues.h       |  2 +-
 src/storage/expressions/Variable.cpp          |  5 +-
 src/storage/expressions/Variable.h            |  3 +-
 src/storage/prism/Assignment.cpp              |  3 +-
 src/storage/prism/Command.cpp                 |  3 +-
 src/storage/prism/Program.cpp                 |  2 +-
 src/storm-dyftee.cpp                          | 34 +++++++++++--
 28 files changed, 181 insertions(+), 152 deletions(-)

diff --git a/src/models/sparse/MarkovAutomaton.cpp b/src/models/sparse/MarkovAutomaton.cpp
index b3b416cfc..7b997293f 100644
--- a/src/models/sparse/MarkovAutomaton.cpp
+++ b/src/models/sparse/MarkovAutomaton.cpp
@@ -43,8 +43,8 @@ namespace storm {
                                                                          std::unordered_map<std::string, RewardModelType>&& rewardModels,
                                                                          boost::optional<std::vector<LabelSet>>&& optionalChoiceLabeling)
             : NondeterministicModel<ValueType, RewardModelType>(storm::models::ModelType::MarkovAutomaton, std::move(transitionMatrix), std::move(stateLabeling), std::move(rewardModels), std::move(optionalChoiceLabeling)), markovianStates(markovianStates), exitRates(std::move(exitRates)), closed(this->checkIsClosed()) {
-                assert(probabilities);
-                assert(this->getTransitionMatrix().isProbabilistic());
+                STORM_LOG_ASSERT(probabilities, "Matrix must be probabilistic.");
+                STORM_LOG_ASSERT(this->getTransitionMatrix().isProbabilistic(), "Matrix must be probabilistic.");
             }
             
             template <typename ValueType, typename RewardModelType>
@@ -244,10 +244,10 @@ namespace storm {
                     // Get number of choices in current state
                     uint_fast64_t numberChoices = this->getTransitionMatrix().getRowGroupIndices()[state + 1] - this->getTransitionMatrix().getRowGroupIndices()[state];
                     if (isMarkovianState(state)) {
-                        assert(numberChoices == 1);
+                        STORM_LOG_ASSERT(numberChoices == 1, "Wrong number of choices for markovian state.");
                     }
                     if (numberChoices > 1) {
-                        assert(isProbabilisticState(state));
+                        STORM_LOG_ASSERT(isProbabilisticState(state), "State is not probabilistic.");
                         return false;
                     }
                 }
@@ -276,7 +276,7 @@ namespace storm {
                 storm::solver::stateelimination::MAEliminator<storm::models::sparse::Dtmc<ValueType>> stateEliminator(flexibleMatrix, flexibleBackwardTransitions);
                 
                 for (uint_fast64_t state = 0; state < this->getNumberOfStates(); ++state) {
-                    assert(!this->isHybridState(state));
+                    STORM_LOG_ASSERT(!this->isHybridState(state), "State is hybrid.");
                     if (this->isProbabilisticState(state)) {
                         // Eliminate this probabilistic state
                         stateEliminator.eliminateState(state, true);
@@ -293,7 +293,7 @@ namespace storm {
                         // State is eliminated and can be discarded
                         keepStates.set(state, false);
                     } else {
-                        assert(this->isMarkovianState(state));
+                        STORM_LOG_ASSERT(this->isMarkovianState(state), "State is not markovian.");
                         // Copy transitions
                         for (uint_fast64_t row = flexibleMatrix.getRowGroupIndices()[state]; row < flexibleMatrix.getRowGroupIndices()[state + 1]; ++row) {
                             for (auto const& entry : flexibleMatrix.getRow(row)) {
diff --git a/src/models/sparse/Model.cpp b/src/models/sparse/Model.cpp
index 265f0d8b0..a47214753 100644
--- a/src/models/sparse/Model.cpp
+++ b/src/models/sparse/Model.cpp
@@ -91,7 +91,7 @@ namespace storm {
 
             template<typename ValueType, typename RewardModelType>
             RewardModelType& Model<ValueType, RewardModelType>::rewardModel(std::string const& rewardModelName) {
-                assert(this->hasRewardModel(rewardModelName));
+                STORM_LOG_ASSERT(this->hasRewardModel(rewardModelName), "Model has no reward model.");
                 return this->rewardModels.find(rewardModelName)->second;
             }
 
@@ -117,7 +117,7 @@ namespace storm {
                 if(this->hasRewardModel(rewardModelName)) {
                     STORM_LOG_THROW(!(this->hasRewardModel(rewardModelName)), storm::exceptions::IllegalArgumentException, "A reward model with the given name '" << rewardModelName << "' already exists.");
                 }
-                assert(newRewardModel.isCompatible(this->getNumberOfStates(), this->getTransitionMatrix().getRowCount()));
+                STORM_LOG_ASSERT(newRewardModel.isCompatible(this->getNumberOfStates(), this->getTransitionMatrix().getRowCount()), "New reward model is not compatible.");
                 this->rewardModels.emplace(rewardModelName, newRewardModel);
             }
 
diff --git a/src/models/sparse/StandardRewardModel.cpp b/src/models/sparse/StandardRewardModel.cpp
index 4cab9bbb4..0c9b6de89 100644
--- a/src/models/sparse/StandardRewardModel.cpp
+++ b/src/models/sparse/StandardRewardModel.cpp
@@ -37,13 +37,13 @@ namespace storm {
             
             template<typename ValueType>
             std::vector<ValueType> const& StandardRewardModel<ValueType>::getStateRewardVector() const {
-                assert(this->hasStateRewards());
+                STORM_LOG_ASSERT(this->hasStateRewards(), "No state rewards available.");
                 return this->optionalStateRewardVector.get();
             }
 
             template<typename ValueType>
             std::vector<ValueType>& StandardRewardModel<ValueType>::getStateRewardVector() {
-                assert(this->hasStateRewards());
+                STORM_LOG_ASSERT(this->hasStateRewards(), "No state rewards available.");
                 return this->optionalStateRewardVector.get();
             }
 
@@ -54,16 +54,16 @@ namespace storm {
 
             template<typename ValueType>
             ValueType const& StandardRewardModel<ValueType>::getStateReward(uint_fast64_t state) const {
-                assert(this->hasStateRewards());
-                assert(state < this->optionalStateRewardVector.get().size());
+                STORM_LOG_ASSERT(this->hasStateRewards(), "No state rewards available.");
+                STORM_LOG_ASSERT(state < this->optionalStateRewardVector.get().size(), "Invalid state.");
                 return this->optionalStateRewardVector.get()[state];
             }
 
             template<typename ValueType>
             template<typename T>
             void StandardRewardModel<ValueType>::setStateReward(uint_fast64_t state, T const & newReward) {
-                assert(this->hasStateRewards());
-                assert(state < this->optionalStateRewardVector.get().size());
+                STORM_LOG_ASSERT(this->hasStateRewards(), "No state rewards available.");
+                STORM_LOG_ASSERT(state < this->optionalStateRewardVector.get().size(), "Invalid state.");
                 this->optionalStateRewardVector.get()[state] = newReward;
             }
 
@@ -76,28 +76,28 @@ namespace storm {
             
             template<typename ValueType>
             std::vector<ValueType> const& StandardRewardModel<ValueType>::getStateActionRewardVector() const {
-                assert(this->hasStateActionRewards());
+                STORM_LOG_ASSERT(this->hasStateActionRewards(), "No state action rewards available.");
                 return this->optionalStateActionRewardVector.get();
             }
             
             template<typename ValueType>
             std::vector<ValueType>& StandardRewardModel<ValueType>::getStateActionRewardVector() {
-                assert(this->hasStateActionRewards());
+                STORM_LOG_ASSERT(this->hasStateActionRewards(), "No state action rewards available.");
                 return this->optionalStateActionRewardVector.get();
             }
 
             template<typename ValueType>
             ValueType const& StandardRewardModel<ValueType>::getStateActionReward(uint_fast64_t choiceIndex) const {
-                assert(this->hasStateActionRewards());
-                assert(choiceIndex < this->optionalStateActionRewardVector.get().size());
+                STORM_LOG_ASSERT(this->hasStateActionRewards(), "No state action rewards available.");
+                STORM_LOG_ASSERT(choiceIndex < this->optionalStateActionRewardVector.get().size(), "Invalid choiceIndex.");
                 return this->optionalStateActionRewardVector.get()[choiceIndex];
             }
 
             template<typename ValueType>
             template<typename T>
             void StandardRewardModel<ValueType>::setStateActionReward(uint_fast64_t choiceIndex, T const &newValue) {
-                assert(this->hasStateActionRewards());
-                assert(choiceIndex < this->optionalStateActionRewardVector.get().size());
+                STORM_LOG_ASSERT(this->hasStateActionRewards(), "No state action rewards available.");
+                STORM_LOG_ASSERT(choiceIndex < this->optionalStateActionRewardVector.get().size(), "Invalid choiceIndex.");
                 this->optionalStateActionRewardVector.get()[choiceIndex] = newValue;
             }
 
@@ -330,4 +330,4 @@ namespace storm {
         }
         
     }
-}
\ No newline at end of file
+}
diff --git a/src/permissivesched/MILPPermissiveSchedulers.h b/src/permissivesched/MILPPermissiveSchedulers.h
index b0f6b4529..fe5a48e11 100644
--- a/src/permissivesched/MILPPermissiveSchedulers.h
+++ b/src/permissivesched/MILPPermissiveSchedulers.h
@@ -51,13 +51,13 @@ class MilpPermissiveSchedulerComputation : public PermissiveSchedulerComputation
             
             
             bool foundSolution() const override {
-                assert(mCalledOptimizer);
+                STORM_LOG_ASSERT(mCalledOptimizer, "Optimizer not called.");
                 return !solver.isInfeasible();
             }
             
             SubMDPPermissiveScheduler<RM> getScheduler() const override {
-                assert(mCalledOptimizer);
-                assert(foundSolution());
+                STORM_LOG_ASSERT(mCalledOptimizer, "Optimizer not called.");
+                STORM_LOG_ASSERT(foundSolution(), "Solution not found.");
 
 
                 SubMDPPermissiveScheduler<RM> result(this->mdp, true);
@@ -103,7 +103,7 @@ class MilpPermissiveSchedulerComputation : public PermissiveSchedulerComputation
              */
             void createVariables(PermissiveSchedulerPenalties const& penalties, storm::storage::BitVector const& relevantStates) {
                 // We need the unique initial state later, so we get that one before looping.
-                assert(this->mdp.getInitialStates().getNumberOfSetBits() == 1);
+                STORM_LOG_ASSERT(this->mdp.getInitialStates().getNumberOfSetBits() == 1, "No unique initial state.");
                 uint_fast64_t initialStateIndex = this->mdp.getInitialStates().getNextSetIndex(0);
                     
                 storm::expressions::Variable var;
@@ -151,9 +151,9 @@ class MilpPermissiveSchedulerComputation : public PermissiveSchedulerComputation
                 // (5) and (7) are omitted on purpose (-- we currenty do not support controllability of actions -- )
                 
                 // (1)
-                assert(this->mdp.getInitialStates().getNumberOfSetBits() == 1);
+                STORM_LOG_ASSERT(this->mdp.getInitialStates().getNumberOfSetBits() == 1, "No unique initial state.");
                 uint_fast64_t initialStateIndex = this->mdp.getInitialStates().getNextSetIndex(0);
-                assert(relevantStates[initialStateIndex]);
+                STORM_LOG_ASSERT(relevantStates[initialStateIndex], "Initial state not relevant.");
                 if(lowerBound) {
                     solver.addConstraint("c1", mProbVariables[initialStateIndex] >= solver.getConstant(boundary));
                 } else {
@@ -206,9 +206,9 @@ class MilpPermissiveSchedulerComputation : public PermissiveSchedulerComputation
                                 std::string satstring = to_string(sat);
                                 // (8)
                                 if(relevantStates[entry.getColumn()]) {
-                                    assert(mGammaVariables.count(entry.getColumn()) > 0);
-                                    assert(mGammaVariables.count(s) > 0);
-                                    assert(mBetaVariables.count(sat) > 0);
+                                    STORM_LOG_ASSERT(mGammaVariables.count(entry.getColumn()) > 0, "Entry not found.");
+                                    STORM_LOG_ASSERT(mGammaVariables.count(s) > 0, "Entry not found.");
+                                    STORM_LOG_ASSERT(mBetaVariables.count(sat) > 0, "Entry not found.");
                                     solver.addConstraint("c8-" + satstring, mGammaVariables[entry.getColumn()] < mGammaVariables[s] + (solver.getConstant(1) - mBetaVariables[sat]));
                                 }
                             }
diff --git a/src/permissivesched/PermissiveSchedulerPenalty.h b/src/permissivesched/PermissiveSchedulerPenalty.h
index bb680defa..f25f61ac1 100644
--- a/src/permissivesched/PermissiveSchedulerPenalty.h
+++ b/src/permissivesched/PermissiveSchedulerPenalty.h
@@ -30,7 +30,7 @@ namespace storm {
             }
 
             void set(uint_fast64_t state, uint_fast64_t action, double penalty) {
-                assert(penalty >= 1.0);
+                STORM_LOG_ASSERT(penalty >= 1.0, "Penalty too low.");
                 if(penalty == 1.0) {
                     auto it = mPenalties.find(std::make_pair(state, action));
                     if(it != mPenalties.end()) {
diff --git a/src/permissivesched/PermissiveSchedulers.cpp b/src/permissivesched/PermissiveSchedulers.cpp
index 21aa9227c..b35f9549c 100644
--- a/src/permissivesched/PermissiveSchedulers.cpp
+++ b/src/permissivesched/PermissiveSchedulers.cpp
@@ -17,7 +17,7 @@ namespace storm {
         template<typename RM>
         boost::optional<SubMDPPermissiveScheduler<RM>> computePermissiveSchedulerViaMILP(storm::models::sparse::Mdp<double, RM> const& mdp, storm::logic::ProbabilityOperatorFormula const& safeProp) {
             storm::modelchecker::SparsePropositionalModelChecker<storm::models::sparse::Mdp<double, RM>> propMC(mdp);
-            assert(safeProp.getSubformula().isEventuallyFormula());
+            STORM_LOG_ASSERT(safeProp.getSubformula().isEventuallyFormula(), "No eventually formula.");
             auto backwardTransitions = mdp.getBackwardTransitions();
             storm::storage::BitVector goalstates = propMC.check(safeProp.getSubformula().asEventuallyFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector();
             goalstates = storm::utility::graph::performProb1A(mdp, backwardTransitions, storm::storage::BitVector(goalstates.size(), true), goalstates);
@@ -44,7 +44,7 @@ namespace storm {
         template<typename RM>
         boost::optional<SubMDPPermissiveScheduler<RM>> computePermissiveSchedulerViaSMT(storm::models::sparse::Mdp<double, RM> const& mdp, storm::logic::ProbabilityOperatorFormula const& safeProp) {
             storm::modelchecker::SparsePropositionalModelChecker<storm::models::sparse::Mdp<double, RM>> propMC(mdp);
-            assert(safeProp.getSubformula().isEventuallyFormula());
+            STORM_LOG_ASSERT(safeProp.getSubformula().isEventuallyFormula(), "No eventually formula.");
             auto backwardTransitions = mdp.getBackwardTransitions();
             storm::storage::BitVector goalstates = propMC.check(safeProp.getSubformula().asEventuallyFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector();
             goalstates = storm::utility::graph::performProb1A(mdp, backwardTransitions, storm::storage::BitVector(goalstates.size(), true), goalstates);
diff --git a/src/permissivesched/PermissiveSchedulers.h b/src/permissivesched/PermissiveSchedulers.h
index 7d0bdb3f7..eb09d4b24 100644
--- a/src/permissivesched/PermissiveSchedulers.h
+++ b/src/permissivesched/PermissiveSchedulers.h
@@ -32,7 +32,7 @@ namespace storm {
             }
 
             void disable(uint_fast64_t choiceIndex) {
-                assert(choiceIndex < enabledChoices.size());
+                STORM_LOG_ASSERT(choiceIndex < enabledChoices.size(), "Invalid choiceIndex.");
                 enabledChoices.set(choiceIndex, false);
             }
 
diff --git a/src/permissivesched/SmtBasedPermissiveSchedulers.h b/src/permissivesched/SmtBasedPermissiveSchedulers.h
index bfc1530b8..ed183866c 100644
--- a/src/permissivesched/SmtBasedPermissiveSchedulers.h
+++ b/src/permissivesched/SmtBasedPermissiveSchedulers.h
@@ -34,12 +34,12 @@ namespace storm {
             }
             
             bool foundSolution() const override {
-                assert(mPerformedSmtLoop);
+                STORM_LOG_ASSERT(mPerformedSmtLoop, "SMT loop not performed.");
                 return mFoundSolution;
             }
             
             SubMDPPermissiveScheduler<RM> getScheduler() const override {
-                assert(foundSolution());
+                STORM_LOG_ASSERT(foundSolution(), "Solution not found.");
                 SubMDPPermissiveScheduler<RM> result(this->mdp, true);
                 for(auto const& entry : multistrategyVariables) {
                     if(!multistrategyVariablesToTakenMap.at(entry.second)) {
@@ -98,9 +98,9 @@ namespace storm {
                 // (4) and (7) are omitted on purpose (-- we currenty do not support controllability of actions -- )
                 
                 // (1)
-                assert(this->mdp.getInitialStates().getNumberOfSetBits() == 1);
+                STORM_LOG_ASSERT(this->mdp.getInitialStates().getNumberOfSetBits() == 1, "No unique initial state.");
                 uint_fast64_t initialStateIndex = this->mdp.getInitialStates().getNextSetIndex(0);
-                assert(relevantStates[initialStateIndex]);
+                STORM_LOG_ASSERT(relevantStates[initialStateIndex], "Initial state not relevant.");
                 if(lowerBound) {
                     solver.add(mProbVariables[initialStateIndex] >= manager.rational(boundary));
                 } else {
@@ -162,9 +162,9 @@ namespace storm {
 //                                    std::string satstring = to_string(sat);
 //                                    // (8)
 //                                    if(relevantStates[entry.getColumn()]) {
-//                                        assert(mGammaVariables.count(entry.getColumn()) > 0);
-//                                        assert(mGammaVariables.count(s) > 0);
-//                                        assert(mBetaVariables.count(sat) > 0);
+//                                        STORM_LOG_ASSERT(mGammaVariables.count(entry.getColumn()) > 0, "Entry not found.");
+//                                        STORM_LOG_ASSERT(mGammaVariables.count(s) > 0, "Entry not found.");
+//                                        STORM_LOG_ASSERT(mBetaVariables.count(sat) > 0, "Entry not found.");
 //                                        solver.addConstraint("c8-" + satstring, mGammaVariables[entry.getColumn()] < mGammaVariables[s] + (solver.getConstant(1) - mBetaVariables[sat]) + mProbVariables[s]); // With rewards, we have to change this.
 //                                    }
 //                                }
diff --git a/src/solver/MinMaxLinearEquationSolver.h b/src/solver/MinMaxLinearEquationSolver.h
index 71ea10ee2..a9c497d45 100644
--- a/src/solver/MinMaxLinearEquationSolver.h
+++ b/src/solver/MinMaxLinearEquationSolver.h
@@ -102,7 +102,7 @@ namespace storm {
              * Can only be called after the direction has been set.
              */
             virtual void solveEquationSystem(std::vector<ValueType>& x, std::vector<ValueType> const& b, std::vector<ValueType>* multiplyResult = nullptr, std::vector<ValueType>* newX = nullptr) const {
-                assert(isSet(this->direction));
+                STORM_LOG_ASSERT(isSet(this->direction), "Direction not set.");
                 solveEquationSystem(convert(this->direction), x, b, multiplyResult, newX);
             }
             
diff --git a/src/solver/OptimizationDirection.cpp b/src/solver/OptimizationDirection.cpp
index cd88657b9..71d0760ed 100644
--- a/src/solver/OptimizationDirection.cpp
+++ b/src/solver/OptimizationDirection.cpp
@@ -1,6 +1,6 @@
 #include "OptimizationDirection.h"
 #include <iostream>
-#include <cassert>
+#include "src/utility/macros.h"
 
 namespace storm {
     namespace solver {
@@ -18,7 +18,7 @@ namespace storm {
         }
         
         OptimizationDirection convert(OptimizationDirectionSetting s) {
-            assert(isSet(s));
+            STORM_LOG_ASSERT(isSet(s), "Setting is not set.");
             return static_cast<OptimizationDirection>(s);
         }
         
diff --git a/src/solver/stateelimination/StateEliminator.cpp b/src/solver/stateelimination/StateEliminator.cpp
index 01dc8a5af..6189cb2b0 100644
--- a/src/solver/stateelimination/StateEliminator.cpp
+++ b/src/solver/stateelimination/StateEliminator.cpp
@@ -70,7 +70,7 @@ namespace storm {
                     
                     // Skip the state itself as one of its predecessors.
                     if (predecessor == state) {
-                        assert(hasSelfLoop);
+                        STORM_LOG_ASSERT(hasSelfLoop, "State has no self loop.");
                         continue;
                     }
                     
diff --git a/src/storage/FlexibleSparseMatrix.cpp b/src/storage/FlexibleSparseMatrix.cpp
index 2e3a4e876..5ee31060e 100644
--- a/src/storage/FlexibleSparseMatrix.cpp
+++ b/src/storage/FlexibleSparseMatrix.cpp
@@ -51,15 +51,15 @@ namespace storm {
         
         template<typename ValueType>
         typename FlexibleSparseMatrix<ValueType>::row_type& FlexibleSparseMatrix<ValueType>::getRow(index_type rowGroup, index_type offset) {
-            assert(rowGroup < this->getRowGroupCount());
-            assert(offset < this->getRowGroupSize(rowGroup));
+            STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Invalid rowGroup.");
+            STORM_LOG_ASSERT(offset < this->getRowGroupSize(rowGroup), "Invalid offset.");
             return getRow(rowGroupIndices[rowGroup] + offset);
         }
         
         template<typename ValueType>
         typename FlexibleSparseMatrix<ValueType>::row_type const& FlexibleSparseMatrix<ValueType>::getRow(index_type rowGroup, index_type offset) const {
-            assert(rowGroup < this->getRowGroupCount());
-            assert(offset < this->getRowGroupSize(rowGroup));
+            STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Invalid rowGroup.");
+            STORM_LOG_ASSERT(offset < this->getRowGroupSize(rowGroup), "Invalid offset.");
             return getRow(rowGroupIndices[rowGroup] + offset);
         }
         
@@ -112,7 +112,7 @@ namespace storm {
             this->columnCount = 0;
             for (auto const& row : this->data) {
                 for (auto const& element : row) {
-                    assert(!storm::utility::isZero(element.getValue()));
+                    STORM_LOG_ASSERT(!storm::utility::isZero(element.getValue()), "Entry is 0.");
                     ++this->nonzeroEntryCount;
                     this->columnCount = std::max(element.getColumn() + 1, this->columnCount);
                 }
@@ -252,4 +252,4 @@ namespace storm {
 #endif
 
     } // namespace storage
-} // namespace storm
\ No newline at end of file
+} // namespace storm
diff --git a/src/storage/SparseMatrix.cpp b/src/storage/SparseMatrix.cpp
index bfed8f49c..4b763e383 100644
--- a/src/storage/SparseMatrix.cpp
+++ b/src/storage/SparseMatrix.cpp
@@ -277,9 +277,9 @@ namespace storm {
                 }
                 maxColumn = std::max(maxColumn, elem.getColumn());
             }
-            assert(changed || highestColumn == maxColumn);
+            STORM_LOG_ASSERT(changed || highestColumn == maxColumn, "Incorrect maximal column.");
             highestColumn = maxColumn;
-            assert(changed || lastColumn == columnsAndValues[columnsAndValues.size() - 1].getColumn());
+            STORM_LOG_ASSERT(changed || lastColumn == columnsAndValues[columnsAndValues.size() - 1].getColumn(), "Incorrect last column.");
             lastColumn = columnsAndValues[columnsAndValues.size() - 1].getColumn();
             
             if (changed) {
@@ -305,10 +305,10 @@ namespace storm {
                                       return a.getColumn() < b.getColumn();
                                   });
                         // Assert no equal elements
-                        assert(std::is_sorted(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows,
+                        STORM_LOG_ASSERT(std::is_sorted(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows,
                                               [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) {
                                                   return a.getColumn() <= b.getColumn();
-                                              }));
+                                              }), "Columns not sorted.");
                     }
                 }
             } else {
@@ -320,10 +320,10 @@ namespace storm {
                                   return a.getColumn() < b.getColumn();
                               });
                     // Assert no equal elements
-                    assert(std::is_sorted(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows,
+                    STORM_LOG_ASSERT(std::is_sorted(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows,
                                           [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) {
                                               return a.getColumn() <= b.getColumn();
-                                          }));
+                                          }), "Columns not sorted.");
                 }
 
             }
@@ -1368,7 +1368,7 @@ namespace storm {
         void SparseMatrix<ValueType>::printAsMatlabMatrix(std::ostream& out) const {
             // Iterate over all row groups.
             for (typename SparseMatrix<ValueType>::index_type group = 0; group < this->getRowGroupCount(); ++group) {
-                assert(this->getRowGroupSize(group) == 1);
+                STORM_LOG_ASSERT(this->getRowGroupSize(group) == 1, "Incorrect row group size.");
                 for (typename SparseMatrix<ValueType>::index_type i = this->getRowGroupIndices()[group]; i < this->getRowGroupIndices()[group + 1]; ++i) {
                     typename SparseMatrix<ValueType>::index_type nextIndex = this->rowIndications[i];
                     
diff --git a/src/storage/SparseMatrix.h b/src/storage/SparseMatrix.h
index 374859af5..c170d43a9 100644
--- a/src/storage/SparseMatrix.h
+++ b/src/storage/SparseMatrix.h
@@ -11,6 +11,7 @@
 #include <boost/optional.hpp>
 
 #include "src/utility/OsDetection.h"
+#include "src/utility/macros.h"
 #include "src/adapters/CarlAdapter.h"
 
 // Forward declaration for adapter classes.
diff --git a/src/storage/bisimulation/BisimulationDecomposition.h b/src/storage/bisimulation/BisimulationDecomposition.h
index 6507e3b07..6d86f2df9 100644
--- a/src/storage/bisimulation/BisimulationDecomposition.h
+++ b/src/storage/bisimulation/BisimulationDecomposition.h
@@ -120,7 +120,7 @@ namespace storm {
                 }
                 
                 OptimizationDirection getOptimizationDirection() const {
-                    assert(optimalityType);
+                    STORM_LOG_ASSERT(optimalityType, "Optimality type not set.");
                     return optimalityType.get();
                 }
                 // A flag that indicates whether a measure driven initial partition is to be used. If this flag is set
diff --git a/src/storage/dft/DFT.cpp b/src/storage/dft/DFT.cpp
index 5c70c475d..5fdf44ab3 100644
--- a/src/storage/dft/DFT.cpp
+++ b/src/storage/dft/DFT.cpp
@@ -14,7 +14,7 @@ namespace storm {
 
         template<typename ValueType>
         DFT<ValueType>::DFT(DFTElementVector const& elements, DFTElementPointer const& tle) : mElements(elements), mNrOfBEs(0), mNrOfSpares(0), mTopLevelIndex(tle->id()), mMaxSpareChildCount(0) {
-            assert(elementIndicesCorrect());
+            STORM_LOG_ASSERT(elementIndicesCorrect(), "Ids incorrect.");
             size_t nrRepresentatives = 0;
             
             for (auto& elem : mElements) {
@@ -100,9 +100,9 @@ namespace storm {
             } else {
                 // Generate information according to symmetries
                 for (size_t symmetryIndex : symmetries.sortedSymmetries) {
-                    assert(!visited[symmetryIndex]);
+                    STORM_LOG_ASSERT(!visited[symmetryIndex], "Element already considered for symmetry.");
                     auto const& symmetryGroup = symmetries.groups.at(symmetryIndex);
-                    assert(!symmetryGroup.empty());
+                    STORM_LOG_ASSERT(!symmetryGroup.empty(), "No symmetry available.");
 
                     // Insert all elements of first subtree of each symmetry
                     size_t groupIndex = stateIndex;
@@ -117,14 +117,14 @@ namespace storm {
                     
                     // Mirror symmetries
                     size_t noSymmetricElements = symmetryGroup.front().size();
-                    assert(noSymmetricElements > 1);
+                    STORM_LOG_ASSERT(noSymmetricElements > 1, "No symmetry available.");
 
                     for (std::vector<size_t> symmetricElements : symmetryGroup) {
-                        assert(symmetricElements.size() == noSymmetricElements);
+                        STORM_LOG_ASSERT(symmetricElements.size() == noSymmetricElements, "No. of symmetric elements do not coincide.");
                         if (visited[symmetricElements[1]]) {
                             // Elements already mirrored
                             for (size_t index : symmetricElements) {
-                                assert(visited[index]);
+                                STORM_LOG_ASSERT(visited[index], "Element not mirrored.");
                             }
                             continue;
                         }
@@ -143,13 +143,13 @@ namespace storm {
                             generationInfo.addStateIndex(symmetricElement, index + offset * i);
                             stateIndex += 2;
 
-                            assert((activationIndex > 0) == isRepresentative(symmetricElement));
+                            STORM_LOG_ASSERT((activationIndex > 0) == isRepresentative(symmetricElement), "Bits for representative incorrect.");
                             if (activationIndex > 0) {
                                 generationInfo.addSpareActivationIndex(symmetricElement, activationIndex + offset * i);
                                 ++stateIndex;
                             }
 
-                            assert((usageIndex > 0) == mElements[symmetricElement]->isSpareGate());
+                            STORM_LOG_ASSERT((usageIndex > 0) == mElements[symmetricElement]->isSpareGate(), "Bits for usage incorrect.");
                             if (usageIndex > 0) {
                                 generationInfo.addSpareUsageIndex(symmetricElement, usageIndex + offset * i);
                                 stateIndex += generationInfo.usageInfoBits();
@@ -187,15 +187,15 @@ namespace storm {
             generationInfo.generateSymmetries(symmetries);
 
             STORM_LOG_TRACE(generationInfo);
-            assert(stateIndex == mStateVectorSize);
-            assert(visited.full());
+            STORM_LOG_ASSERT(stateIndex == mStateVectorSize, "Id incorrect.");
+            STORM_LOG_ASSERT(visited.full(), "Not all elements considered.");
             
             return generationInfo;
         }
         
         template<typename ValueType>
         size_t DFT<ValueType>::generateStateInfo(DFTStateGenerationInfo& generationInfo, size_t id, storm::storage::BitVector& visited, size_t stateIndex) const {
-            assert(!visited[id]);
+            STORM_LOG_ASSERT(!visited[id], "Element already visited.");
             visited.set(id);
             
             // Reserve bits for element
@@ -238,7 +238,7 @@ namespace storm {
         
         template<typename ValueType>
         std::vector<DFT<ValueType>>  DFT<ValueType>::topModularisation() const {
-            assert(isGate(mTopLevelIndex));
+            STORM_LOG_ASSERT(isGate(mTopLevelIndex), "Top level element is no gate.");
             auto const& children = getGate(mTopLevelIndex)->children();
             std::map<size_t, std::vector<size_t>> subdfts;
             for(auto const& child : children) {
@@ -250,7 +250,7 @@ namespace storm {
                 if (isGate(child->id())) {
                     isubdft = getGate(child->id())->independentSubDft(false);
                 } else {
-                    assert(isBasicElement(child->id()));
+                    STORM_LOG_ASSERT(isBasicElement(child->id()), "Child is no BE.");
                     if(getBasicElement(child->id())->hasIngoingDependencies()) {
                         STORM_LOG_TRACE("child " << child->name() << "does not allow modularisation.");
                         return {*this};
@@ -309,16 +309,16 @@ namespace storm {
             
             // Add rewritten elements
             for (std::vector<size_t> rewrites : rewriteIds) {
-                assert(rewrites.size() > 1);
-                assert(mElements[rewrites[1]]->hasParents());
-                assert(mElements[rewrites[1]]->parents().front()->isGate());
+                STORM_LOG_ASSERT(rewrites.size() > 1, "No rewritten elements.");
+                STORM_LOG_ASSERT(mElements[rewrites[1]]->hasParents(), "Rewritten elements has no parents.");
+                STORM_LOG_ASSERT(mElements[rewrites[1]]->parents().front()->isGate(), "Rewritten element has no parent gate.");
                 DFTGatePointer originalParent = std::static_pointer_cast<DFTGate<ValueType>>(mElements[rewrites[1]]->parents().front());
                 std::string newParentName = builder.getUniqueName(originalParent->name());
                 
                 // Accumulate children names
                 std::vector<std::string> childrenNames;
                 for (size_t i = 1; i < rewrites.size(); ++i) {
-                    assert(mElements[rewrites[i]]->parents().front()->id() == originalParent->id()); // Children have the same father
+                    STORM_LOG_ASSERT(mElements[rewrites[i]]->parents().front()->id() == originalParent->id(), "Children have the same father");
                     childrenNames.push_back(mElements[rewrites[i]]->name());
                 }
                 
@@ -390,7 +390,7 @@ namespace storm {
                 stream << "}" << std::endl;
                 return stream.str();
             }
-            assert(it != mTopModule.end());
+            STORM_LOG_ASSERT(it != mTopModule.end(), "Element not found.");
             stream << mElements[(*it)]->name();
             ++it;
             while(it != mTopModule.end()) {
@@ -403,7 +403,7 @@ namespace storm {
                 stream << "[" << mElements[spareModule.first]->name() << "] = {";
                 if (!spareModule.second.empty()) {
                     std::vector<size_t>::const_iterator it = spareModule.second.begin();
-                    assert(it != spareModule.second.end());
+                    STORM_LOG_ASSERT(it != spareModule.second.end(), "Element not found.");
                     stream << mElements[(*it)]->name();
                     ++it;
                     while(it != spareModule.second.end()) {
@@ -494,13 +494,13 @@ namespace storm {
         
         template<typename ValueType>
         size_t DFT<ValueType>::getChild(size_t spareId, size_t nrUsedChild) const {
-            assert(mElements[spareId]->isSpareGate());
+            STORM_LOG_ASSERT(mElements[spareId]->isSpareGate(), "Element is no spare.");
             return getGate(spareId)->children()[nrUsedChild]->id();
         }
         
         template<typename ValueType>
         size_t DFT<ValueType>::getNrChild(size_t spareId, size_t childId) const {
-            assert(mElements[spareId]->isSpareGate());
+            STORM_LOG_ASSERT(mElements[spareId]->isSpareGate(), "Element is no spare.");
             DFTElementVector children = getGate(spareId)->children();
             for (size_t nrChild = 0; nrChild < children.size(); ++nrChild) {
                 if (children[nrChild]->id() == childId) {
@@ -551,8 +551,8 @@ namespace storm {
                 }
             }
             
-            assert(isGate(index1));
-            assert(isGate(index2));
+            STORM_LOG_ASSERT(isGate(index1), "Element is no gate.");
+            STORM_LOG_ASSERT(isGate(index2), "Element is no gate.");
             std::vector<size_t> isubdft1 = getGate(index1)->independentSubDft(false);
             std::vector<size_t> isubdft2 = getGate(index2)->independentSubDft(false);
             if(isubdft1.empty() || isubdft2.empty() || isubdft1.size() != isubdft2.size()) {
@@ -591,7 +591,7 @@ namespace storm {
                                 size_t childLeftId = spareLeft->children().at(i)->id();
                                 size_t childRightId = spareRight->children().at(i)->id();
 
-                                assert(bijection.count(childLeftId) == 0);
+                                STORM_LOG_ASSERT(bijection.count(childLeftId) == 0, "Child already part of bijection.");
                                 if (childLeftId == childRightId) {
                                     // Ignore shared child
                                     continue;
diff --git a/src/storage/dft/DFT.h b/src/storage/dft/DFT.h
index 6fdfd08ef..7b0177d07 100644
--- a/src/storage/dft/DFT.h
+++ b/src/storage/dft/DFT.h
@@ -118,7 +118,7 @@ namespace storm {
                 if(representativeId == mTopLevelIndex) {
                     return mTopModule;
                 } else {
-                    assert(mSpareModules.count(representativeId)>0);
+                    STORM_LOG_ASSERT(mSpareModules.count(representativeId) > 0, "Representative not found.");
                     return mSpareModules.find(representativeId)->second;
                 }
             }
@@ -145,7 +145,7 @@ namespace storm {
              *  @param index The id of the element
              */
             DFTElementCPointer getElement(size_t index) const {
-                assert(index < nrElements());
+                STORM_LOG_ASSERT(index < nrElements(), "Index invalid.");
                 return mElements[index];
             }
 
@@ -166,7 +166,7 @@ namespace storm {
             }
 
             std::shared_ptr<DFTBE<ValueType> const> getBasicElement(size_t index) const {
-                assert(isBasicElement(index));
+                STORM_LOG_ASSERT(isBasicElement(index), "Element is no BE.");
                 return std::static_pointer_cast<DFTBE<ValueType> const>(mElements[index]);
             }
 
@@ -175,17 +175,17 @@ namespace storm {
             }
             
             std::shared_ptr<DFTGate<ValueType> const> getGate(size_t index) const {
-                assert(isGate(index));
+                STORM_LOG_ASSERT(isGate(index), "Element is no gate.");
                 return std::static_pointer_cast<DFTGate<ValueType> const>(mElements[index]);
             }
 
             std::shared_ptr<DFTDependency<ValueType> const> getDependency(size_t index) const {
-                assert(isDependency(index));
+                STORM_LOG_ASSERT(isDependency(index), "Element is no dependency.");
                 return std::static_pointer_cast<DFTDependency<ValueType> const>(mElements[index]);
             }
             
             std::shared_ptr<DFTRestriction<ValueType> const> getRestriction(size_t index) const {
-                assert(isRestriction(index));
+                STORM_LOG_ASSERT(isRestriction(index), "Element is no restriction.");
                 return std::static_pointer_cast<DFTRestriction<ValueType> const>(mElements[index]);
             }
 
@@ -215,7 +215,7 @@ namespace storm {
             }
 
             DFTElementCPointer getRepresentant(size_t id) const {
-                assert(hasRepresentant(id));
+                STORM_LOG_ASSERT(hasRepresentant(id), "Element has no representant.");
                 return getElement(mRepresentants.find(id)->second);
             }
 
diff --git a/src/storage/dft/DFTElementState.h b/src/storage/dft/DFTElementState.h
index d191cc2d9..548eb6c88 100644
--- a/src/storage/dft/DFTElementState.h
+++ b/src/storage/dft/DFTElementState.h
@@ -2,7 +2,7 @@
 #ifndef DFTELEMENTSTATE_H
 #define	DFTELEMENTSTATE_H
 
-#include <cassert>
+#include "src/utility/macros.h"
 
 namespace storm {
     namespace storage {
@@ -18,8 +18,10 @@ namespace storm {
                     return os << "Failsafe";
                 case DFTElementState::DontCare:
                     return os << "Don't Care";
+                default:
+                    STORM_LOG_ASSERT(false, "Element state not known.");
+                    return os;
             }
-            assert(false);
         }
         
         inline char toChar(DFTElementState st) {
@@ -32,8 +34,10 @@ namespace storm {
                     return 'S';
                 case DFTElementState::DontCare:
                     return '-';
+                default:
+                    STORM_LOG_ASSERT(false, "Element state not known.");
+                    return ' ';
             }
-            assert(false);
         }
         
         enum class DFTDependencyState {Passive = 0, Unsuccessful = 1, Successful = 2, DontCare = 3};
@@ -48,8 +52,10 @@ namespace storm {
                     return os << "Unsuccessful";
                 case DFTDependencyState::DontCare:
                     return os << "Don't Care";
+                default:
+                    STORM_LOG_ASSERT(false, "Element state not known.");
+                    return os;
             }
-            assert(false);
         }
         
         inline char toChar(DFTDependencyState st) {
@@ -62,8 +68,10 @@ namespace storm {
                     return 'U';
                 case DFTDependencyState::DontCare:
                     return '-';
+                default:
+                    STORM_LOG_ASSERT(false, "Element state not known.");
+                    return ' ';
             }
-            assert(false);
         }
 
     }
diff --git a/src/storage/dft/DFTIsomorphism.h b/src/storage/dft/DFTIsomorphism.h
index d94640d9c..1f66e5449 100644
--- a/src/storage/dft/DFTIsomorphism.h
+++ b/src/storage/dft/DFTIsomorphism.h
@@ -1,6 +1,5 @@
 #pragma once
 
-#include <cassert>
 #include <vector>
 #include <unordered_map>
 #include <utility>
@@ -197,7 +196,7 @@ namespace storage {
                 } else if(dft.isDependency(id)) {
                     colourize(dft.getDependency(id));
                 } else {
-                    assert(dft.isRestriction(id));
+                    STORM_LOG_ASSERT(dft.isRestriction(id), "Element is no restriction.");
                     colourize(dft.getRestriction(id));
                 }
             }
@@ -233,7 +232,7 @@ namespace storage {
                         res.pdepCandidates[depColour.at(index)] = std::vector<size_t>({index});
                     }
                 } else {
-                    assert(dft.isRestriction(index));
+                    STORM_LOG_ASSERT(dft.isRestriction(index), "Element is no restriction.");
                     auto it = res.restrictionCandidates.find(restrictionColour.at(index));
                     if(it != res.restrictionCandidates.end()) {
                         it->second.push_back(index);
@@ -342,14 +341,14 @@ namespace storage {
          * Construct the initial bijection.
          */
         void constructInitialBijection() {
-            assert(candidatesCompatible);
+            STORM_LOG_ASSERT(candidatesCompatible, "Candidates are not compatible.");
             // We first construct the currentPermutations, which helps to determine the current state of the check.
             initializePermutationsAndTreatTrivialGroups(bleft.beCandidates, bright.beCandidates, currentPermutations.beCandidates);
             initializePermutationsAndTreatTrivialGroups(bleft.gateCandidates, bright.gateCandidates, currentPermutations.gateCandidates);
             initializePermutationsAndTreatTrivialGroups(bleft.pdepCandidates, bright.pdepCandidates, currentPermutations.pdepCandidates);
             initializePermutationsAndTreatTrivialGroups(bleft.restrictionCandidates, bright.restrictionCandidates, currentPermutations.restrictionCandidates);
             STORM_LOG_TRACE(bijection.size() << " vs. " << bleft.size() << " vs. " << bright.size());
-            assert(bijection.size() == bleft.size());
+            STORM_LOG_ASSERT(bijection.size() == bleft.size(), "No. of bijection elements do not match.");
             
         }
 
@@ -358,7 +357,7 @@ namespace storage {
          * @return true if a next bijection exists.
          */
         bool findNextBijection() {
-            assert(candidatesCompatible);
+            STORM_LOG_ASSERT(candidatesCompatible, "Candidates are not compatible.");
             bool foundNext = false;
             if(!currentPermutations.beCandidates.empty()) {
                 auto it = currentPermutations.beCandidates.begin();
@@ -395,28 +394,28 @@ namespace storage {
             if(foundNext) {
                 for(auto const& colour : bleft.beCandidates) {
                     if (colour.second.size() > 1) {
-                        assert(currentPermutations.beCandidates.find(colour.first) != currentPermutations.beCandidates.end());
+                        STORM_LOG_ASSERT(currentPermutations.beCandidates.find(colour.first) != currentPermutations.beCandidates.end(), "Colour not found.");
                         zipVectorsIntoMap(colour.second, currentPermutations.beCandidates.find(colour.first)->second, bijection);
                     }
                 }
 
                 for(auto const& colour : bleft.gateCandidates) {
                     if (colour.second.size() > 1) {
-                        assert(currentPermutations.gateCandidates.find(colour.first) != currentPermutations.gateCandidates.end());
+                        STORM_LOG_ASSERT(currentPermutations.gateCandidates.find(colour.first) != currentPermutations.gateCandidates.end(), "Colour not found.");
                         zipVectorsIntoMap(colour.second, currentPermutations.gateCandidates.find(colour.first)->second, bijection);
                     }
                 }
 
                 for(auto const& colour : bleft.pdepCandidates) {
                     if (colour.second.size() > 1) {
-                        assert(currentPermutations.pdepCandidates.find(colour.first) != currentPermutations.pdepCandidates.end());
+                        STORM_LOG_ASSERT(currentPermutations.pdepCandidates.find(colour.first) != currentPermutations.pdepCandidates.end(), "Colour not found.");
                         zipVectorsIntoMap(colour.second, currentPermutations.pdepCandidates.find(colour.first)->second, bijection);
                     }
                 }
                 
                 for(auto const& colour : bleft.restrictionCandidates) {
                     if (colour.second.size() > 1) {
-                        assert(currentPermutations.restrictionCandidates.find(colour.first) != currentPermutations.restrictionCandidates.end());
+                        STORM_LOG_ASSERT(currentPermutations.restrictionCandidates.find(colour.first) != currentPermutations.restrictionCandidates.end(), "Colour not found.");
                         zipVectorsIntoMap(colour.second, currentPermutations.restrictionCandidates.find(colour.first)->second, bijection);
                     }
                 }
@@ -430,13 +429,13 @@ namespace storage {
          *
          */
         bool check() const {
-            assert(bijection.size() == bleft.size());
+            STORM_LOG_ASSERT(bijection.size() == bleft.size(), "No. of bijection elements do not match.");
             // We can skip BEs, as they are identified by they're homomorphic if they are in the same class
             for(auto const& indexpair : bijection) {
                 // Check type first. Colouring takes care of a lot, but not necesarily everything (e.g. voting thresholds)
                 equalType(*dft.getElement(indexpair.first), *dft.getElement(indexpair.second));
                 if(dft.isGate(indexpair.first)) {
-                    assert(dft.isGate(indexpair.second));
+                    STORM_LOG_ASSERT(dft.isGate(indexpair.second), "Element is no gate.");
                     auto const& lGate = dft.getGate(indexpair.first);
                     auto const& rGate = dft.getGate(indexpair.second);
                     if(lGate->isDynamicGate()) {
@@ -483,7 +482,7 @@ namespace storage {
                 
                     
                 } else if(dft.isDependency(indexpair.first)) {
-                    assert(dft.isDependency(indexpair.second));
+                    STORM_LOG_ASSERT(dft.isDependency(indexpair.second), "Element is no dependency.");
                     auto const& lDep = dft.getDependency(indexpair.first);
                     auto const& rDep = dft.getDependency(indexpair.second);
                     if(bijection.at(lDep->triggerEvent()->id()) != rDep->triggerEvent()->id()) {
@@ -493,7 +492,7 @@ namespace storage {
                         return false;
                     }
                 } else if(dft.isRestriction(indexpair.first)) {
-                    assert(dft.isRestriction(indexpair.second));
+                    STORM_LOG_ASSERT(dft.isRestriction(indexpair.second), "Element is no restriction.");
                     auto const& lRestr = dft.getRestriction(indexpair.first);
                     std::vector<size_t> childrenLeftMapped;
                     for(auto const& child : lRestr->children() ) {
@@ -521,8 +520,8 @@ namespace storage {
                     }
                 }
                 else {
-                    assert(dft.isBasicElement(indexpair.first));
-                    assert(dft.isBasicElement(indexpair.second));
+                    STORM_LOG_ASSERT(dft.isBasicElement(indexpair.first), "Element is no BE.");
+                    STORM_LOG_ASSERT(dft.isBasicElement(indexpair.second), "Element is no BE.");
                     // No operations required.
                 }
             }
@@ -590,12 +589,12 @@ namespace storage {
             for(auto const& colour : right) {
                 if(colour.second.size()>1) {
                     auto it = permutations.insert(colour);
-                    assert(it.second);
+                    STORM_LOG_ASSERT(it.second, "Element already contained.");
                     std::sort(it.first->second.begin(), it.first->second.end());
                     zipVectorsIntoMap(left.at(colour.first), it.first->second, bijection);
                 } else {
-                    assert(colour.second.size() == 1);
-                    assert(bijection.count(left.at(colour.first).front()) == 0);
+                    STORM_LOG_ASSERT(colour.second.size() == 1, "No elements for colour.");
+                    STORM_LOG_ASSERT(bijection.count(left.at(colour.first).front()) == 0, "Element already contained.");
                     bijection[left.at(colour.first).front()] = colour.second.front();
                 }
             }
@@ -606,7 +605,7 @@ namespace storage {
          */
         void zipVectorsIntoMap(std::vector<size_t> const& a, std::vector<size_t> const& b, std::map<size_t, size_t>& map) const {
             // Assert should pass due to compatibility check
-            assert(a.size() == b.size());
+            STORM_LOG_ASSERT(a.size() == b.size(), "Sizes do not match.");
             auto it = b.cbegin();
             for(size_t lIndex : a) {
                 map[lIndex] = *it;
@@ -638,4 +637,4 @@ namespace std {
             return hasher(p.first) ^ hasher(p.second);
         }
     };
-}
\ No newline at end of file
+}
diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index 25edf1d38..9a0a16dba 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -11,8 +11,8 @@ namespace storm {
             // Initialize uses
             for(size_t id  : mDft.getSpareIndices()) {
                 std::shared_ptr<DFTGate<ValueType> const> elem = mDft.getGate(id);
-                assert(elem->isSpareGate());
-                assert(elem->nrChildren() > 0);
+                STORM_LOG_ASSERT(elem->isSpareGate(), "Element is no spare gate.");
+                STORM_LOG_ASSERT(elem->nrChildren() > 0, "Element has no child.");
                 this->setUses(id, elem->children()[0]->id());
             }
             
@@ -47,7 +47,7 @@ namespace storm {
             // Initialize failable dependencies
             for (size_t dependencyId : mDft.getDependencies()) {
                 std::shared_ptr<DFTDependency<ValueType> const> dependency = mDft.getDependency(dependencyId);
-                assert(dependencyId == dependency->id());
+                STORM_LOG_ASSERT(dependencyId == dependency->id(), "Ids do not match.");
                 if (hasFailed(dependency->triggerEvent()->id()) && getElementState(dependency->dependentEvent()->id()) == DFTElementState::Operational) {
                     mFailableDependencies.push_back(dependencyId);
                     STORM_LOG_TRACE("New dependency failure: " << dependency->toString());
@@ -182,9 +182,9 @@ namespace storm {
             }
             
             for (auto dependency : mDft.getElement(id)->outgoingDependencies()) {
-                assert(dependency->triggerEvent()->id() == id);
+                STORM_LOG_ASSERT(dependency->triggerEvent()->id() == id, "Ids do not match.");
                 if (getElementState(dependency->dependentEvent()->id()) == DFTElementState::Operational) {
-                    assert(!isFailsafe(dependency->dependentEvent()->id()));
+                    STORM_LOG_ASSERT(!isFailsafe(dependency->dependentEvent()->id()), "Dependent event is failsafe.");
                     mFailableDependencies.push_back(dependency->id());
                     STORM_LOG_TRACE("New dependency failure: " << dependency->toString());
                 }
@@ -194,11 +194,11 @@ namespace storm {
         
         template<typename ValueType>
         void DFTState<ValueType>::updateDontCareDependencies(size_t id) {
-            assert(mDft.isBasicElement(id));
-            assert(hasFailed(id));
+            STORM_LOG_ASSERT(mDft.isBasicElement(id), "Element is no BE.");
+            STORM_LOG_ASSERT(hasFailed(id), "Element has not failed.");
             
             for (auto dependency : mDft.getBasicElement(id)->ingoingDependencies()) {
-                assert(dependency->dependentEvent()->id() == id);
+                STORM_LOG_ASSERT(dependency->dependentEvent()->id() == id, "Ids do not match.");
                 setDependencyDontCare(dependency->id());
             }
         }
@@ -209,7 +209,7 @@ namespace storm {
             STORM_LOG_TRACE("currently failable: " << getCurrentlyFailableString());
             if (nrFailableDependencies() > 0) {
                 // Consider failure due to dependency
-                assert(index < nrFailableDependencies());
+                STORM_LOG_ASSERT(index < nrFailableDependencies(), "Index invalid.");
                 std::shared_ptr<DFTDependency<ValueType> const> dependency = mDft.getDependency(mFailableDependencies[index]);
                 std::pair<std::shared_ptr<DFTBE<ValueType> const>,bool> res(mDft.getBasicElement(dependency->dependentEvent()->id()), true);
                 mFailableDependencies.erase(mFailableDependencies.begin() + index);
@@ -218,9 +218,9 @@ namespace storm {
                 return res;
             } else {
                 // Consider "normal" failure
-                assert(index < nrFailableBEs());
+                STORM_LOG_ASSERT(index < nrFailableBEs(), "Index invalid.");
                 std::pair<std::shared_ptr<DFTBE<ValueType> const>,bool> res(mDft.getBasicElement(mIsCurrentlyFailableBE[index]), false);
-                assert(res.first->canFail());
+                STORM_LOG_ASSERT(res.first->canFail(), "Element cannot fail.");
                 mIsCurrentlyFailableBE.erase(mIsCurrentlyFailableBE.begin() + index);
                 setFailed(res.first->id());
                 return res;
@@ -229,7 +229,7 @@ namespace storm {
  
         template<typename ValueType>
         void DFTState<ValueType>::letDependencyBeUnsuccessful(size_t index) {
-            assert(nrFailableDependencies() > 0 && index < nrFailableDependencies());
+            STORM_LOG_ASSERT(nrFailableDependencies() > 0 && index < nrFailableDependencies(), "Index invalid.");
             std::shared_ptr<DFTDependency<ValueType> const> dependency = mDft.getDependency(getDependencyId(index));
             mFailableDependencies.erase(mFailableDependencies.begin() + index);
             setDependencyUnsuccessful(dependency->id());
@@ -243,7 +243,7 @@ namespace storm {
 
         template<typename ValueType>
         bool DFTState<ValueType>::isActive(size_t id) const {
-            assert(mDft.isRepresentative(id));
+            STORM_LOG_ASSERT(mDft.isRepresentative(id), "Element is no representative.");
             return mStatus[mStateGenerationInfo.getSpareActivationIndex(id)];
         }
             
@@ -277,7 +277,7 @@ namespace storm {
 
         template<typename ValueType>
         uint_fast64_t DFTState<ValueType>::extractUses(size_t from) const {
-            assert(mStateGenerationInfo.usageInfoBits() < 64);
+            STORM_LOG_ASSERT(mStateGenerationInfo.usageInfoBits() < 64, "UsageInfoBit size too large.");
             return mStatus.getAsInt(from, mStateGenerationInfo.usageInfoBits());
         }
 
@@ -294,14 +294,14 @@ namespace storm {
         
         template<typename ValueType>
         void DFTState<ValueType>::finalizeUses(size_t spareId) {
-            assert(hasFailed(spareId));
+            STORM_LOG_ASSERT(hasFailed(spareId), "Spare has not failed.");
             mStatus.setFromInt(mStateGenerationInfo.getSpareUsageIndex(spareId), mStateGenerationInfo.usageInfoBits(), mDft.getMaxSpareChildCount());
         }
         
         template<typename ValueType>
         bool DFTState<ValueType>::hasOperationalPostSeqElements(size_t id) const {
-            assert(!mDft.isDependency(id));
-            assert(!mDft.isRestriction(id));
+            STORM_LOG_ASSERT(!mDft.isDependency(id), "Element is dependency.");
+            STORM_LOG_ASSERT(!mDft.isRestriction(id), "Element is restriction.");
             auto const& postIds =  mStateGenerationInfo.seqRestrictionPostElements(id);
             for(size_t id : postIds) {
                 if(isOperational(id)) {
@@ -315,7 +315,7 @@ namespace storm {
         bool DFTState<ValueType>::claimNew(size_t spareId, size_t currentlyUses, std::vector<std::shared_ptr<DFTElement<ValueType>>> const& children) {
             auto it = children.begin();
             while ((*it)->id() != currentlyUses) {
-                assert(it != children.end());
+                STORM_LOG_ASSERT(it != children.end(), "Currently used element not found.");
                 ++it;
             }
             ++it;
@@ -377,4 +377,4 @@ namespace storm {
 #endif
 
     }
-}
\ No newline at end of file
+}
diff --git a/src/storage/dft/DFTState.h b/src/storage/dft/DFTState.h
index f647aae17..8562559b3 100644
--- a/src/storage/dft/DFTState.h
+++ b/src/storage/dft/DFTState.h
@@ -6,7 +6,6 @@
 
 #include <sstream>
 #include <memory>
-#include <cassert>
 
 namespace storm {
     namespace storage {
@@ -156,7 +155,7 @@ namespace storm {
              * @return Id of the dependency
              */
             size_t getDependencyId(size_t index) const {
-                assert(index < nrFailableDependencies());
+                STORM_LOG_ASSERT(index < nrFailableDependencies(), "Index invalid.");
                 return mFailableDependencies[index];
             }
 
diff --git a/src/storage/dft/DFTStateSpaceGenerationQueues.h b/src/storage/dft/DFTStateSpaceGenerationQueues.h
index 6ded7cb38..bd71b5fbf 100644
--- a/src/storage/dft/DFTStateSpaceGenerationQueues.h
+++ b/src/storage/dft/DFTStateSpaceGenerationQueues.h
@@ -55,7 +55,7 @@ namespace storm {
             }
             
             DFTRestrictionPointer nextRestrictionCheck() {
-                assert(!restrictionChecksDone());
+                STORM_LOG_ASSERT(!restrictionChecksDone(), "All restriction checks done already.");
                 DFTRestrictionPointer next = restrictionChecks.back();
                 restrictionChecks.pop_back();
                 return next;
diff --git a/src/storage/expressions/Variable.cpp b/src/storage/expressions/Variable.cpp
index aeb432f2a..5c9660b83 100644
--- a/src/storage/expressions/Variable.cpp
+++ b/src/storage/expressions/Variable.cpp
@@ -1,6 +1,5 @@
 #include "src/storage/expressions/Variable.h"
 #include "src/storage/expressions/ExpressionManager.h"
-#include <cassert>
 
 namespace storm {
     namespace expressions {
@@ -41,7 +40,7 @@ namespace storm {
         }
         
         ExpressionManager const& Variable::getManager() const {
-            assert(manager != nullptr);
+            STORM_LOG_ASSERT(manager != nullptr, "Manager is null.");
             return *manager;
         }
 
@@ -65,4 +64,4 @@ namespace storm {
             return this->getType().isNumericalType();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/storage/expressions/Variable.h b/src/storage/expressions/Variable.h
index 3ade039ed..79b430f65 100644
--- a/src/storage/expressions/Variable.h
+++ b/src/storage/expressions/Variable.h
@@ -6,6 +6,7 @@
 #include <functional>
 
 #include "src/utility/OsDetection.h"
+#include "src/utility/macros.h"
 
 namespace storm {
     namespace expressions {
@@ -155,4 +156,4 @@ namespace std {
     };
 }
 
-#endif /* STORM_STORAGE_EXPRESSIONS_VARIABLE_H_ */
\ No newline at end of file
+#endif /* STORM_STORAGE_EXPRESSIONS_VARIABLE_H_ */
diff --git a/src/storage/prism/Assignment.cpp b/src/storage/prism/Assignment.cpp
index a6c8b4456..7aa685a6d 100644
--- a/src/storage/prism/Assignment.cpp
+++ b/src/storage/prism/Assignment.cpp
@@ -1,5 +1,4 @@
 #include "Assignment.h"
-#include <cassert>
 
 namespace storm {
     namespace prism {
@@ -25,7 +24,7 @@ namespace storm {
         
         bool Assignment::isIdentity() const {
             if(this->expression.isVariable()) {
-                assert(this->expression.getVariables().size() == 1);
+                STORM_LOG_ASSERT(this->expression.getVariables().size() == 1, "Invalid number of variables.");
                 //if( variable == *(this->expression.getVariables().begin())) {
                 //    std::cout << variable.getName() << " == " << (this->expression.getVariables().begin())->getName() << std::endl;
                 //}
diff --git a/src/storage/prism/Command.cpp b/src/storage/prism/Command.cpp
index 5cad634e7..a5a59522d 100644
--- a/src/storage/prism/Command.cpp
+++ b/src/storage/prism/Command.cpp
@@ -1,5 +1,4 @@
 #include "Command.h"
-#include <cassert>
 
 namespace storm {
     namespace prism {
@@ -32,7 +31,7 @@ namespace storm {
         }
         
         storm::prism::Update const& Command::getUpdate(uint_fast64_t index) const {
-            assert(index < getNumberOfUpdates());
+            STORM_LOG_ASSERT(index < getNumberOfUpdates(), "Invalid index.");
             return this->updates[index];
         }
         
diff --git a/src/storage/prism/Program.cpp b/src/storage/prism/Program.cpp
index 0a7b11bd6..ca55258b3 100644
--- a/src/storage/prism/Program.cpp
+++ b/src/storage/prism/Program.cpp
@@ -1297,7 +1297,7 @@ namespace storm {
         }
 
         uint_fast64_t Program::largestActionIndex() const {
-            assert(numberOfActions() != 0);
+            STORM_LOG_ASSERT(numberOfActions() != 0, "No actions available.");
             return this->indexToActionMap.rbegin()->first;
         }
         
diff --git a/src/storm-dyftee.cpp b/src/storm-dyftee.cpp
index 3ffd665ad..4cfd1f58f 100644
--- a/src/storm-dyftee.cpp
+++ b/src/storm-dyftee.cpp
@@ -5,6 +5,7 @@
 #include "src/cli/cli.h"
 #include "src/exceptions/BaseException.h"
 #include "src/utility/macros.h"
+#include "src/builder/DftSmtBuilder.h"
 #include <boost/lexical_cast.hpp>
 
 #include "src/settings/modules/GeneralSettings.h"
@@ -44,6 +45,18 @@ void analyzeDFT(std::string filename, std::string property, bool symred = false,
     analyser.printResult();
 }
 
+template<typename ValueType>
+void analyzeWithSMT(std::string filename) {
+    std::cout << "Running DFT analysis on file " << filename << " with use of SMT" << std::endl;
+    
+    storm::parser::DFTGalileoParser<ValueType> parser;
+    storm::storage::DFT<ValueType> dft = parser.parseDFT(filename);
+    storm::builder::DFTSMTBuilder<ValueType> dftSmtBuilder;
+    dftSmtBuilder.convertToSMT(dft);
+    bool sat = dftSmtBuilder.check();
+    std::cout << "SMT result: " << sat << std::endl;
+}
+
 /*!
  * Initialize the settings manager.
  */
@@ -92,6 +105,22 @@ int main(const int argc, const char** argv) {
             STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "No input model.");
         }
         
+        bool parametric = false;
+#ifdef STORM_HAVE_CARL
+        parametric = generalSettings.isParametricSet();
+#endif
+        
+        if (dftSettings.solveWithSMT()) {
+            // Solve with SMT
+            if (parametric) {
+                analyzeWithSMT<storm::RationalFunction>(dftSettings.getDftFilename());
+            } else {
+                analyzeWithSMT<double>(dftSettings.getDftFilename());
+            }
+            storm::utility::cleanUp();
+            return 0;
+        }
+        
         // Set min or max
         bool minimal = true;
         if (dftSettings.isComputeMaximalValue()) {
@@ -132,11 +161,6 @@ int main(const int argc, const char** argv) {
         
         STORM_LOG_ASSERT(!pctlFormula.empty(), "Pctl formula empty.");
 
-        bool parametric = false;
-#ifdef STORM_HAVE_CARL
-        parametric = generalSettings.isParametricSet();
-#endif
-        
         // From this point on we are ready to carry out the actual computations.
         if (parametric) {
             analyzeDFT<storm::RationalFunction>(dftSettings.getDftFilename(), pctlFormula, dftSettings.useSymmetryReduction(), allowModular && dftSettings.useModularisation(), !dftSettings.isDisableDC() );

From bc10291680ce76a16785f9b64650954187c2127d Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Wed, 18 May 2016 14:53:37 +0200
Subject: [PATCH 02/65] STORM_DEVELOPER mode introduced

Former-commit-id: 22ff09ad8e779d0ed3f150b1da11978ab9cbb321
---
 CMakeLists.txt                                | 12 +++++------
 .../SparseDtmcEliminationModelChecker.cpp     |  4 ++++
 src/storage/BitVector.cpp                     | 20 +++++++++----------
 3 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 13ccb71fc..f2621cf4d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,7 +18,7 @@ include(ExternalProject)
 ##	CMake options of StoRM
 ##
 #############################################################
-option(STORM_DEBUG "Sets whether the DEBUG mode is used" ON)
+option(STORM_DEVELOPER "Sets whether the development mode is used" OFF)
 option(STORM_USE_POPCNT "Sets whether the popcnt instruction is going to be used." ON)
 option(USE_BOOST_STATIC_LIBRARIES "Sets whether the Boost libraries should be linked statically." ON)
 option(STORM_USE_INTELTBB "Sets whether the Intel TBB libraries should be used." OFF)
@@ -40,11 +40,11 @@ set(MSAT_ROOT "" CACHE STRING "The hint to the root directory of MathSAT (option
 set(ADDITIONAL_INCLUDE_DIRS "" CACHE STRING "Additional directories added to the include directories.")
 set(ADDITIONAL_LINK_DIRS "" CACHE STRING "Additional directories added to the link directories.")
 
-# If the DEBUG option was turned on, we will target a debug version and a release version otherwise.
-if (STORM_DEBUG)
-    set (CMAKE_BUILD_TYPE "DEBUG")
-else()
-    set (CMAKE_BUILD_TYPE "RELEASE")
+# If the STORM_DEVELOPER option was turned on, we will target a debug version.
+if (STORM_DEVELOPER)
+    message(STATUS "StoRM - Using development mode")
+    set(CMAKE_BUILD_TYPE "DEBUG" CACHE STRING "Set the build type" FORCE)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTORM_DEV")
 endif()
 message(STATUS "StoRM - Building ${CMAKE_BUILD_TYPE} version.")
 
diff --git a/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp b/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp
index 0f67cca4a..5a6045f66 100644
--- a/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp
+++ b/src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp
@@ -271,7 +271,9 @@ namespace storm {
             while (priorityQueue->hasNextState()) {
                 storm::storage::sparse::state_type state = priorityQueue->popNextState();
                 stateEliminator.eliminateState(state, true);
+#ifdef STORM_DEV
                 STORM_LOG_ASSERT(checkConsistent(flexibleMatrix, flexibleBackwardTransitions), "The forward and backward transition matrices became inconsistent.");
+#endif
             }
             
             // Now, we set the values of all states in BSCCs to that of the representative value (and clear the
@@ -903,7 +905,9 @@ namespace storm {
                 if (removeForwardTransitions) {
                     values[state] = storm::utility::zero<ValueType>();
                 }
+#ifdef STORM_DEV
                 STORM_LOG_ASSERT(checkConsistent(transitionMatrix, backwardTransitions), "The forward and backward transition matrices became inconsistent.");
+#endif
             }
         }
         
diff --git a/src/storage/BitVector.cpp b/src/storage/BitVector.cpp
index fcbceca7b..a60b8c10c 100644
--- a/src/storage/BitVector.cpp
+++ b/src/storage/BitVector.cpp
@@ -12,8 +12,8 @@
 
 #include <bitset>
 
-#ifndef NDEBUG
-//#define ASSERT_BITVECTOR
+#ifdef STORM_DEV
+#define ASSERT_BITVECTOR
 #endif
 
 namespace storm {
@@ -725,11 +725,11 @@ namespace storm {
                 if (result.get(i) != get(start + i)) {
                     STORM_LOG_ERROR("Getting of bits not correct for index " << i);
                     STORM_LOG_ERROR("Getting from " << start << " with length " << length);
-                    stringstream stream;
+                    std::stringstream stream;
                     printBits(stream);
                     stream << std::endl;
                     result.printBits(stream);
-                    STORM_LOG_ERROR(stream);
+                    STORM_LOG_ERROR(stream.str());
                     STORM_LOG_ASSERT(false, "Getting of bits not correct.");
                 }
             }
@@ -738,11 +738,11 @@ namespace storm {
                     if (original.get(i) != get(i)) {
                         STORM_LOG_ERROR("Getting did change bitvector at index " << i);
                         STORM_LOG_ERROR("Getting from " << start << " with length " << length);
-                        stringstream stream;
+                        std::stringstream stream;
                         printBits(stream);
                         stream << std::endl;
                         original.printBits(stream);
-                        STORM_LOG_ERROR(stream);
+                        STORM_LOG_ERROR(stream.str());
                         STORM_LOG_ASSERT(false, "Getting of bits not correct.");
                     }
                 }
@@ -818,11 +818,11 @@ namespace storm {
                 if (other.get(i) != get(start + i)) {
                     STORM_LOG_ERROR("Setting of bits not correct for index " << i);
                     STORM_LOG_ERROR("Setting from " << start << " with length " << other.bitCount);
-                    stringstream stream;
+                    std::stringstream stream;
                     printBits(stream);
                     stream << std::endl;
                     other.printBits(stream);
-                    STORM_LOG_ERROR(stream);
+                    STORM_LOG_ERROR(stream.str());
                     STORM_LOG_ASSERT(false, "Setting of bits not correct.");
                 }
             }
@@ -831,11 +831,11 @@ namespace storm {
                     if (original.get(i) != get(i)) {
                         STORM_LOG_ERROR("Setting did change bitvector at index " << i);
                         STORM_LOG_ERROR("Setting from " << start << " with length " << other.bitCount);
-                        stringstream stream;
+                        std::stringstream stream;
                         printBits(stream);
                         stream << std::endl;
                         original.printBits(stream);
-                        STORM_LOG_ERROR(stream);
+                        STORM_LOG_ERROR(stream.str());
                         STORM_LOG_ASSERT(false, "Setting of bits not correct.");
                     }
                 }

From fb5db51595994ff261e0bb36556711690a093c2f Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Wed, 18 May 2016 14:53:58 +0200
Subject: [PATCH 03/65] Missing include

Former-commit-id: 16d4ff67dcbf7cb8c74b873d7b69279b7f03ec69
---
 src/solver/MinMaxLinearEquationSolver.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/solver/MinMaxLinearEquationSolver.h b/src/solver/MinMaxLinearEquationSolver.h
index a9c497d45..6c547cf0c 100644
--- a/src/solver/MinMaxLinearEquationSolver.h
+++ b/src/solver/MinMaxLinearEquationSolver.h
@@ -14,6 +14,7 @@
 #include "src/solver/OptimizationDirection.h"
 
 #include "src/exceptions/InvalidSettingsException.h"
+#include "src/utility/macros.h"
 
 namespace storm {
     namespace storage {

From 493407f74f82e92d053bbeee5ca144bf0a8dd037 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Wed, 18 May 2016 16:27:48 +0200
Subject: [PATCH 04/65] Started with SMT encoding for DFTs

Former-commit-id: a2a68cee6ac0385b2653280d295bb482b1b412f6
---
 src/builder/DftSmtBuilder.cpp        | 120 +++++++++++++++++++++++++++
 src/builder/DftSmtBuilder.h          |  49 +++++++++++
 src/settings/modules/DFTSettings.cpp |  14 +++-
 src/settings/modules/DFTSettings.h   |  12 +++
 4 files changed, 194 insertions(+), 1 deletion(-)
 create mode 100644 src/builder/DftSmtBuilder.cpp
 create mode 100644 src/builder/DftSmtBuilder.h

diff --git a/src/builder/DftSmtBuilder.cpp b/src/builder/DftSmtBuilder.cpp
new file mode 100644
index 000000000..1d60b2c74
--- /dev/null
+++ b/src/builder/DftSmtBuilder.cpp
@@ -0,0 +1,120 @@
+#include "src/builder/DFTSMTBuilder.h"
+#include "src/exceptions/NotImplementedException.h"
+
+namespace storm {
+    namespace builder {
+
+        template <typename ValueType>
+        DFTSMTBuilder<ValueType>::DFTSMTBuilder() : manager(std::make_shared<storm::expressions::ExpressionManager>()) {
+            solver = storm::utility::solver::SmtSolverFactory().create(*manager);
+        }
+
+        template <typename ValueType>
+        void DFTSMTBuilder<ValueType>::convertToSMT(storm::storage::DFT<ValueType> const& dft) {
+            std::cout << "Convert DFT to SMT" << std::endl;
+            timeMax = manager->integer(dft.nrBasicElements());
+            timeFailSafe = manager->integer(dft.nrBasicElements() + 1);
+            timeZero = manager->integer(0);
+            
+            // Convert all elements
+            for (size_t i = 0; i < dft.nrElements(); ++i) {
+                std::shared_ptr<storm::storage::DFTElement<ValueType> const> element = dft.getElement(i);
+                std::cout << "Consider " << element->toString() << std::endl;
+                if (element->isBasicElement()) {
+                    storm::expressions::Variable varBE = convert(std::static_pointer_cast<storm::storage::DFTBE<ValueType> const>(element));
+                    varsBE.push_back(varBE);
+                } else if (element->isGate()) {
+                    storm::expressions::Variable varGate = convert(std::static_pointer_cast<storm::storage::DFTGate<ValueType> const>(element));
+                    if (dft.getTopLevelIndex() == i) {
+                        topLevel = varGate;
+                    }
+                } else if (element->isDependency()) {
+                    convert(std::static_pointer_cast<storm::storage::DFTDependency<ValueType> const>(element));
+                } else if (element->isRestriction()) {
+                    convert(std::static_pointer_cast<storm::storage::DFTRestriction<ValueType> const>(element));
+                }
+            }
+            
+            // No simultaneous fails can occur
+            for (size_t i = 0; i < varsBE.size() - 1; ++i) {
+                storm::expressions::Expression be = varsBE[i];
+                for (size_t j = i + 1; j < varsBE.size(); ++j) {
+                    storm::expressions::Expression assertion = be != varsBE[j];
+                    solver->add(assertion);
+                }
+            }
+            
+            // For every time-point one BE must fail
+            for (size_t time = 1; time <= dft.nrBasicElements(); ++time) {
+                storm::expressions::Expression exprTime = manager->integer(time);
+                storm::expressions::Expression assertion = varsBE[0] == exprTime;
+                for (size_t i = 1; i < varsBE.size(); ++i) {
+                    assertion = assertion || varsBE[i] == exprTime;
+                }
+                assertion = assertion || topLevel <= exprTime;
+                solver->add(assertion);
+            }
+            
+        }
+        
+        template <typename ValueType>
+        storm::expressions::Variable DFTSMTBuilder<ValueType>::convert(std::shared_ptr<storm::storage::DFTBE<ValueType> const> const& be) {
+            storm::expressions::Variable var = manager->declareIntegerVariable(be->name());
+            storm::expressions::Expression assertion = timeZero < var && var < timeFailSafe;
+            solver->add(assertion);
+            return var;
+        }
+        
+        template <typename ValueType>
+        storm::expressions::Variable DFTSMTBuilder<ValueType>::convert(std::shared_ptr<storm::storage::DFTGate<ValueType> const> const& gate) {
+            storm::expressions::Variable var = manager->declareIntegerVariable(gate->name());
+            storm::expressions::Expression assertion = timeZero < var && var <= timeFailSafe;
+            solver->add(assertion);
+            return var;
+        }
+        
+        template <typename ValueType>
+        storm::expressions::Variable DFTSMTBuilder<ValueType>::convert(std::shared_ptr<storm::storage::DFTDependency<ValueType> const> const& dependency) {
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "The dependency cannot be converted into SMT.");
+        }
+        
+        template <typename ValueType>
+        storm::expressions::Variable DFTSMTBuilder<ValueType>::convert(std::shared_ptr<storm::storage::DFTRestriction<ValueType> const> const& restriction) {
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "The restriction cannot be converted into SMT.");
+        }
+
+        template <typename ValueType>
+        bool DFTSMTBuilder<ValueType>::check() const {
+            std::cout << "Check" << std::endl;
+            storm::solver::SmtSolver::CheckResult result = solver->check();
+            switch (result) {
+                case solver::SmtSolver::CheckResult::Sat:
+                {
+                    std::cout << "SAT with model:" << std::endl;
+                    std::shared_ptr<storm::solver::SmtSolver::ModelReference> model = solver->getModel();
+                    for (auto const& pair : *manager) {
+                        std::cout << pair.first.getName() << "->" << model->getIntegerValue(pair.first) << std::endl;
+                    }
+                    return true;
+                }
+                case solver::SmtSolver::CheckResult::Unsat:
+                    return false;
+                case solver::SmtSolver::CheckResult::Unknown:
+                default:
+                    STORM_LOG_ASSERT(false, "Result is unknown.");
+                    return false;
+            }
+        }
+        
+
+        // Explicitly instantiate the class.
+        template class DFTSMTBuilder<double>;
+
+#ifdef STORM_HAVE_CARL
+        template class DFTSMTBuilder<storm::RationalFunction>;
+#endif
+
+    } // namespace builder
+} // namespace storm
+
+
diff --git a/src/builder/DftSmtBuilder.h b/src/builder/DftSmtBuilder.h
new file mode 100644
index 000000000..596e8106f
--- /dev/null
+++ b/src/builder/DftSmtBuilder.h
@@ -0,0 +1,49 @@
+#ifndef DFTSMTBUILDER_H
+#define	DFTSMTBUILDER_H
+
+#include "src/solver/SmtSolver.h"
+#include "src/utility/solver.h"
+#include "src/storage/dft/DFT.h"
+
+namespace storm {
+    namespace builder {
+
+        template<typename ValueType>
+        class DFTSMTBuilder {
+
+        public:
+            DFTSMTBuilder();
+            
+            void convertToSMT(storm::storage::DFT<ValueType> const& dft);
+            
+            bool check() const;
+
+        private:
+            
+            std::shared_ptr<storm::solver::SmtSolver> solver;
+            
+            std::shared_ptr<storm::expressions::ExpressionManager> manager;
+            
+            storm::expressions::Expression timeMax;
+            
+            storm::expressions::Expression timeFailSafe;
+            
+            storm::expressions::Expression timeZero;
+            
+            storm::expressions::Expression topLevel;
+            
+            std::vector<storm::expressions::Variable> varsBE;
+
+            storm::expressions::Variable convert(std::shared_ptr<storm::storage::DFTBE<ValueType> const> const& be);
+
+            storm::expressions::Variable convert(std::shared_ptr<storm::storage::DFTGate<ValueType> const> const& gate);
+            
+            storm::expressions::Variable convert(std::shared_ptr<storm::storage::DFTDependency<ValueType> const> const& dependency);
+            
+            storm::expressions::Variable convert(std::shared_ptr<storm::storage::DFTRestriction<ValueType> const> const& restriction);
+
+        };
+    }
+}
+
+#endif	/* DFTSMTBUILDER_H */
diff --git a/src/settings/modules/DFTSettings.cpp b/src/settings/modules/DFTSettings.cpp
index 365ba0271..4df95987c 100644
--- a/src/settings/modules/DFTSettings.cpp
+++ b/src/settings/modules/DFTSettings.cpp
@@ -27,7 +27,10 @@ namespace storm {
             const std::string DFTSettings::propTimeBoundOptionName = "timebound";
             const std::string DFTSettings::minValueOptionName = "min";
             const std::string DFTSettings::maxValueOptionName = "max";
-
+#ifdef STORM_HAVE_Z3
+            const std::string DFTSettings::solveWithSmtOptionName = "smt";
+#endif
+            
             DFTSettings::DFTSettings() : ModuleSettings(moduleName) {
                 this->addOption(storm::settings::OptionBuilder(moduleName, dftFileOptionName, false, "Parses the model given in the Galileo format.").setShortName(dftFileOptionShortName)
                                 .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the DFT model.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
@@ -39,6 +42,9 @@ namespace storm {
                 this->addOption(storm::settings::OptionBuilder(moduleName, propTimeBoundOptionName, false, "Compute probability of system failure up to given timebound.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("time", "The timebound to use.").addValidationFunctionDouble(storm::settings::ArgumentValidators::doubleGreaterValidatorExcluding(0.0)).build()).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, minValueOptionName, false, "Compute minimal value in case of non-determinism.").build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, maxValueOptionName, false, "Compute maximal value in case of non-determinism.").build());
+#ifdef STORM_HAVE_Z3
+                this->addOption(storm::settings::OptionBuilder(moduleName, solveWithSmtOptionName, true, "Solve the DFT with SMT.").build());
+#endif
             }
             
             bool DFTSettings::isDftFileSet() const {
@@ -85,6 +91,12 @@ namespace storm {
                 return this->getOption(maxValueOptionName).getHasOptionBeenSet();
             }
             
+#ifdef STORM_HAVE_Z3
+            bool DFTSettings::solveWithSMT() const {
+                return this->getOption(solveWithSmtOptionName).getHasOptionBeenSet();
+            }
+#endif
+            
             void DFTSettings::finalize() {
                 
             }
diff --git a/src/settings/modules/DFTSettings.h b/src/settings/modules/DFTSettings.h
index 844953c2c..183e00eef 100644
--- a/src/settings/modules/DFTSettings.h
+++ b/src/settings/modules/DFTSettings.h
@@ -99,6 +99,15 @@ namespace storm {
                  */
                 double getPropTimebound() const;
                 
+#ifdef STORM_HAVE_Z3
+                /*!
+                 * Retrieves whether the DFT should be checked via SMT.
+                 *
+                 * @return True iff the option was set.
+                 */
+                bool solveWithSMT() const;
+#endif
+                
                 bool check() const override;
                 void finalize() override;
 
@@ -119,6 +128,9 @@ namespace storm {
                 static const std::string propTimeBoundOptionName;
                 static const std::string minValueOptionName;
                 static const std::string maxValueOptionName;
+#ifdef STORM_HAVE_Z3
+                static const std::string solveWithSmtOptionName;
+#endif
                 
             };
 

From c4260d3d5af37dba8ec9dc9a9a38e48aa3bb38fc Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Wed, 18 May 2016 16:29:28 +0200
Subject: [PATCH 05/65] First try on approximation

Former-commit-id: 53c6738c729bb143e04d31876c17b9b5873cccd4
---
 src/builder/ExplicitDFTModelBuilder.cpp | 42 +++++++++++++++++++++++++
 src/builder/ExplicitDFTModelBuilder.h   |  3 ++
 2 files changed, 45 insertions(+)

diff --git a/src/builder/ExplicitDFTModelBuilder.cpp b/src/builder/ExplicitDFTModelBuilder.cpp
index 4fb6131df..7cf1488be 100644
--- a/src/builder/ExplicitDFTModelBuilder.cpp
+++ b/src/builder/ExplicitDFTModelBuilder.cpp
@@ -4,6 +4,8 @@
 #include <src/utility/constants.h>
 #include <src/utility/vector.h>
 #include <src/exceptions/UnexpectedException.h>
+#include "src/settings/modules/DebugSettings.h"
+#include "src/settings/SettingsManager.h"
 #include <map>
 
 namespace storm {
@@ -157,7 +159,24 @@ namespace storm {
             
             return model;
         }
+        
+        template<>
+        bool belowThreshold(double const& number) {
+            return number < 0.1;
+        }
+
+        template<>
+        bool belowThreshold(storm::RationalFunction const& number) {
+            storm::RationalFunction threshold = storm::utility::one<storm::RationalFunction>() / 10;
+            std::cout << number << " < " << threshold << ": " << (number < threshold) << std::endl;
+            std::map<storm::Variable, storm::RationalNumber> mapping;
+            
+            storm::RationalFunction eval(number.evaluate(mapping));
+            std::cout << "Evaluated: " << eval << std::endl;
+            return eval < threshold;
+        }
 
+        
         template <typename ValueType>
         std::pair<uint_fast64_t, bool> ExplicitDFTModelBuilder<ValueType>::exploreStates(DFTStatePointer const& state, size_t& rowOffset, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<uint_fast64_t>& markovianStates, std::vector<ValueType>& exitRates) {
             STORM_LOG_TRACE("Explore state: " << mDft.getStateString(state));
@@ -206,6 +225,29 @@ namespace storm {
                 STORM_LOG_ASSERT(nextBE, "NextBE is null.");
                 STORM_LOG_ASSERT(nextBEPair.second == hasDependencies, "Failure due to dependencies does not match.");
                 STORM_LOG_TRACE("With the failure of: " << nextBE->name() << " [" << nextBE->id() << "] in " << mDft.getStateString(state));
+                
+                if (storm::settings::getModule<storm::settings::modules::DebugSettings>().isTestSet()) {
+                    if (!storm::utility::isZero(exitRate)) {
+                    ValueType rate = nextBE->activeFailureRate();
+                    ValueType div = rate / exitRate;
+                    if (!storm::utility::isZero(exitRate) && belowThreshold(div)) {
+                        // Set transition directly to failed state
+                        auto resultFind = outgoingRates.find(failedIndex);
+                        if (resultFind != outgoingRates.end()) {
+                            // Add to existing transition
+                            resultFind->second += rate;
+                            STORM_LOG_TRACE("Updated transition to " << resultFind->first << " with rate " << rate << " to new rate " << resultFind->second);
+                        } else {
+                            // Insert new transition
+                            outgoingRates.insert(std::make_pair(failedIndex, rate));
+                            STORM_LOG_TRACE("Added transition to " << failedIndex << " with rate " << rate);
+                        }
+                        exitRate += rate;
+                        std::cout << "IGNORE: " << nextBE->name() << " [" << nextBE->id() << "] with rate " << rate << std::endl;
+                        //STORM_LOG_TRACE("Ignore: " << nextBE->name() << " [" << nextBE->id() << "] with rate " << rate);
+                        continue;
+                    }}
+                }
 
                 // Propagate failures
                 storm::storage::DFTStateSpaceGenerationQueues<ValueType> queues;
diff --git a/src/builder/ExplicitDFTModelBuilder.h b/src/builder/ExplicitDFTModelBuilder.h
index 3e78180d1..71bfada61 100644
--- a/src/builder/ExplicitDFTModelBuilder.h
+++ b/src/builder/ExplicitDFTModelBuilder.h
@@ -91,6 +91,9 @@ namespace storm {
             std::pair<bool, uint_fast64_t> checkForExploration(DFTStatePointer const& state);
 
         };
+        
+        template<typename ValueType>
+        bool belowThreshold(ValueType const& number);
     }
 }
 

From a0cd14905449d03a4fd81650b5450bd6aa94dfc5 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Wed, 18 May 2016 17:01:21 +0200
Subject: [PATCH 06/65] Introduced setting for DFT approximation

Former-commit-id: 03a2c0ca0cbe406a75d57f8040c6cd64b2151bc7
---
 src/builder/ExplicitDFTModelBuilder.cpp | 4 ++--
 src/settings/modules/DFTSettings.cpp    | 9 ++++++++-
 src/settings/modules/DFTSettings.h      | 9 +++++++++
 3 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilder.cpp b/src/builder/ExplicitDFTModelBuilder.cpp
index 7cf1488be..4d794cb2f 100644
--- a/src/builder/ExplicitDFTModelBuilder.cpp
+++ b/src/builder/ExplicitDFTModelBuilder.cpp
@@ -4,7 +4,7 @@
 #include <src/utility/constants.h>
 #include <src/utility/vector.h>
 #include <src/exceptions/UnexpectedException.h>
-#include "src/settings/modules/DebugSettings.h"
+#include "src/settings/modules/DFTSettings.h"
 #include "src/settings/SettingsManager.h"
 #include <map>
 
@@ -226,7 +226,7 @@ namespace storm {
                 STORM_LOG_ASSERT(nextBEPair.second == hasDependencies, "Failure due to dependencies does not match.");
                 STORM_LOG_TRACE("With the failure of: " << nextBE->name() << " [" << nextBE->id() << "] in " << mDft.getStateString(state));
                 
-                if (storm::settings::getModule<storm::settings::modules::DebugSettings>().isTestSet()) {
+                if (storm::settings::getModule<storm::settings::modules::DFTSettings>().computeApproximation()) {
                     if (!storm::utility::isZero(exitRate)) {
                     ValueType rate = nextBE->activeFailureRate();
                     ValueType div = rate / exitRate;
diff --git a/src/settings/modules/DFTSettings.cpp b/src/settings/modules/DFTSettings.cpp
index 4df95987c..416a8a5af 100644
--- a/src/settings/modules/DFTSettings.cpp
+++ b/src/settings/modules/DFTSettings.cpp
@@ -21,6 +21,8 @@ namespace storm {
             const std::string DFTSettings::symmetryReductionOptionShortName = "symred";
             const std::string DFTSettings::modularisationOptionName = "modularisation";
             const std::string DFTSettings::disableDCOptionName = "disabledc";
+            const std::string DFTSettings::computeApproximationOptionName = "approximation";
+            const std::string DFTSettings::computeApproximationOptionShortName = "approx";
             const std::string DFTSettings::propExpectedTimeOptionName = "expectedtime";
             const std::string DFTSettings::propExpectedTimeOptionShortName = "mttf";
             const std::string DFTSettings::propProbabilityOptionName = "probability";
@@ -37,6 +39,7 @@ namespace storm {
                 this->addOption(storm::settings::OptionBuilder(moduleName, symmetryReductionOptionName, false, "Exploit symmetric structure of model.").setShortName(symmetryReductionOptionShortName).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, modularisationOptionName, false, "Use modularisation (not applicable for expected time).").build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, disableDCOptionName, false, "Disable Dont Care propagation.").build());
+                this->addOption(storm::settings::OptionBuilder(moduleName, computeApproximationOptionName, false, "Compute an approximation.").setShortName(computeApproximationOptionShortName).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, propExpectedTimeOptionName, false, "Compute expected time of system failure.").setShortName(propExpectedTimeOptionShortName).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, propProbabilityOptionName, false, "Compute probability of system failure.").build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, propTimeBoundOptionName, false, "Compute probability of system failure up to given timebound.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("time", "The timebound to use.").addValidationFunctionDouble(storm::settings::ArgumentValidators::doubleGreaterValidatorExcluding(0.0)).build()).build());
@@ -67,6 +70,10 @@ namespace storm {
                 return this->getOption(disableDCOptionName).getHasOptionBeenSet();
             }
             
+            bool DFTSettings::computeApproximation() const {
+                return this->getOption(computeApproximationOptionName).getHasOptionBeenSet();
+            }
+            
             bool DFTSettings::usePropExpectedTime() const {
                 return this->getOption(propExpectedTimeOptionName).getHasOptionBeenSet();
             }
@@ -116,4 +123,4 @@ namespace storm {
             
         } // namespace modules
     } // namespace settings
-} // namespace storm
\ No newline at end of file
+} // namespace storm
diff --git a/src/settings/modules/DFTSettings.h b/src/settings/modules/DFTSettings.h
index 183e00eef..f21752f7f 100644
--- a/src/settings/modules/DFTSettings.h
+++ b/src/settings/modules/DFTSettings.h
@@ -57,6 +57,13 @@ namespace storm {
                  */
                 bool isDisableDC() const;
 
+                /*!
+                 * Retrieves whether the option to compute an approximation is set.
+                 *
+                 * @return True iff the option was set.
+                 */
+                bool computeApproximation() const;
+                
                 /*!
                  * Retrieves whether the property expected time should be used.
                  *
@@ -122,6 +129,8 @@ namespace storm {
                 static const std::string symmetryReductionOptionShortName;
                 static const std::string modularisationOptionName;
                 static const std::string disableDCOptionName;
+                static const std::string computeApproximationOptionName;
+                static const std::string computeApproximationOptionShortName;
                 static const std::string propExpectedTimeOptionName;
                 static const std::string propExpectedTimeOptionShortName;
                 static const std::string propProbabilityOptionName;

From 560b42a94a63b893828192bf90f86e7bf426b629 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Mon, 18 Jul 2016 08:55:37 +0200
Subject: [PATCH 07/65] Some interval functions not implemented

Former-commit-id: c88dca9d96c280ff8e2b810a46349d92e1c4ae4d
---
 src/storage/SparseMatrix.cpp | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/storage/SparseMatrix.cpp b/src/storage/SparseMatrix.cpp
index 4b763e383..c43dc77d9 100644
--- a/src/storage/SparseMatrix.cpp
+++ b/src/storage/SparseMatrix.cpp
@@ -1014,6 +1014,11 @@ namespace storm {
         }
         
 #ifdef STORM_HAVE_CARL
+        template<>
+        typename std::pair<storm::storage::SparseMatrix<Interval>, std::vector<Interval>> SparseMatrix<Interval>::getJacobiDecomposition() const {
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This operation is not supported.");
+        }
+        
         template<>
         typename std::pair<storm::storage::SparseMatrix<RationalFunction>, std::vector<RationalFunction>> SparseMatrix<RationalFunction>::getJacobiDecomposition() const {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This operation is not supported.");
@@ -1144,6 +1149,13 @@ namespace storm {
             }
         }
         
+#ifdef STORM_HAVE_CARL
+        template<>
+        void SparseMatrix<Interval>::performSuccessiveOverRelaxationStep(Interval omega, std::vector<Interval>& x, std::vector<Interval> const& b) const {
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This operation is not supported.");
+        }
+#endif
+
         template<typename ValueType>
         void SparseMatrix<ValueType>::multiplyVectorWithMatrix(std::vector<value_type> const& vector, std::vector<value_type>& result) const {
             const_iterator it = this->begin();

From 662bbd73d7a434d4c5a846cf35b46560ab86ea9c Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Mon, 18 Jul 2016 17:17:24 +0200
Subject: [PATCH 08/65] CompressedStateType as template argument for
 NextStateGenerator

Former-commit-id: 145182a9180b4d2f13f67f964086cf40e51528e6
---
 src/builder/ExplicitDFTModelBuilder.h   | 2 +-
 src/generator/NextStateGenerator.h      | 6 +++---
 src/generator/PrismNextStateGenerator.h | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilder.h b/src/builder/ExplicitDFTModelBuilder.h
index 71bfada61..eae19cb61 100644
--- a/src/builder/ExplicitDFTModelBuilder.h
+++ b/src/builder/ExplicitDFTModelBuilder.h
@@ -60,7 +60,7 @@ namespace storm {
             size_t initialStateIndex = 0;
 
         public:
-              struct LabelOptions {
+            struct LabelOptions {
                 bool buildFailLabel = true;
                 bool buildFailSafeLabel = false;
                 std::set<std::string> beLabels = {};
diff --git a/src/generator/NextStateGenerator.h b/src/generator/NextStateGenerator.h
index 7dab9f470..67fd5f9f6 100644
--- a/src/generator/NextStateGenerator.h
+++ b/src/generator/NextStateGenerator.h
@@ -11,15 +11,15 @@
 
 namespace storm {
     namespace generator {
-        template<typename ValueType, typename StateType = uint32_t>
+        template<typename ValueType, typename CompressedStateType, typename StateType = uint32_t>
         class NextStateGenerator {
         public:
-            typedef std::function<StateType (CompressedState const&)> StateToIdCallback;
+            typedef std::function<StateType (CompressedStateType const&)> StateToIdCallback;
 
             virtual bool isDeterministicModel() const = 0;
             virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) = 0;
             
-            virtual void load(CompressedState const& state) = 0;
+            virtual void load(CompressedStateType const& state) = 0;
             virtual StateBehavior<ValueType, StateType> expand(StateToIdCallback const& stateToIdCallback) = 0;
             virtual bool satisfies(storm::expressions::Expression const& expression) const = 0;
         };
diff --git a/src/generator/PrismNextStateGenerator.h b/src/generator/PrismNextStateGenerator.h
index fe997d73a..fc1411aa0 100644
--- a/src/generator/PrismNextStateGenerator.h
+++ b/src/generator/PrismNextStateGenerator.h
@@ -13,9 +13,9 @@ namespace storm {
     namespace generator {
         
         template<typename ValueType, typename StateType = uint32_t>
-        class PrismNextStateGenerator : public NextStateGenerator<ValueType, StateType> {
+        class PrismNextStateGenerator : public NextStateGenerator<ValueType, CompressedState, StateType> {
         public:
-            typedef typename NextStateGenerator<ValueType, StateType>::StateToIdCallback StateToIdCallback;
+            typedef typename NextStateGenerator<ValueType, CompressedState, StateType>::StateToIdCallback StateToIdCallback;
             
             PrismNextStateGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation, bool buildChoiceLabeling);
                         

From 12f7c08bacaac886ef03e131a605208a256adde0 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Mon, 18 Jul 2016 17:18:43 +0200
Subject: [PATCH 09/65] New class for DftStateGenerator

Former-commit-id: 5d7f798de1071dd908e60d84330ba241104af22d
---
 examples/dft/and_approx.dft             |   5 +
 examples/dft/and_approx_param.dft       |   6 +
 examples/dft/nonmonoton.dft             |   6 +
 src/generator/DftNextStateGenerator.cpp | 156 ++++++++++++++++++++++++
 src/generator/DftNextStateGenerator.h   |  40 ++++++
 5 files changed, 213 insertions(+)
 create mode 100644 examples/dft/and_approx.dft
 create mode 100644 examples/dft/and_approx_param.dft
 create mode 100644 examples/dft/nonmonoton.dft
 create mode 100644 src/generator/DftNextStateGenerator.cpp
 create mode 100644 src/generator/DftNextStateGenerator.h

diff --git a/examples/dft/and_approx.dft b/examples/dft/and_approx.dft
new file mode 100644
index 000000000..ff6393dd5
--- /dev/null
+++ b/examples/dft/and_approx.dft
@@ -0,0 +1,5 @@
+toplevel "A";
+"A" and "B" "C" "D";
+"B" lambda=1 dorm=0;
+"C" lambda=100 dorm=0;
+"D" lambda=50 dorm=0;
diff --git a/examples/dft/and_approx_param.dft b/examples/dft/and_approx_param.dft
new file mode 100644
index 000000000..bbd00bd80
--- /dev/null
+++ b/examples/dft/and_approx_param.dft
@@ -0,0 +1,6 @@
+param x;
+toplevel "A";
+"A" and "B" "C" "D";
+"B" lambda=1 dorm=0;
+"C" lambda=100 dorm=0;
+"D" lambda=100*x dorm=0;
diff --git a/examples/dft/nonmonoton.dft b/examples/dft/nonmonoton.dft
new file mode 100644
index 000000000..0575028e8
--- /dev/null
+++ b/examples/dft/nonmonoton.dft
@@ -0,0 +1,6 @@
+toplevel "A";
+"A" or "B" "Z";
+"B" pand "D" "S";
+"Z" lambda=1 dorm=0;
+"D" lambda=100 dorm=0;
+"S" lambda=50 dorm=0;
diff --git a/src/generator/DftNextStateGenerator.cpp b/src/generator/DftNextStateGenerator.cpp
new file mode 100644
index 000000000..b56f8a358
--- /dev/null
+++ b/src/generator/DftNextStateGenerator.cpp
@@ -0,0 +1,156 @@
+#include "src/generator/DftNextStateGenerator.h"
+
+#include "src/utility/constants.h"
+#include "src/utility/macros.h"
+#include "src/exceptions/WrongFormatException.h"
+
+namespace storm {
+    namespace generator {
+        
+        template<typename ValueType, typename StateType>
+        DftNextStateGenerator<ValueType, StateType>::DftNextStateGenerator(storm::storage::DFT<ValueType> const& dft) : mDft(dft), state(nullptr), comparator() {
+            // Intentionally left empty.
+        }
+        
+        template<typename ValueType, typename StateType>
+        bool DftNextStateGenerator<ValueType, StateType>::isDeterministicModel() const {
+            assert(false);
+            return true;
+        }
+        
+        template<typename ValueType, typename StateType>
+        std::vector<StateType> DftNextStateGenerator<ValueType, StateType>::getInitialStates(StateToIdCallback const& stateToIdCallback) {
+            // FIXME: This only works for models with exactly one initial state. We should make this more general.
+            /*CompressedState initialState(variableInformation.getTotalBitOffset());
+            
+            // We need to initialize the values of the variables to their initial value.
+            for (auto const& booleanVariable : variableInformation.booleanVariables) {
+                initialState.set(booleanVariable.bitOffset, booleanVariable.initialValue);
+            }
+            for (auto const& integerVariable : variableInformation.integerVariables) {
+                initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast<uint_fast64_t>(integerVariable.initialValue - integerVariable.lowerBound));
+            }
+
+            // Register initial state and return it.
+            StateType id = stateToIdCallback(initialState);
+            return {id};*/
+        }
+        
+        template<typename ValueType, typename StateType>
+        void DftNextStateGenerator<ValueType, StateType>::load(std::shared_ptr<storm::storage::DFTState<ValueType>> const& state) {
+            /*// Since almost all subsequent operations are based on the evaluator, we load the state into it now.
+            unpackStateIntoEvaluator(state, variableInformation, evaluator);
+            
+            // Also, we need to store a pointer to the state itself, because we need to be able to access it when expanding it.
+            this->state = &state;*/
+        }
+        
+        template<typename ValueType, typename StateType>
+        bool DftNextStateGenerator<ValueType, StateType>::satisfies(storm::expressions::Expression const& expression) const {
+           /* if (expression.isTrue()) {
+                return true;
+            }
+            return evaluator.asBool(expression);*/
+        }
+        
+        template<typename ValueType, typename StateType>
+        StateBehavior<ValueType, StateType> DftNextStateGenerator<ValueType, StateType>::expand(StateToIdCallback const& stateToIdCallback) {
+            /*// Prepare the result, in case we return early.
+            StateBehavior<ValueType, StateType> result;
+            
+            // First, construct the state rewards, as we may return early if there are no choices later and we already
+            // need the state rewards then.
+            for (auto const& rewardModel : selectedRewardModels) {
+                ValueType stateRewardValue = storm::utility::zero<ValueType>();
+                if (rewardModel.get().hasStateRewards()) {
+                    for (auto const& stateReward : rewardModel.get().getStateRewards()) {
+                        if (evaluator.asBool(stateReward.getStatePredicateExpression())) {
+                            stateRewardValue += ValueType(evaluator.asRational(stateReward.getRewardValueExpression()));
+                        }
+                    }
+                }
+                result.addStateReward(stateRewardValue);
+            }
+            
+            // If a terminal expression was set and we must not expand this state, return now.
+            if (terminalExpression && evaluator.asBool(terminalExpression.get())) {
+                return result;
+            }
+            
+            // Get all choices for the state.
+            std::vector<Choice<ValueType>> allChoices = getUnlabeledChoices(*this->state, stateToIdCallback);
+            std::vector<Choice<ValueType>> allLabeledChoices = getLabeledChoices(*this->state, stateToIdCallback);
+            for (auto& choice : allLabeledChoices) {
+                allChoices.push_back(std::move(choice));
+            }
+            
+            std::size_t totalNumberOfChoices = allChoices.size();
+            
+            // If there is not a single choice, we return immediately, because the state has no behavior (other than
+            // the state reward).
+            if (totalNumberOfChoices == 0) {
+                return result;
+            }
+            
+            // If the model is a deterministic model, we need to fuse the choices into one.
+            if (program.isDeterministicModel() && totalNumberOfChoices > 1) {
+                Choice<ValueType> globalChoice;
+                
+                // For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs
+                // this is equal to the number of choices, which is why we initialize it like this here.
+                ValueType totalExitRate = program.isDiscreteTimeModel() ? static_cast<ValueType>(totalNumberOfChoices) : storm::utility::zero<ValueType>();
+                
+                // Iterate over all choices and combine the probabilities/rates into one choice.
+                for (auto const& choice : allChoices) {
+                    for (auto const& stateProbabilityPair : choice) {
+                        if (program.isDiscreteTimeModel()) {
+                            globalChoice.addProbability(stateProbabilityPair.first, stateProbabilityPair.second / totalNumberOfChoices);
+                        } else {
+                            globalChoice.addProbability(stateProbabilityPair.first, stateProbabilityPair.second);
+                        }
+                    }
+                    
+                    if (hasStateActionRewards && !program.isDiscreteTimeModel()) {
+                        totalExitRate += choice.getTotalMass();
+                    }
+                    
+                    if (buildChoiceLabeling) {
+                        globalChoice.addChoiceLabels(choice.getChoiceLabels());
+                    }
+                }
+                
+                // Now construct the state-action reward for all selected reward models.
+                for (auto const& rewardModel : selectedRewardModels) {
+                    ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
+                    if (rewardModel.get().hasStateActionRewards()) {
+                        for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) {
+                            for (auto const& choice : allChoices) {
+                                if (stateActionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(stateActionReward.getStatePredicateExpression())) {
+                                    stateActionRewardValue += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass() / totalExitRate;
+                                }
+                            }
+                            
+                        }
+                    }
+                    globalChoice.addChoiceReward(stateActionRewardValue);
+                }
+                
+                // Move the newly fused choice in place.
+                allChoices.clear();
+                allChoices.push_back(std::move(globalChoice));
+            }
+            
+            // Move all remaining choices in place.
+            for (auto& choice : allChoices) {
+                result.addChoice(std::move(choice));
+            }
+            
+            result.setExpanded();
+            return result;*/
+        }
+        
+        
+        template class DftNextStateGenerator<double>;
+        template class DftNextStateGenerator<storm::RationalFunction>;
+    }
+}
\ No newline at end of file
diff --git a/src/generator/DftNextStateGenerator.h b/src/generator/DftNextStateGenerator.h
new file mode 100644
index 000000000..6c8e5538d
--- /dev/null
+++ b/src/generator/DftNextStateGenerator.h
@@ -0,0 +1,40 @@
+#ifndef STORM_GENERATOR_DFTNEXTSTATEGENERATOR_H_
+#define STORM_GENERATOR_DFTNEXTSTATEGENERATOR_H_
+
+#include "src/generator/NextStateGenerator.h"
+#include "src/storage/dft/DFT.h"
+
+#include "src/utility/ConstantsComparator.h"
+
+namespace storm {
+    namespace generator {
+        
+        template<typename ValueType, typename StateType = uint32_t>
+        class DftNextStateGenerator : public NextStateGenerator<ValueType, std::shared_ptr<storm::storage::DFTState<ValueType>>, StateType> {
+        public:
+            typedef typename NextStateGenerator<ValueType, std::shared_ptr<storm::storage::DFTState<ValueType>>, StateType>::StateToIdCallback StateToIdCallback;
+            
+            DftNextStateGenerator(storm::storage::DFT<ValueType> const& dft);
+                        
+            virtual bool isDeterministicModel() const override;
+            virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) override;
+
+            virtual void load(std::shared_ptr<storm::storage::DFTState<ValueType>> const& state) override;
+            virtual StateBehavior<ValueType, StateType> expand(StateToIdCallback const& stateToIdCallback) override;
+            virtual bool satisfies(storm::expressions::Expression const& expression) const override;
+
+        private:
+            
+            // The program used for the generation of next states.
+            storm::storage::DFT<ValueType> const& mDft;
+            
+            CompressedState const* state;
+            
+            // A comparator used to compare constants.
+            storm::utility::ConstantsComparator<ValueType> comparator;
+        };
+        
+    }
+}
+
+#endif /* STORM_GENERATOR_DFTNEXTSTATEGENERATOR_H_ */
\ No newline at end of file

From 495b42ff4c5fb9eba078f93ad864c0b51702e426 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Thu, 18 Aug 2016 17:09:15 +0200
Subject: [PATCH 10/65] Temporarily split new approximating state generation
 into own builder

Former-commit-id: 70be02f2ae2e07585d9874fdfac80947e4979b8d
---
 examples/dft/mas.dft                          |  58 ++
 examples/dft/nonmonoton_param.dft             |   8 +-
 src/builder/ExplicitDFTModelBuilder.cpp       |  40 --
 src/builder/ExplicitDFTModelBuilder.h         |   3 -
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 666 ++++++++++++++++++
 src/builder/ExplicitDFTModelBuilderApprox.h   | 105 +++
 src/generator/DftNextStateGenerator.cpp       |  31 +-
 src/generator/DftNextStateGenerator.h         |  15 +-
 src/modelchecker/DFTAnalyser.h                |  30 +-
 src/storage/sparse/StateStorage.cpp           |   1 +
 10 files changed, 875 insertions(+), 82 deletions(-)
 create mode 100644 examples/dft/mas.dft
 create mode 100644 src/builder/ExplicitDFTModelBuilderApprox.cpp
 create mode 100644 src/builder/ExplicitDFTModelBuilderApprox.h

diff --git a/examples/dft/mas.dft b/examples/dft/mas.dft
new file mode 100644
index 000000000..bed57d59c
--- /dev/null
+++ b/examples/dft/mas.dft
@@ -0,0 +1,58 @@
+toplevel "MAS";
+"MAS" or "CPU" "DB" "MB" "VMB" "MEM" "VMS";
+"CPU" or "CW" "SO1" "SO2" "PG" "SM";
+"CW" and "CWA" "CWB";
+"SO1" and "SO1A" "SO1B";
+"SO2" and "SO2A" "SO2B";
+"PG" and "PGA" "PGB";
+"SM" and "SMA" "SMB";
+"CWA" csp "CWAev" "S1" "S2";
+"CWB" csp "CWBev" "S1" "S2";
+"SO1A" csp "SO1Aev" "S1" "S2";
+"SO1B" csp "SO1Bev" "S1" "S2";
+"SO2A" csp "SO2Aev" "S1" "S2";
+"SO2B" csp "SO2Bev" "S1" "S2";
+"PGA" csp "PGAev" "S1" "S2";
+"PGB" csp "PGBev" "S1" "S2";
+"SMA" csp "SMAev" "S1" "S2";
+"SMB" csp "SMBev" "S1" "S2";
+"CWAev" lambda=1.0e-6 dorm=0;
+"CWBev" lambda=1.0e-6 dorm=0;
+"SO1Aev" lambda=1.0e-6 dorm=0;
+"SO1Bev" lambda=1.0e-6 dorm=0;
+"SO2Aev" lambda=1.0e-6 dorm=0;
+"SO2Bev" lambda=1.0e-6 dorm=0;
+"PGAev" lambda=1.0e-6 dorm=0;
+"PGBev" lambda=1.0e-6 dorm=0;
+"SMAev" lambda=1.0e-6 dorm=0;
+"SMBev" lambda=1.0e-6 dorm=0;
+"S1" lambda=1.0e-6 dorm=0;
+"S2" lambda=1.0e-6 dorm=0;
+"DB" and "DB1" "DB2" "DB3";
+"DB1" lambda=5.0e-6 dorm=0;
+"DB2" lambda=5.0e-6 dorm=0;
+"DB3" lambda=5.0e-6 dorm=0;
+"MB" and "MB1" "MB2" "MB3";
+"MB1" lambda=5.0e-6 dorm=0;
+"MB2" lambda=5.0e-6 dorm=0;
+"MB3" lambda=5.0e-6 dorm=0;
+"VMB" and "VMB1" "VMB2";
+"VMB1" lambda=5.0e-6 dorm=0;
+"VMB2" lambda=5.0e-6 dorm=0;
+"MEM" and "MEM1" "MEM2";
+"MEM1" lambda=1.0e-5 dorm=0;
+"MEM2" lambda=1.0e-5 dorm=0;
+"VMS" or "VM1" "VM2";
+"VM1" and "VM1A" "VM1B";
+"VM2" and "VM2A" "VM2B";
+"VM1A" csp "VM1Aev" "VMS1" "VMS2";
+"VM1B" csp "VM1Bev" "VMS1" "VMS2";
+"VM2A" csp "VM2Aev" "VMS1" "VMS2";
+"VM2B" csp "VM2Bev" "VMS1" "VMS2";
+"VM1Aev" lambda=1.0e-6 dorm=0;
+"VM1Bev" lambda=1.0e-6 dorm=0;
+"VM2Aev" lambda=1.0e-6 dorm=0;
+"VM2Bev" lambda=1.0e-6 dorm=0;
+"VMS1" lambda=1.0e-6 dorm=0;
+"VMS2" lambda=1.0e-6 dorm=0;
+
diff --git a/examples/dft/nonmonoton_param.dft b/examples/dft/nonmonoton_param.dft
index e83f3b012..fab011e64 100644
--- a/examples/dft/nonmonoton_param.dft
+++ b/examples/dft/nonmonoton_param.dft
@@ -2,7 +2,7 @@ param x;
 param y;
 toplevel "A";
 "A" or "B" "Z";
-"B" pand "D" "S";
-"Z" lambda=y dorm=0;
-"D" lambda=100 dorm=0;
-"S" lambda=100*x dorm=0;
+"Z" pand "C" "D";
+"B" lambda=y dorm=0;
+"C" lambda=100 dorm=0;
+"D" lambda=100*x dorm=0;
diff --git a/src/builder/ExplicitDFTModelBuilder.cpp b/src/builder/ExplicitDFTModelBuilder.cpp
index 4d794cb2f..46797aa23 100644
--- a/src/builder/ExplicitDFTModelBuilder.cpp
+++ b/src/builder/ExplicitDFTModelBuilder.cpp
@@ -160,23 +160,6 @@ namespace storm {
             return model;
         }
         
-        template<>
-        bool belowThreshold(double const& number) {
-            return number < 0.1;
-        }
-
-        template<>
-        bool belowThreshold(storm::RationalFunction const& number) {
-            storm::RationalFunction threshold = storm::utility::one<storm::RationalFunction>() / 10;
-            std::cout << number << " < " << threshold << ": " << (number < threshold) << std::endl;
-            std::map<storm::Variable, storm::RationalNumber> mapping;
-            
-            storm::RationalFunction eval(number.evaluate(mapping));
-            std::cout << "Evaluated: " << eval << std::endl;
-            return eval < threshold;
-        }
-
-        
         template <typename ValueType>
         std::pair<uint_fast64_t, bool> ExplicitDFTModelBuilder<ValueType>::exploreStates(DFTStatePointer const& state, size_t& rowOffset, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<uint_fast64_t>& markovianStates, std::vector<ValueType>& exitRates) {
             STORM_LOG_TRACE("Explore state: " << mDft.getStateString(state));
@@ -225,29 +208,6 @@ namespace storm {
                 STORM_LOG_ASSERT(nextBE, "NextBE is null.");
                 STORM_LOG_ASSERT(nextBEPair.second == hasDependencies, "Failure due to dependencies does not match.");
                 STORM_LOG_TRACE("With the failure of: " << nextBE->name() << " [" << nextBE->id() << "] in " << mDft.getStateString(state));
-                
-                if (storm::settings::getModule<storm::settings::modules::DFTSettings>().computeApproximation()) {
-                    if (!storm::utility::isZero(exitRate)) {
-                    ValueType rate = nextBE->activeFailureRate();
-                    ValueType div = rate / exitRate;
-                    if (!storm::utility::isZero(exitRate) && belowThreshold(div)) {
-                        // Set transition directly to failed state
-                        auto resultFind = outgoingRates.find(failedIndex);
-                        if (resultFind != outgoingRates.end()) {
-                            // Add to existing transition
-                            resultFind->second += rate;
-                            STORM_LOG_TRACE("Updated transition to " << resultFind->first << " with rate " << rate << " to new rate " << resultFind->second);
-                        } else {
-                            // Insert new transition
-                            outgoingRates.insert(std::make_pair(failedIndex, rate));
-                            STORM_LOG_TRACE("Added transition to " << failedIndex << " with rate " << rate);
-                        }
-                        exitRate += rate;
-                        std::cout << "IGNORE: " << nextBE->name() << " [" << nextBE->id() << "] with rate " << rate << std::endl;
-                        //STORM_LOG_TRACE("Ignore: " << nextBE->name() << " [" << nextBE->id() << "] with rate " << rate);
-                        continue;
-                    }}
-                }
 
                 // Propagate failures
                 storm::storage::DFTStateSpaceGenerationQueues<ValueType> queues;
diff --git a/src/builder/ExplicitDFTModelBuilder.h b/src/builder/ExplicitDFTModelBuilder.h
index eae19cb61..b9c54d2b6 100644
--- a/src/builder/ExplicitDFTModelBuilder.h
+++ b/src/builder/ExplicitDFTModelBuilder.h
@@ -91,9 +91,6 @@ namespace storm {
             std::pair<bool, uint_fast64_t> checkForExploration(DFTStatePointer const& state);
 
         };
-        
-        template<typename ValueType>
-        bool belowThreshold(ValueType const& number);
     }
 }
 
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
new file mode 100644
index 000000000..285301807
--- /dev/null
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -0,0 +1,666 @@
+#include "src/builder/ExplicitDFTModelBuilderApprox.h"
+#include <src/models/sparse/MarkovAutomaton.h>
+#include <src/models/sparse/Ctmc.h>
+#include <src/utility/constants.h>
+#include <src/utility/vector.h>
+#include <src/exceptions/UnexpectedException.h>
+#include "src/settings/modules/DFTSettings.h"
+#include "src/settings/SettingsManager.h"
+#include "src/generator/DftNextStateGenerator.h"
+#include <map>
+
+namespace storm {
+    namespace builder {
+
+        template <typename ValueType>
+        ExplicitDFTModelBuilderApprox<ValueType>::ModelComponents::ModelComponents() : transitionMatrix(), stateLabeling(), markovianStates(), exitRates(), choiceLabeling() {
+            // Intentionally left empty.
+        }
+        
+        template <typename ValueType>
+        ExplicitDFTModelBuilderApprox<ValueType>::ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC) : mDft(dft), enableDC(enableDC), stateStorage(((mDft.stateVectorSize() / 64) + 1) * 64) {
+            // stateVectorSize is bound for size of bitvector
+
+            mStateGenerationInfo = std::make_shared<storm::storage::DFTStateGenerationInfo>(mDft.buildStateGenerationInfo(symmetries));
+        }
+
+
+        template <typename ValueType>
+        std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilderApprox<ValueType>::buildModel(LabelOptions const& labelOpts) {
+            // Initialize
+            bool deterministicModel = false;
+            size_t rowOffset = 0;
+            ModelComponents modelComponents;
+            std::vector<uint_fast64_t> tmpMarkovianStates;
+            storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !deterministicModel, 0);
+
+            if(mergeFailedStates) {
+                // Introduce explicit fail state
+                failedIndex = newIndex;
+                newIndex++;
+                transitionMatrixBuilder.newRowGroup(failedIndex);
+                transitionMatrixBuilder.addNextValue(failedIndex, failedIndex, storm::utility::one<ValueType>());
+                STORM_LOG_TRACE("Introduce fail state with id: " << failedIndex);
+                modelComponents.exitRates.push_back(storm::utility::one<ValueType>());
+                tmpMarkovianStates.push_back(failedIndex);        
+            }
+            
+            // Explore state space
+            DFTStatePointer state = std::make_shared<storm::storage::DFTState<ValueType>>(mDft, *mStateGenerationInfo, newIndex);
+            auto exploreResult = exploreStates(state, rowOffset, transitionMatrixBuilder, tmpMarkovianStates, modelComponents.exitRates);
+            initialStateIndex = exploreResult.first;
+            bool deterministic = exploreResult.second;
+        
+            // Before ending the exploration check for pseudo states which are not initialized yet
+            for (auto & pseudoStatePair : mPseudoStatesMapping) {
+                if (pseudoStatePair.first == 0) {
+                    // Create state from pseudo state and explore
+                    STORM_LOG_ASSERT(stateStorage.stateToId.contains(pseudoStatePair.second), "Pseudo state not contained.");
+                    STORM_LOG_ASSERT(stateStorage.stateToId.getValue(pseudoStatePair.second) >= OFFSET_PSEUDO_STATE, "State is no pseudo state.");
+                    STORM_LOG_TRACE("Create pseudo state from bit vector " << pseudoStatePair.second);
+                    DFTStatePointer pseudoState = std::make_shared<storm::storage::DFTState<ValueType>>(pseudoStatePair.second, mDft, *mStateGenerationInfo, newIndex);
+                    STORM_LOG_ASSERT(pseudoStatePair.second == pseudoState->status(), "Pseudo states do not coincide.");
+                    STORM_LOG_TRACE("Explore pseudo state " << mDft.getStateString(pseudoState) << " with id " << pseudoState->getId());
+                    auto exploreResult = exploreStates(pseudoState, rowOffset, transitionMatrixBuilder, tmpMarkovianStates, modelComponents.exitRates);
+                    deterministic &= exploreResult.second;
+                    STORM_LOG_ASSERT(pseudoStatePair.first == pseudoState->getId(), "Pseudo state ids do not coincide");
+                    STORM_LOG_ASSERT(pseudoState->getId() == exploreResult.first, "Pseudo state ids do not coincide.");
+                }
+            }
+            
+            // Replace pseudo states in matrix
+            std::vector<uint_fast64_t> pseudoStatesVector;
+            for (auto const& pseudoStatePair : mPseudoStatesMapping) {
+                pseudoStatesVector.push_back(pseudoStatePair.first);
+            }
+            STORM_LOG_ASSERT(std::find(pseudoStatesVector.begin(), pseudoStatesVector.end(), 0) == pseudoStatesVector.end(), "Unexplored pseudo state still contained.");
+            transitionMatrixBuilder.replaceColumns(pseudoStatesVector, OFFSET_PSEUDO_STATE);
+            
+            STORM_LOG_DEBUG("Generated " << stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0) << " states");
+            STORM_LOG_DEBUG("Model is " << (deterministic ? "deterministic" : "non-deterministic"));
+
+            size_t stateSize = stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0);
+            // Build Markov Automaton
+            modelComponents.markovianStates = storm::storage::BitVector(stateSize, tmpMarkovianStates);
+            // Build transition matrix
+            modelComponents.transitionMatrix = transitionMatrixBuilder.build(stateSize, stateSize);
+            if (stateSize <= 15) {
+                STORM_LOG_TRACE("Transition matrix: " << std::endl << modelComponents.transitionMatrix);
+            } else {
+                STORM_LOG_TRACE("Transition matrix: too big to print");
+            }
+            STORM_LOG_TRACE("Exit rates: " << modelComponents.exitRates);
+            STORM_LOG_TRACE("Markovian states: " << modelComponents.markovianStates);
+            
+            // Build state labeling
+            modelComponents.stateLabeling = storm::models::sparse::StateLabeling(stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0));
+            // Initial state is always first state without any failure
+            modelComponents.stateLabeling.addLabel("init");
+            modelComponents.stateLabeling.addLabelToState("init", initialStateIndex);
+            // Label all states corresponding to their status (failed, failsafe, failed BE)
+            if(labelOpts.buildFailLabel) {
+                modelComponents.stateLabeling.addLabel("failed");
+            } 
+            if(labelOpts.buildFailSafeLabel) {
+                modelComponents.stateLabeling.addLabel("failsafe");
+            }
+            
+            // Collect labels for all BE
+            std::vector<std::shared_ptr<storage::DFTBE<ValueType>>> basicElements = mDft.getBasicElements();
+            for (std::shared_ptr<storage::DFTBE<ValueType>> elem : basicElements) {
+                if(labelOpts.beLabels.count(elem->name()) > 0) {
+                    modelComponents.stateLabeling.addLabel(elem->name() + "_fail");
+                }
+            }
+
+            if(mergeFailedStates) {
+                modelComponents.stateLabeling.addLabelToState("failed", failedIndex);
+            }
+            for (auto const& stateIdPair : stateStorage.stateToId) {
+                storm::storage::BitVector state = stateIdPair.first;
+                size_t stateId = stateIdPair.second;
+                if (!mergeFailedStates && labelOpts.buildFailLabel && mDft.hasFailed(state, *mStateGenerationInfo)) {
+                    modelComponents.stateLabeling.addLabelToState("failed", stateId);
+                }
+                if (labelOpts.buildFailSafeLabel && mDft.isFailsafe(state, *mStateGenerationInfo)) {
+                    modelComponents.stateLabeling.addLabelToState("failsafe", stateId);
+                };
+                // Set fail status for each BE
+                for (std::shared_ptr<storage::DFTBE<ValueType>> elem : basicElements) {
+                    if (labelOpts.beLabels.count(elem->name()) > 0 && storm::storage::DFTState<ValueType>::hasFailed(state, mStateGenerationInfo->getStateIndex(elem->id())) ) {
+                        modelComponents.stateLabeling.addLabelToState(elem->name() + "_fail", stateId);
+                    }
+                }
+            }
+
+            std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
+            
+            if (deterministic) {
+                // Turn the probabilities into rates by multiplying each row with the exit rate of the state.
+                // TODO Matthias: avoid transforming back and forth
+                storm::storage::SparseMatrix<ValueType> rateMatrix(modelComponents.transitionMatrix);
+                for (uint_fast64_t row = 0; row < rateMatrix.getRowCount(); ++row) {
+                    STORM_LOG_ASSERT(row < modelComponents.markovianStates.size(), "Row exceeds no. of markovian states.");
+                    if (modelComponents.markovianStates.get(row)) {
+                        for (auto& entry : rateMatrix.getRow(row)) {
+                            entry.setValue(entry.getValue() * modelComponents.exitRates[row]);
+                        }
+                    }
+                }
+                model = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(std::move(rateMatrix), std::move(modelComponents.exitRates), std::move(modelComponents.stateLabeling));
+            } else {
+                std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma = std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), std::move(modelComponents.markovianStates), std::move(modelComponents.exitRates), true);
+                if (ma->hasOnlyTrivialNondeterminism()) {
+                    // Markov automaton can be converted into CTMC
+                    model = ma->convertToCTMC();
+                } else {
+                    model = ma;
+                }
+            }
+            
+            return model;
+        }
+        
+        template <typename ValueType>
+        std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilderApprox<ValueType>::buildModelApprox(LabelOptions const& labelOpts) {
+            // Initialize
+            bool deterministicModel = false;
+            size_t rowOffset = 0;
+            ModelComponents modelComponents;
+            std::vector<uint_fast64_t> tmpMarkovianStates;
+            storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !deterministicModel, 0);
+            
+            if(mergeFailedStates) {
+                // Introduce explicit fail state
+                failedIndex = newIndex;
+                newIndex++;
+                transitionMatrixBuilder.newRowGroup(failedIndex);
+                transitionMatrixBuilder.addNextValue(failedIndex, failedIndex, storm::utility::one<ValueType>());
+                STORM_LOG_TRACE("Introduce fail state with id: " << failedIndex);
+                modelComponents.exitRates.push_back(storm::utility::one<ValueType>());
+                tmpMarkovianStates.push_back(failedIndex);
+            }
+            
+            // Initialize generator
+            storm::generator::DftNextStateGenerator<ValueType, uint_fast64_t> generator(mDft, *mStateGenerationInfo);
+            
+            // Explore state space
+            typename storm::generator::DftNextStateGenerator<ValueType, uint_fast64_t>::StateToIdCallback stateToIdCallback = [this] (DFTStatePointer const& state) -> uint_fast64_t {
+                uint_fast64_t id = newIndex++;
+                std::cout << "Added state " << id << std::endl;
+                return id;
+            };
+            
+            uint_fast64_t id = generator.getInitialStates(stateToIdCallback)[0];
+            std::cout << "Initial state " << id << std::endl;
+            DFTStatePointer state = std::make_shared<storm::storage::DFTState<ValueType>>(mDft, *mStateGenerationInfo, newIndex);
+            auto exploreResult = exploreStates(state, rowOffset, transitionMatrixBuilder, tmpMarkovianStates, modelComponents.exitRates);
+            initialStateIndex = exploreResult.first;
+            bool deterministic = exploreResult.second;
+            
+            // Before ending the exploration check for pseudo states which are not initialized yet
+            for (auto & pseudoStatePair : mPseudoStatesMapping) {
+                if (pseudoStatePair.first == 0) {
+                    // Create state from pseudo state and explore
+                    STORM_LOG_ASSERT(stateStorage.stateToId.contains(pseudoStatePair.second), "Pseudo state not contained.");
+                    STORM_LOG_ASSERT(stateStorage.stateToId.getValue(pseudoStatePair.second) >= OFFSET_PSEUDO_STATE, "State is no pseudo state.");
+                    STORM_LOG_TRACE("Create pseudo state from bit vector " << pseudoStatePair.second);
+                    DFTStatePointer pseudoState = std::make_shared<storm::storage::DFTState<ValueType>>(pseudoStatePair.second, mDft, *mStateGenerationInfo, newIndex);
+                    STORM_LOG_ASSERT(pseudoStatePair.second == pseudoState->status(), "Pseudo states do not coincide.");
+                    STORM_LOG_TRACE("Explore pseudo state " << mDft.getStateString(pseudoState) << " with id " << pseudoState->getId());
+                    auto exploreResult = exploreStates(pseudoState, rowOffset, transitionMatrixBuilder, tmpMarkovianStates, modelComponents.exitRates);
+                    deterministic &= exploreResult.second;
+                    STORM_LOG_ASSERT(pseudoStatePair.first == pseudoState->getId(), "Pseudo state ids do not coincide");
+                    STORM_LOG_ASSERT(pseudoState->getId() == exploreResult.first, "Pseudo state ids do not coincide.");
+                }
+            }
+            
+            // Replace pseudo states in matrix
+            std::vector<uint_fast64_t> pseudoStatesVector;
+            for (auto const& pseudoStatePair : mPseudoStatesMapping) {
+                pseudoStatesVector.push_back(pseudoStatePair.first);
+            }
+            STORM_LOG_ASSERT(std::find(pseudoStatesVector.begin(), pseudoStatesVector.end(), 0) == pseudoStatesVector.end(), "Unexplored pseudo state still contained.");
+            transitionMatrixBuilder.replaceColumns(pseudoStatesVector, OFFSET_PSEUDO_STATE);
+            
+            STORM_LOG_DEBUG("Generated " << stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0) << " states");
+            STORM_LOG_DEBUG("Model is " << (deterministic ? "deterministic" : "non-deterministic"));
+            
+            size_t stateSize = stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0);
+            // Build Markov Automaton
+            modelComponents.markovianStates = storm::storage::BitVector(stateSize, tmpMarkovianStates);
+            // Build transition matrix
+            modelComponents.transitionMatrix = transitionMatrixBuilder.build(stateSize, stateSize);
+            if (stateSize <= 15) {
+                STORM_LOG_TRACE("Transition matrix: " << std::endl << modelComponents.transitionMatrix);
+            } else {
+                STORM_LOG_TRACE("Transition matrix: too big to print");
+            }
+            STORM_LOG_TRACE("Exit rates: " << modelComponents.exitRates);
+            STORM_LOG_TRACE("Markovian states: " << modelComponents.markovianStates);
+            
+            // Build state labeling
+            modelComponents.stateLabeling = storm::models::sparse::StateLabeling(stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0));
+            // Initial state is always first state without any failure
+            modelComponents.stateLabeling.addLabel("init");
+            modelComponents.stateLabeling.addLabelToState("init", initialStateIndex);
+            // Label all states corresponding to their status (failed, failsafe, failed BE)
+            if(labelOpts.buildFailLabel) {
+                modelComponents.stateLabeling.addLabel("failed");
+            }
+            if(labelOpts.buildFailSafeLabel) {
+                modelComponents.stateLabeling.addLabel("failsafe");
+            }
+            
+            // Collect labels for all BE
+            std::vector<std::shared_ptr<storage::DFTBE<ValueType>>> basicElements = mDft.getBasicElements();
+            for (std::shared_ptr<storage::DFTBE<ValueType>> elem : basicElements) {
+                if(labelOpts.beLabels.count(elem->name()) > 0) {
+                    modelComponents.stateLabeling.addLabel(elem->name() + "_fail");
+                }
+            }
+            
+            if(mergeFailedStates) {
+                modelComponents.stateLabeling.addLabelToState("failed", failedIndex);
+            }
+            for (auto const& stateIdPair : stateStorage.stateToId) {
+                storm::storage::BitVector state = stateIdPair.first;
+                size_t stateId = stateIdPair.second;
+                if (!mergeFailedStates && labelOpts.buildFailLabel && mDft.hasFailed(state, *mStateGenerationInfo)) {
+                    modelComponents.stateLabeling.addLabelToState("failed", stateId);
+                }
+                if (labelOpts.buildFailSafeLabel && mDft.isFailsafe(state, *mStateGenerationInfo)) {
+                    modelComponents.stateLabeling.addLabelToState("failsafe", stateId);
+                };
+                // Set fail status for each BE
+                for (std::shared_ptr<storage::DFTBE<ValueType>> elem : basicElements) {
+                    if (labelOpts.beLabels.count(elem->name()) > 0 && storm::storage::DFTState<ValueType>::hasFailed(state, mStateGenerationInfo->getStateIndex(elem->id())) ) {
+                        modelComponents.stateLabeling.addLabelToState(elem->name() + "_fail", stateId);
+                    }
+                }
+            }
+            
+            std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
+            
+            if (deterministic) {
+                // Turn the probabilities into rates by multiplying each row with the exit rate of the state.
+                // TODO Matthias: avoid transforming back and forth
+                storm::storage::SparseMatrix<ValueType> rateMatrix(modelComponents.transitionMatrix);
+                for (uint_fast64_t row = 0; row < rateMatrix.getRowCount(); ++row) {
+                    STORM_LOG_ASSERT(row < modelComponents.markovianStates.size(), "Row exceeds no. of markovian states.");
+                    if (modelComponents.markovianStates.get(row)) {
+                        for (auto& entry : rateMatrix.getRow(row)) {
+                            entry.setValue(entry.getValue() * modelComponents.exitRates[row]);
+                        }
+                    }
+                }
+                model = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(std::move(rateMatrix), std::move(modelComponents.exitRates), std::move(modelComponents.stateLabeling));
+            } else {
+                std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma = std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), std::move(modelComponents.markovianStates), std::move(modelComponents.exitRates), true);
+                if (ma->hasOnlyTrivialNondeterminism()) {
+                    // Markov automaton can be converted into CTMC
+                    model = ma->convertToCTMC();
+                } else {
+                    model = ma;
+                }
+            }
+            
+            return model;
+
+        }
+        
+        template<>
+        bool belowThreshold(double const& number) {
+            return number < 0.1;
+        }
+
+        template<>
+        bool belowThreshold(storm::RationalFunction const& number) {
+            storm::RationalFunction threshold = storm::utility::one<storm::RationalFunction>() / 10;
+            std::cout << number << " < " << threshold << ": " << (number < threshold) << std::endl;
+            std::map<storm::Variable, storm::RationalNumber> mapping;
+            
+            storm::RationalFunction eval(number.evaluate(mapping));
+            std::cout << "Evaluated: " << eval << std::endl;
+            return eval < threshold;
+        }
+
+        
+        template <typename ValueType>
+        std::pair<uint_fast64_t, bool> ExplicitDFTModelBuilderApprox<ValueType>::exploreStates(DFTStatePointer const& state, size_t& rowOffset, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<uint_fast64_t>& markovianStates, std::vector<ValueType>& exitRates) {
+            STORM_LOG_TRACE("Explore state: " << mDft.getStateString(state));
+
+            auto explorePair = checkForExploration(state);
+            if (!explorePair.first) {
+                // State does not need any exploration
+                return std::make_pair(explorePair.second, true);
+            }
+
+            
+            // Initialization
+            // TODO Matthias: set Markovian states directly as bitvector?
+            std::map<uint_fast64_t, ValueType> outgoingRates;
+            std::vector<std::map<uint_fast64_t, ValueType>> outgoingProbabilities;
+            bool hasDependencies = state->nrFailableDependencies() > 0;
+            size_t failableCount = hasDependencies ? state->nrFailableDependencies() : state->nrFailableBEs();
+            size_t smallest = 0;
+            ValueType exitRate = storm::utility::zero<ValueType>();
+            bool deterministic = !hasDependencies;
+
+            // Absorbing state
+            if (mDft.hasFailed(state) || mDft.isFailsafe(state) || state->nrFailableBEs() == 0) {
+                uint_fast64_t stateId = addState(state);
+                STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not coincide.");
+
+                // Add self loop
+                transitionMatrixBuilder.newRowGroup(stateId + rowOffset);
+                transitionMatrixBuilder.addNextValue(stateId + rowOffset, stateId, storm::utility::one<ValueType>());
+                STORM_LOG_TRACE("Added self loop for " << stateId);
+                exitRates.push_back(storm::utility::one<ValueType>());
+                STORM_LOG_ASSERT(exitRates.size()-1 == stateId, "No. of considered states does not match state id.");
+                markovianStates.push_back(stateId);
+                // No further exploration required
+                return std::make_pair(stateId, true);
+            }
+
+            // Let BE fail
+            while (smallest < failableCount) {
+                STORM_LOG_ASSERT(!mDft.hasFailed(state), "Dft has failed.");
+
+                // Construct new state as copy from original one
+                DFTStatePointer newState = std::make_shared<storm::storage::DFTState<ValueType>>(*state);
+                std::pair<std::shared_ptr<storm::storage::DFTBE<ValueType> const>, bool> nextBEPair = newState->letNextBEFail(smallest++);
+                std::shared_ptr<storm::storage::DFTBE<ValueType> const>& nextBE = nextBEPair.first;
+                STORM_LOG_ASSERT(nextBE, "NextBE is null.");
+                STORM_LOG_ASSERT(nextBEPair.second == hasDependencies, "Failure due to dependencies does not match.");
+                STORM_LOG_TRACE("With the failure of: " << nextBE->name() << " [" << nextBE->id() << "] in " << mDft.getStateString(state));
+                
+                if (storm::settings::getModule<storm::settings::modules::DFTSettings>().computeApproximation()) {
+                    if (!storm::utility::isZero(exitRate)) {
+                        ValueType rate = nextBE->activeFailureRate();
+                        ValueType div = rate / exitRate;
+                        if (!storm::utility::isZero(exitRate) && belowThreshold(div)) {
+                            // Set transition directly to failed state
+                            auto resultFind = outgoingRates.find(failedIndex);
+                            if (resultFind != outgoingRates.end()) {
+                                // Add to existing transition
+                                resultFind->second += rate;
+                                STORM_LOG_TRACE("Updated transition to " << resultFind->first << " with rate " << rate << " to new rate " << resultFind->second);
+                            } else {
+                                // Insert new transition
+                                outgoingRates.insert(std::make_pair(failedIndex, rate));
+                                STORM_LOG_TRACE("Added transition to " << failedIndex << " with rate " << rate);
+                            }
+                            exitRate += rate;
+                            std::cout << "IGNORE: " << nextBE->name() << " [" << nextBE->id() << "] with rate " << rate << std::endl;
+                            //STORM_LOG_TRACE("Ignore: " << nextBE->name() << " [" << nextBE->id() << "] with rate " << rate);
+                            continue;
+                        }
+                    }
+                }
+
+                // Propagate failures
+                storm::storage::DFTStateSpaceGenerationQueues<ValueType> queues;
+
+                for (DFTGatePointer parent : nextBE->parents()) {
+                    if (newState->isOperational(parent->id())) {
+                        queues.propagateFailure(parent);
+                    }
+                }
+                for (DFTRestrictionPointer restr : nextBE->restrictions()) {
+                    queues.checkRestrictionLater(restr);
+                }
+
+                while (!queues.failurePropagationDone()) {
+                    DFTGatePointer next = queues.nextFailurePropagation();
+                    next->checkFails(*newState, queues);
+                    newState->updateFailableDependencies(next->id());
+                }
+                
+                while(!queues.restrictionChecksDone()) {
+                    DFTRestrictionPointer next = queues.nextRestrictionCheck();
+                    next->checkFails(*newState, queues);
+                    newState->updateFailableDependencies(next->id());
+                }
+                
+                if(newState->isInvalid()) {
+                    continue;
+                }
+                bool dftFailed = newState->hasFailed(mDft.getTopLevelIndex());
+                
+                while (!dftFailed && !queues.failsafePropagationDone()) {
+                    DFTGatePointer next = queues.nextFailsafePropagation();
+                    next->checkFailsafe(*newState, queues);
+                }
+
+                while (!dftFailed && enableDC && !queues.dontCarePropagationDone()) {
+                    DFTElementPointer next = queues.nextDontCarePropagation();
+                    next->checkDontCareAnymore(*newState, queues);
+                }
+                
+                // Update failable dependencies
+                if (!dftFailed) {
+                    newState->updateFailableDependencies(nextBE->id());
+                    newState->updateDontCareDependencies(nextBE->id());
+                }
+                
+                uint_fast64_t newStateId;
+                if(dftFailed && mergeFailedStates) {
+                    newStateId = failedIndex;
+                } else {
+                    // Explore new state recursively
+                    auto explorePair = exploreStates(newState, rowOffset, transitionMatrixBuilder, markovianStates, exitRates);
+                    newStateId = explorePair.first;
+                    deterministic &= explorePair.second;
+                }
+
+                // Set transitions
+                if (hasDependencies) {
+                    // Failure is due to dependency -> add non-deterministic choice
+                    std::map<uint_fast64_t, ValueType> choiceProbabilities;
+                    std::shared_ptr<storm::storage::DFTDependency<ValueType> const> dependency = mDft.getDependency(state->getDependencyId(smallest-1));
+                    choiceProbabilities.insert(std::make_pair(newStateId, dependency->probability()));
+                    STORM_LOG_TRACE("Added transition to " << newStateId << " with probability " << dependency->probability());
+
+                    if (!storm::utility::isOne(dependency->probability())) {
+                        // Add transition to state where dependency was unsuccessful
+                        DFTStatePointer unsuccessfulState = std::make_shared<storm::storage::DFTState<ValueType>>(*state);
+                        unsuccessfulState->letDependencyBeUnsuccessful(smallest-1);
+                        auto explorePair = exploreStates(unsuccessfulState, rowOffset, transitionMatrixBuilder, markovianStates, exitRates);
+                        uint_fast64_t unsuccessfulStateId = explorePair.first;
+                        deterministic &= explorePair.second;
+                        ValueType remainingProbability = storm::utility::one<ValueType>() - dependency->probability();
+                        choiceProbabilities.insert(std::make_pair(unsuccessfulStateId, remainingProbability));
+                        STORM_LOG_TRACE("Added transition to " << unsuccessfulStateId << " with remaining probability " << remainingProbability);
+                    }
+                    outgoingProbabilities.push_back(choiceProbabilities);
+                } else {
+                    // Set failure rate according to activation
+                    bool isActive = true;
+                    if (mDft.hasRepresentant(nextBE->id())) {
+                        // Active must be checked for the state we are coming from as this state is responsible for the
+                        // rate and not the new state we are going to
+                        isActive = state->isActive(mDft.getRepresentant(nextBE->id())->id());
+                    }
+                    ValueType rate = isActive ? nextBE->activeFailureRate() : nextBE->passiveFailureRate();
+                    STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Rate is 0.");
+                    auto resultFind = outgoingRates.find(newStateId);
+                    if (resultFind != outgoingRates.end()) {
+                        // Add to existing transition
+                        resultFind->second += rate;
+                        STORM_LOG_TRACE("Updated transition to " << resultFind->first << " with " << (isActive ? "active" : "passive") << " rate " << rate << " to new rate " << resultFind->second);
+                    } else {
+                        // Insert new transition
+                        outgoingRates.insert(std::make_pair(newStateId, rate));
+                        STORM_LOG_TRACE("Added transition to " << newStateId << " with " << (isActive ? "active" : "passive") << " rate " << rate);
+                    }
+                    exitRate += rate;
+                }
+
+            } // end while failing BE
+            
+            // Add state
+            uint_fast64_t stateId = addState(state);
+            STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not match.");
+            STORM_LOG_ASSERT(stateId == newIndex-1, "Id does not match no. of states.");
+            
+            if (hasDependencies) {
+                // Add all probability transitions
+                STORM_LOG_ASSERT(outgoingRates.empty(), "Outgoing transitions not empty.");
+                transitionMatrixBuilder.newRowGroup(stateId + rowOffset);
+                for (size_t i = 0; i < outgoingProbabilities.size(); ++i, ++rowOffset) {
+                    STORM_LOG_ASSERT(outgoingProbabilities[i].size() == 1 || outgoingProbabilities[i].size() == 2, "No. of outgoing transitions is not valid.");
+                    for (auto it = outgoingProbabilities[i].begin(); it != outgoingProbabilities[i].end(); ++it)
+                    {
+                        STORM_LOG_TRACE("Set transition from " << stateId << " to " << it->first << " with probability " << it->second);
+                        transitionMatrixBuilder.addNextValue(stateId + rowOffset, it->first, it->second);
+                    }
+                }
+                rowOffset--; // One increment too many
+            } else {
+                // Try to merge pseudo states with their instantiation
+                // TODO Matthias: improve?
+                for (auto it = outgoingRates.begin(); it != outgoingRates.end(); ) {
+                    if (it->first >= OFFSET_PSEUDO_STATE) {
+                        uint_fast64_t newId = it->first - OFFSET_PSEUDO_STATE;
+                        STORM_LOG_ASSERT(newId < mPseudoStatesMapping.size(), "Id is not valid.");
+                        if (mPseudoStatesMapping[newId].first > 0) {
+                            // State exists already
+                            newId = mPseudoStatesMapping[newId].first;
+                            auto itFind = outgoingRates.find(newId);
+                            if (itFind != outgoingRates.end()) {
+                                // Add probability from pseudo state to instantiation
+                                itFind->second += it->second;
+                                STORM_LOG_TRACE("Merged pseudo state " << newId << " adding rate " << it->second << " to total rate of " << itFind->second);
+                            } else {
+                                // Only change id
+                                outgoingRates.emplace(newId, it->second);
+                                STORM_LOG_TRACE("Instantiated pseudo state " << newId << " with rate " << it->second);
+                            }
+                            // Remove pseudo state
+                            it = outgoingRates.erase(it);
+                        } else {
+                            ++it;
+                        }
+                    } else {
+                        ++it;
+                    }
+                }
+                
+                // Add all rate transitions
+                STORM_LOG_ASSERT(outgoingProbabilities.empty(), "Outgoing probabilities not empty.");
+                transitionMatrixBuilder.newRowGroup(state->getId() + rowOffset);
+                STORM_LOG_TRACE("Exit rate for " << state->getId() << ": " << exitRate);
+                for (auto it = outgoingRates.begin(); it != outgoingRates.end(); ++it)
+                {
+                    ValueType probability = it->second / exitRate; // Transform rate to probability
+                    STORM_LOG_TRACE("Set transition from " << state->getId() << " to " << it->first << " with rate " << it->second);
+                    transitionMatrixBuilder.addNextValue(state->getId() + rowOffset, it->first, probability);
+                }
+
+                markovianStates.push_back(state->getId());
+            }
+            
+            STORM_LOG_TRACE("Finished exploring state: " << mDft.getStateString(state));
+            exitRates.push_back(exitRate);
+            STORM_LOG_ASSERT(exitRates.size()-1 == state->getId(), "Id does not match no. of states.");
+            return std::make_pair(state->getId(), deterministic);
+        }
+        
+        template <typename ValueType>
+        std::pair<bool, uint_fast64_t> ExplicitDFTModelBuilderApprox<ValueType>::checkForExploration(DFTStatePointer const& state) {
+            bool changed = false;
+            if (mStateGenerationInfo->hasSymmetries()) {
+                // Order state by symmetry
+                STORM_LOG_TRACE("Check for symmetry: " << mDft.getStateString(state));
+                changed = state->orderBySymmetry();
+                STORM_LOG_TRACE("State " << (changed ? "changed to " : "did not change") << (changed ? mDft.getStateString(state) : ""));
+            }
+            
+            if (stateStorage.stateToId.contains(state->status())) {
+                // State already exists
+                uint_fast64_t stateId = stateStorage.stateToId.getValue(state->status());
+                STORM_LOG_TRACE("State " << mDft.getStateString(state) << " with id " << stateId << " already exists");
+                
+                if (changed || stateId < OFFSET_PSEUDO_STATE) {
+                    // State is changed or an explored "normal" state
+                    return std::make_pair(false, stateId);
+                }
+                
+                stateId -= OFFSET_PSEUDO_STATE;
+                STORM_LOG_ASSERT(stateId < mPseudoStatesMapping.size(), "Id not valid.");
+                if (mPseudoStatesMapping[stateId].first > 0) {
+                    // Pseudo state already explored
+                    return std::make_pair(false, mPseudoStatesMapping[stateId].first);
+                }
+                
+                STORM_LOG_ASSERT(mPseudoStatesMapping[stateId].second == state->status(), "States do not coincide.");
+                STORM_LOG_TRACE("Pseudo state " << mDft.getStateString(state) << " can be explored now");
+                return std::make_pair(true, stateId);
+            } else {
+                // State does not exists
+                if (changed) {
+                    // Remember state for later creation
+                    state->setId(mPseudoStatesMapping.size() + OFFSET_PSEUDO_STATE);
+                    mPseudoStatesMapping.push_back(std::make_pair(0, state->status()));
+                    stateStorage.stateToId.findOrAdd(state->status(), state->getId());
+                    STORM_LOG_TRACE("Remember state for later creation: " << mDft.getStateString(state));
+                    return std::make_pair(false, state->getId());
+                } else {
+                    // State needs exploration
+                    return std::make_pair(true, 0);
+                }
+            }
+        }
+
+        template <typename ValueType>
+        uint_fast64_t ExplicitDFTModelBuilderApprox<ValueType>::addState(DFTStatePointer const& state) {
+            uint_fast64_t stateId;
+            // TODO remove
+            bool changed = state->orderBySymmetry();
+            STORM_LOG_ASSERT(!changed, "State to add has changed by applying symmetry.");
+            
+            // Check if state already exists
+            if (stateStorage.stateToId.contains(state->status())) {
+                // State already exists
+                stateId = stateStorage.stateToId.getValue(state->status());
+                STORM_LOG_TRACE("State " << mDft.getStateString(state) << " with id " << stateId << " already exists");
+                
+                // Check if possible pseudo state can be created now
+                STORM_LOG_ASSERT(stateId >= OFFSET_PSEUDO_STATE, "State is no pseudo state.");
+                stateId -= OFFSET_PSEUDO_STATE;
+                STORM_LOG_ASSERT(stateId < mPseudoStatesMapping.size(), "Pseudo state not known.");
+                if (mPseudoStatesMapping[stateId].first == 0) {
+                    // Create pseudo state now
+                    STORM_LOG_ASSERT(mPseudoStatesMapping[stateId].second == state->status(), "Pseudo states do not coincide.");
+                    state->setId(newIndex++);
+                    mPseudoStatesMapping[stateId].first = state->getId();
+                    stateId = state->getId();
+                    stateStorage.stateToId.setOrAdd(state->status(), stateId);
+                    STORM_LOG_TRACE("Now create state " << mDft.getStateString(state) << " with id " << stateId);
+                    return stateId;
+                } else {
+                    STORM_LOG_ASSERT(false, "Pseudo state already created.");
+                    return 0;
+                }
+            } else {
+                // Create new state
+                state->setId(newIndex++);
+                stateId = stateStorage.stateToId.findOrAdd(state->status(), state->getId());
+                STORM_LOG_TRACE("New state: " << mDft.getStateString(state));
+                return stateId;
+            }
+        }
+
+
+        // Explicitly instantiate the class.
+        template class ExplicitDFTModelBuilderApprox<double>;
+
+#ifdef STORM_HAVE_CARL
+        template class ExplicitDFTModelBuilderApprox<storm::RationalFunction>;
+#endif
+
+    } // namespace builder
+} // namespace storm
+
+
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
new file mode 100644
index 000000000..d03681cbe
--- /dev/null
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -0,0 +1,105 @@
+#ifndef EXPLICITDFTMODELBUILDERAPPROX_H
+#define	EXPLICITDFTMODELBUILDERAPPROX_H
+
+#include <src/models/sparse/StateLabeling.h>
+#include <src/models/sparse/StandardRewardModel.h>
+#include <src/models/sparse/Model.h>
+#include <src/storage/SparseMatrix.h>
+#include "src/storage/sparse/StateStorage.h"
+#include <src/storage/dft/DFT.h>
+#include <src/storage/dft/SymmetricUnits.h>
+#include <boost/container/flat_set.hpp>
+#include <boost/optional/optional.hpp>
+#include <stack>
+#include <unordered_set>
+
+namespace storm {
+    namespace builder {
+
+        template<typename ValueType>
+        class ExplicitDFTModelBuilderApprox {
+
+            using DFTElementPointer = std::shared_ptr<storm::storage::DFTElement<ValueType>>;
+            using DFTElementCPointer = std::shared_ptr<storm::storage::DFTElement<ValueType> const>;
+            using DFTGatePointer = std::shared_ptr<storm::storage::DFTGate<ValueType>>;
+            using DFTStatePointer = std::shared_ptr<storm::storage::DFTState<ValueType>>;
+            using DFTRestrictionPointer = std::shared_ptr<storm::storage::DFTRestriction<ValueType>>;
+
+
+            // A structure holding the individual components of a model.
+            struct ModelComponents {
+                ModelComponents();
+
+                // The transition matrix.
+                storm::storage::SparseMatrix<ValueType> transitionMatrix;
+
+                // The state labeling.
+                storm::models::sparse::StateLabeling stateLabeling;
+
+                // The Markovian states.
+                storm::storage::BitVector markovianStates;
+
+                // The exit rates.
+                std::vector<ValueType> exitRates;
+
+                // A vector that stores a labeling for each choice.
+                boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> choiceLabeling;
+            };
+            
+            const uint_fast64_t OFFSET_PSEUDO_STATE = UINT_FAST64_MAX / 2;
+            
+            storm::storage::DFT<ValueType> const& mDft;
+            std::shared_ptr<storm::storage::DFTStateGenerationInfo> mStateGenerationInfo;
+            //TODO Matthias: remove when everything works
+            std::vector<std::pair<uint_fast64_t, storm::storage::BitVector>> mPseudoStatesMapping; // vector of (id to concrete state, bitvector)
+            size_t newIndex = 0;
+            bool mergeFailedStates = true;
+            bool enableDC = true;
+            size_t failedIndex = 0;
+            size_t initialStateIndex = 0;
+            
+            // Internal information about the states that were explored.
+            storm::storage::sparse::StateStorage<uint_fast64_t> stateStorage;
+
+        public:
+            struct LabelOptions {
+                bool buildFailLabel = true;
+                bool buildFailSafeLabel = false;
+                std::set<std::string> beLabels = {};
+            };
+            
+            ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC);
+
+            std::shared_ptr<storm::models::sparse::Model<ValueType>> buildModel(LabelOptions const& labelOpts);
+
+            // TODO Matthias: only temporary used for avoiding crashing everything
+            std::shared_ptr<storm::models::sparse::Model<ValueType>> buildModelApprox(LabelOptions const& labelOpts);
+            
+        private:
+            std::pair<uint_fast64_t, bool> exploreStates(DFTStatePointer const& state, size_t& rowOffset, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<uint_fast64_t>& markovianStates, std::vector<ValueType>& exitRates);
+            
+            /*!
+             * Adds a state to the explored states and handles pseudo states.
+             *
+             * @param state The state to add.
+             * @return Id of added state.
+             */
+            uint_fast64_t addState(DFTStatePointer const& state);
+            
+            /*!
+             * Check if state needs an exploration and remember pseudo states for later creation.
+             *
+             * @param state State which might need exploration.
+             * @return Pair of flag indicating whether the state needs exploration now and the state id if the state already
+             * exists.
+             */
+            std::pair<bool, uint_fast64_t> checkForExploration(DFTStatePointer const& state);
+
+        };
+        
+        template<typename ValueType>
+        bool belowThreshold(ValueType const& number);
+    }
+}
+
+#endif	/* EXPLICITDFTMODELBUILDERAPPROX_H */
diff --git a/src/generator/DftNextStateGenerator.cpp b/src/generator/DftNextStateGenerator.cpp
index b56f8a358..3138fef6a 100644
--- a/src/generator/DftNextStateGenerator.cpp
+++ b/src/generator/DftNextStateGenerator.cpp
@@ -2,38 +2,30 @@
 
 #include "src/utility/constants.h"
 #include "src/utility/macros.h"
-#include "src/exceptions/WrongFormatException.h"
+#include "src/exceptions/NotImplementedException.h"
 
 namespace storm {
     namespace generator {
         
         template<typename ValueType, typename StateType>
-        DftNextStateGenerator<ValueType, StateType>::DftNextStateGenerator(storm::storage::DFT<ValueType> const& dft) : mDft(dft), state(nullptr), comparator() {
+        DftNextStateGenerator<ValueType, StateType>::DftNextStateGenerator(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo) : mDft(dft), mStateGenerationInfo(stateGenerationInfo), state(nullptr), comparator() {
             // Intentionally left empty.
         }
         
         template<typename ValueType, typename StateType>
         bool DftNextStateGenerator<ValueType, StateType>::isDeterministicModel() const {
-            assert(false);
-            return true;
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This functionality is not yet implemented.");
         }
         
         template<typename ValueType, typename StateType>
         std::vector<StateType> DftNextStateGenerator<ValueType, StateType>::getInitialStates(StateToIdCallback const& stateToIdCallback) {
-            // FIXME: This only works for models with exactly one initial state. We should make this more general.
-            /*CompressedState initialState(variableInformation.getTotalBitOffset());
-            
-            // We need to initialize the values of the variables to their initial value.
-            for (auto const& booleanVariable : variableInformation.booleanVariables) {
-                initialState.set(booleanVariable.bitOffset, booleanVariable.initialValue);
-            }
-            for (auto const& integerVariable : variableInformation.integerVariables) {
-                initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast<uint_fast64_t>(integerVariable.initialValue - integerVariable.lowerBound));
-            }
+            DFTStatePointer initialState = std::make_shared<storm::storage::DFTState<ValueType>>(mDft, mStateGenerationInfo, 0);
 
-            // Register initial state and return it.
+            // Register initial state
             StateType id = stateToIdCallback(initialState);
-            return {id};*/
+
+            initialState->setId(id);
+            return {id};
         }
         
         template<typename ValueType, typename StateType>
@@ -43,14 +35,12 @@ namespace storm {
             
             // Also, we need to store a pointer to the state itself, because we need to be able to access it when expanding it.
             this->state = &state;*/
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This functionality is not yet implemented.");
         }
         
         template<typename ValueType, typename StateType>
         bool DftNextStateGenerator<ValueType, StateType>::satisfies(storm::expressions::Expression const& expression) const {
-           /* if (expression.isTrue()) {
-                return true;
-            }
-            return evaluator.asBool(expression);*/
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This functionality is not yet implemented.");
         }
         
         template<typename ValueType, typename StateType>
@@ -147,6 +137,7 @@ namespace storm {
             
             result.setExpanded();
             return result;*/
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This functionality is not yet implemented.");
         }
         
         
diff --git a/src/generator/DftNextStateGenerator.h b/src/generator/DftNextStateGenerator.h
index 6c8e5538d..17a7dd25a 100644
--- a/src/generator/DftNextStateGenerator.h
+++ b/src/generator/DftNextStateGenerator.h
@@ -9,17 +9,20 @@
 namespace storm {
     namespace generator {
         
-        template<typename ValueType, typename StateType = uint32_t>
+        template<typename ValueType, typename StateType = uint_fast64_t>
         class DftNextStateGenerator : public NextStateGenerator<ValueType, std::shared_ptr<storm::storage::DFTState<ValueType>>, StateType> {
+
+            using DFTStatePointer = std::shared_ptr<storm::storage::DFTState<ValueType>>;
+
         public:
-            typedef typename NextStateGenerator<ValueType, std::shared_ptr<storm::storage::DFTState<ValueType>>, StateType>::StateToIdCallback StateToIdCallback;
+            typedef typename NextStateGenerator<ValueType, DFTStatePointer, StateType>::StateToIdCallback StateToIdCallback;
             
-            DftNextStateGenerator(storm::storage::DFT<ValueType> const& dft);
+            DftNextStateGenerator(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo);
                         
             virtual bool isDeterministicModel() const override;
             virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) override;
 
-            virtual void load(std::shared_ptr<storm::storage::DFTState<ValueType>> const& state) override;
+            virtual void load(DFTStatePointer const& state) override;
             virtual StateBehavior<ValueType, StateType> expand(StateToIdCallback const& stateToIdCallback) override;
             virtual bool satisfies(storm::expressions::Expression const& expression) const override;
 
@@ -28,7 +31,9 @@ namespace storm {
             // The program used for the generation of next states.
             storm::storage::DFT<ValueType> const& mDft;
             
-            CompressedState const* state;
+            storm::storage::DFTStateGenerationInfo const& mStateGenerationInfo;
+            
+            DFTStatePointer const state;
             
             // A comparator used to compare constants.
             storm::utility::ConstantsComparator<ValueType> comparator;
diff --git a/src/modelchecker/DFTAnalyser.h b/src/modelchecker/DFTAnalyser.h
index 24c1068ba..cc1e34696 100644
--- a/src/modelchecker/DFTAnalyser.h
+++ b/src/modelchecker/DFTAnalyser.h
@@ -1,12 +1,14 @@
 #pragma once
 
-#include "logic/Formula.h"
-#include "parser/DFTGalileoParser.h"
-#include "builder/ExplicitDFTModelBuilder.h"
-#include "modelchecker/results/CheckResult.h"
-#include "utility/storm.h"
-#include "storage/dft/DFTIsomorphism.h"
-#include "utility/bitoperations.h"
+#include "src/logic/Formula.h"
+#include "src/parser/DFTGalileoParser.h"
+#include "src/builder/ExplicitDFTModelBuilder.h"
+#include "src/builder/ExplicitDFTModelBuilderApprox.h"
+#include "src/modelchecker/results/CheckResult.h"
+#include "src/utility/storm.h"
+#include "src/storage/dft/DFTIsomorphism.h"
+#include "src/settings/modules/DFTSettings.h"
+#include "src/utility/bitoperations.h"
 
 
 #include <chrono>
@@ -149,9 +151,17 @@ private:
             
             // Building Markov Automaton
             STORM_LOG_INFO("Building Model...");
-            storm::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries, enableDC);
-            typename storm::builder::ExplicitDFTModelBuilder<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
-            std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.buildModel(labeloptions);
+            std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
+            // TODO Matthias: use only one builder if everything works again
+            if (storm::settings::getModule<storm::settings::modules::DFTSettings>().computeApproximation()) {
+                storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
+                typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
+                model = builder.buildModel(labeloptions);
+            } else {
+                storm::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries, enableDC);
+                typename storm::builder::ExplicitDFTModelBuilder<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
+                model = builder.buildModel(labeloptions);
+            }
             //model->printModelInformationToStream(std::cout);
             STORM_LOG_INFO("No. states (Explored): " << model->getNumberOfStates());
             STORM_LOG_INFO("No. transitions (Explored): " << model->getNumberOfTransitions());
diff --git a/src/storage/sparse/StateStorage.cpp b/src/storage/sparse/StateStorage.cpp
index 60af49179..15789c355 100644
--- a/src/storage/sparse/StateStorage.cpp
+++ b/src/storage/sparse/StateStorage.cpp
@@ -15,6 +15,7 @@ namespace storm {
             }
             
             template class StateStorage<uint32_t>;
+            template class StateStorage<uint_fast64_t>;
         }
     }
 }
\ No newline at end of file

From fba2071e9fba5b34232470e24c856e4700d466ff Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Tue, 13 Sep 2016 12:27:20 +0200
Subject: [PATCH 11/65] Dft exploration via NextStateGenerator

Former-commit-id: f81ac4e7fc283554cde7d4c70ab99b7b2f7b007f
---
 examples/dft/fdep4.dft                        |   7 +
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 736 +++++-------------
 src/builder/ExplicitDFTModelBuilderApprox.h   | 111 ++-
 src/generator/DftNextStateGenerator.cpp       | 266 ++++---
 src/generator/DftNextStateGenerator.h         |  43 +-
 src/generator/StateBehavior.cpp               |   3 +
 src/models/sparse/MarkovAutomaton.cpp         |   2 +-
 src/models/sparse/MarkovAutomaton.h           |   7 +-
 src/models/sparse/StateLabeling.cpp           |   2 +-
 src/models/sparse/StateLabeling.h             |   2 +-
 src/storage/dft/DFT.cpp                       |   5 +
 src/storage/dft/DFT.h                         |   2 +
 src/storage/dft/DFTState.cpp                  |   6 +-
 src/utility/vector.cpp                        |  32 +-
 src/utility/vector.h                          |   1 +
 15 files changed, 561 insertions(+), 664 deletions(-)
 create mode 100644 examples/dft/fdep4.dft

diff --git a/examples/dft/fdep4.dft b/examples/dft/fdep4.dft
new file mode 100644
index 000000000..7e3c5642a
--- /dev/null
+++ b/examples/dft/fdep4.dft
@@ -0,0 +1,7 @@
+toplevel "A";
+"A" or "F" "B";
+"F" fdep "E" "C" "D";
+"B" wsp "C" "D";
+"C" lambda=1 dorm=0;
+"D" lambda=1 dorm=0.5;
+"E" lambda=0.5 dorm=0;
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 285301807..9ff34b734 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -12,223 +12,167 @@
 namespace storm {
     namespace builder {
 
-        template <typename ValueType>
-        ExplicitDFTModelBuilderApprox<ValueType>::ModelComponents::ModelComponents() : transitionMatrix(), stateLabeling(), markovianStates(), exitRates(), choiceLabeling() {
+        template <typename ValueType, typename StateType>
+        ExplicitDFTModelBuilderApprox<ValueType, StateType>::ModelComponents::ModelComponents() : transitionMatrix(), stateLabeling(), markovianStates(), exitRates(), choiceLabeling() {
             // Intentionally left empty.
         }
-        
-        template <typename ValueType>
-        ExplicitDFTModelBuilderApprox<ValueType>::ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC) : mDft(dft), enableDC(enableDC), stateStorage(((mDft.stateVectorSize() / 64) + 1) * 64) {
+
+        template <typename ValueType, typename StateType>
+        ExplicitDFTModelBuilderApprox<ValueType, StateType>::ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC) : dft(dft), enableDC(enableDC), stateStorage(((dft.stateVectorSize() / 64) + 1) * 64) {
             // stateVectorSize is bound for size of bitvector
 
-            mStateGenerationInfo = std::make_shared<storm::storage::DFTStateGenerationInfo>(mDft.buildStateGenerationInfo(symmetries));
+            stateGenerationInfo = std::make_shared<storm::storage::DFTStateGenerationInfo>(dft.buildStateGenerationInfo(symmetries));
         }
 
+        template <typename ValueType, typename StateType>
+        std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilderApprox<ValueType, StateType>::buildModel(LabelOptions const& labelOpts) {
+            STORM_LOG_TRACE("Generating DFT state space");
 
-        template <typename ValueType>
-        std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilderApprox<ValueType>::buildModel(LabelOptions const& labelOpts) {
             // Initialize
-            bool deterministicModel = false;
-            size_t rowOffset = 0;
-            ModelComponents modelComponents;
-            std::vector<uint_fast64_t> tmpMarkovianStates;
-            storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !deterministicModel, 0);
+            StateType currentRowGroup = 0;
+            StateType currentRow = 0;
+            modelComponents.markovianStates = storm::storage::BitVector(INITIAL_BITVECTOR_SIZE);
+            // Create generator
+            storm::generator::DftNextStateGenerator<ValueType, StateType> generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates);
+            // Create sparse matrix builder
+            storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !generator.isDeterministicModel(), 0);
 
             if(mergeFailedStates) {
                 // Introduce explicit fail state
-                failedIndex = newIndex;
-                newIndex++;
-                transitionMatrixBuilder.newRowGroup(failedIndex);
-                transitionMatrixBuilder.addNextValue(failedIndex, failedIndex, storm::utility::one<ValueType>());
-                STORM_LOG_TRACE("Introduce fail state with id: " << failedIndex);
-                modelComponents.exitRates.push_back(storm::utility::one<ValueType>());
-                tmpMarkovianStates.push_back(failedIndex);        
-            }
-            
-            // Explore state space
-            DFTStatePointer state = std::make_shared<storm::storage::DFTState<ValueType>>(mDft, *mStateGenerationInfo, newIndex);
-            auto exploreResult = exploreStates(state, rowOffset, transitionMatrixBuilder, tmpMarkovianStates, modelComponents.exitRates);
-            initialStateIndex = exploreResult.first;
-            bool deterministic = exploreResult.second;
-        
-            // Before ending the exploration check for pseudo states which are not initialized yet
-            for (auto & pseudoStatePair : mPseudoStatesMapping) {
-                if (pseudoStatePair.first == 0) {
-                    // Create state from pseudo state and explore
-                    STORM_LOG_ASSERT(stateStorage.stateToId.contains(pseudoStatePair.second), "Pseudo state not contained.");
-                    STORM_LOG_ASSERT(stateStorage.stateToId.getValue(pseudoStatePair.second) >= OFFSET_PSEUDO_STATE, "State is no pseudo state.");
-                    STORM_LOG_TRACE("Create pseudo state from bit vector " << pseudoStatePair.second);
-                    DFTStatePointer pseudoState = std::make_shared<storm::storage::DFTState<ValueType>>(pseudoStatePair.second, mDft, *mStateGenerationInfo, newIndex);
-                    STORM_LOG_ASSERT(pseudoStatePair.second == pseudoState->status(), "Pseudo states do not coincide.");
-                    STORM_LOG_TRACE("Explore pseudo state " << mDft.getStateString(pseudoState) << " with id " << pseudoState->getId());
-                    auto exploreResult = exploreStates(pseudoState, rowOffset, transitionMatrixBuilder, tmpMarkovianStates, modelComponents.exitRates);
-                    deterministic &= exploreResult.second;
-                    STORM_LOG_ASSERT(pseudoStatePair.first == pseudoState->getId(), "Pseudo state ids do not coincide");
-                    STORM_LOG_ASSERT(pseudoState->getId() == exploreResult.first, "Pseudo state ids do not coincide.");
-                }
-            }
-            
-            // Replace pseudo states in matrix
-            std::vector<uint_fast64_t> pseudoStatesVector;
-            for (auto const& pseudoStatePair : mPseudoStatesMapping) {
-                pseudoStatesVector.push_back(pseudoStatePair.first);
-            }
-            STORM_LOG_ASSERT(std::find(pseudoStatesVector.begin(), pseudoStatesVector.end(), 0) == pseudoStatesVector.end(), "Unexplored pseudo state still contained.");
-            transitionMatrixBuilder.replaceColumns(pseudoStatesVector, OFFSET_PSEUDO_STATE);
-            
-            STORM_LOG_DEBUG("Generated " << stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0) << " states");
-            STORM_LOG_DEBUG("Model is " << (deterministic ? "deterministic" : "non-deterministic"));
+                storm::generator::StateBehavior<ValueType, StateType> behavior = generator.createMergeFailedState([this] (DFTStatePointer const& state) {
+                        this->failedStateId = newIndex++;
+                        stateRemapping.push_back(0);
+                        return this->failedStateId;
+                    } );
 
-            size_t stateSize = stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0);
-            // Build Markov Automaton
-            modelComponents.markovianStates = storm::storage::BitVector(stateSize, tmpMarkovianStates);
-            // Build transition matrix
-            modelComponents.transitionMatrix = transitionMatrixBuilder.build(stateSize, stateSize);
-            if (stateSize <= 15) {
-                STORM_LOG_TRACE("Transition matrix: " << std::endl << modelComponents.transitionMatrix);
-            } else {
-                STORM_LOG_TRACE("Transition matrix: too big to print");
-            }
-            STORM_LOG_TRACE("Exit rates: " << modelComponents.exitRates);
-            STORM_LOG_TRACE("Markovian states: " << modelComponents.markovianStates);
-            
-            // Build state labeling
-            modelComponents.stateLabeling = storm::models::sparse::StateLabeling(stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0));
-            // Initial state is always first state without any failure
-            modelComponents.stateLabeling.addLabel("init");
-            modelComponents.stateLabeling.addLabelToState("init", initialStateIndex);
-            // Label all states corresponding to their status (failed, failsafe, failed BE)
-            if(labelOpts.buildFailLabel) {
-                modelComponents.stateLabeling.addLabel("failed");
-            } 
-            if(labelOpts.buildFailSafeLabel) {
-                modelComponents.stateLabeling.addLabel("failsafe");
-            }
-            
-            // Collect labels for all BE
-            std::vector<std::shared_ptr<storage::DFTBE<ValueType>>> basicElements = mDft.getBasicElements();
-            for (std::shared_ptr<storage::DFTBE<ValueType>> elem : basicElements) {
-                if(labelOpts.beLabels.count(elem->name()) > 0) {
-                    modelComponents.stateLabeling.addLabel(elem->name() + "_fail");
+                setRemapping(failedStateId, currentRowGroup);
+
+                STORM_LOG_ASSERT(!behavior.empty(), "Behavior is empty.");
+                setMarkovian(currentRowGroup, behavior.begin()->isMarkovian());
+
+                // If the model is nondeterministic, we need to open a row group.
+                if (!generator.isDeterministicModel()) {
+                    transitionMatrixBuilder.newRowGroup(currentRow);
                 }
-            }
 
-            if(mergeFailedStates) {
-                modelComponents.stateLabeling.addLabelToState("failed", failedIndex);
+                // Now add self loop.
+                // TODO Matthias: maybe use general method.
+                STORM_LOG_ASSERT(behavior.getNumberOfChoices() == 1, "Wrong number of choices for failed state.");
+                STORM_LOG_ASSERT(behavior.begin()->size() == 1, "Wrong number of transitions for failed state.");
+                std::pair<StateType, ValueType> stateProbabilityPair = *(behavior.begin()->begin());
+                STORM_LOG_ASSERT(stateProbabilityPair.first == failedStateId, "No self loop for failed state.");
+                STORM_LOG_ASSERT(storm::utility::isOne<ValueType>(stateProbabilityPair.second), "Probability for failed state != 1.");
+                transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second);
+                ++currentRow;
+                ++currentRowGroup;
             }
-            for (auto const& stateIdPair : stateStorage.stateToId) {
-                storm::storage::BitVector state = stateIdPair.first;
-                size_t stateId = stateIdPair.second;
-                if (!mergeFailedStates && labelOpts.buildFailLabel && mDft.hasFailed(state, *mStateGenerationInfo)) {
-                    modelComponents.stateLabeling.addLabelToState("failed", stateId);
-                }
-                if (labelOpts.buildFailSafeLabel && mDft.isFailsafe(state, *mStateGenerationInfo)) {
-                    modelComponents.stateLabeling.addLabelToState("failsafe", stateId);
-                };
-                // Set fail status for each BE
-                for (std::shared_ptr<storage::DFTBE<ValueType>> elem : basicElements) {
-                    if (labelOpts.beLabels.count(elem->name()) > 0 && storm::storage::DFTState<ValueType>::hasFailed(state, mStateGenerationInfo->getStateIndex(elem->id())) ) {
-                        modelComponents.stateLabeling.addLabelToState(elem->name() + "_fail", stateId);
-                    }
+
+            // Create a callback for the next-state generator to enable it to add states
+            std::function<StateType (DFTStatePointer const&)> stateToIdCallback = std::bind(&ExplicitDFTModelBuilderApprox::getOrAddStateIndex, this, std::placeholders::_1);
+
+            // Build initial states
+            this->stateStorage.initialStateIndices = generator.getInitialStates(stateToIdCallback);
+            STORM_LOG_ASSERT(stateStorage.initialStateIndices.size() == 1, "Only one initial state assumed.");
+            StateType initialStateIndex = stateStorage.initialStateIndices[0];
+            STORM_LOG_TRACE("Initial state: " << initialStateIndex);
+
+            // Explore state space
+            bool explorationFinished = false;
+            while (!explorationFinished) {
+                // Get the first state in the queue
+                DFTStatePointer currentState = statesToExplore.front();
+                STORM_LOG_ASSERT(stateStorage.stateToId.getValue(currentState->status()) == currentState->getId(), "Ids of states do not coincide.");
+                statesToExplore.pop_front();
+
+                // Remember that this row group was actually filled with the transitions of a different state
+                setRemapping(currentState->getId(), currentRowGroup);
+
+                // Explore state
+                generator.load(currentState);
+                storm::generator::StateBehavior<ValueType, StateType> behavior = generator.expand(stateToIdCallback);
+
+                STORM_LOG_ASSERT(!behavior.empty(), "Behavior is empty.");
+                setMarkovian(currentRowGroup, behavior.begin()->isMarkovian());
+
+                // If the model is nondeterministic, we need to open a row group.
+                if (!generator.isDeterministicModel()) {
+                    transitionMatrixBuilder.newRowGroup(currentRow);
                 }
-            }
 
-            std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
-            
-            if (deterministic) {
-                // Turn the probabilities into rates by multiplying each row with the exit rate of the state.
-                // TODO Matthias: avoid transforming back and forth
-                storm::storage::SparseMatrix<ValueType> rateMatrix(modelComponents.transitionMatrix);
-                for (uint_fast64_t row = 0; row < rateMatrix.getRowCount(); ++row) {
-                    STORM_LOG_ASSERT(row < modelComponents.markovianStates.size(), "Row exceeds no. of markovian states.");
-                    if (modelComponents.markovianStates.get(row)) {
-                        for (auto& entry : rateMatrix.getRow(row)) {
-                            entry.setValue(entry.getValue() * modelComponents.exitRates[row]);
+                // Now add all choices.
+                for (auto const& choice : behavior) {
+                    // Add the probabilistic behavior to the matrix.
+                    for (auto const& stateProbabilityPair : choice) {
+
+                        // Check that pseudo state and its instantiation do not appear together
+                        // TODO Matthias: prove that this is not possible and remove
+                        if (stateProbabilityPair.first >= OFFSET_PSEUDO_STATE) {
+                            StateType newId = stateProbabilityPair.first - OFFSET_PSEUDO_STATE;
+                            STORM_LOG_ASSERT(newId < mPseudoStatesMapping.size(), "Id is not valid.");
+                            if (mPseudoStatesMapping[newId].first > 0) {
+                                // State exists already
+                                newId = mPseudoStatesMapping[newId].first;
+                                for (auto itFind = choice.begin(); itFind != choice.end(); ++itFind) {
+                                    STORM_LOG_ASSERT(itFind->first != newId, "Pseudo state and instantiation occur together in a distribution.");
+                                }
+                            }
                         }
+
+                        transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second);
                     }
+                    ++currentRow;
                 }
-                model = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(std::move(rateMatrix), std::move(modelComponents.exitRates), std::move(modelComponents.stateLabeling));
-            } else {
-                std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma = std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), std::move(modelComponents.markovianStates), std::move(modelComponents.exitRates), true);
-                if (ma->hasOnlyTrivialNondeterminism()) {
-                    // Markov automaton can be converted into CTMC
-                    model = ma->convertToCTMC();
-                } else {
-                    model = ma;
-                }
-            }
-            
-            return model;
-        }
-        
-        template <typename ValueType>
-        std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilderApprox<ValueType>::buildModelApprox(LabelOptions const& labelOpts) {
-            // Initialize
-            bool deterministicModel = false;
-            size_t rowOffset = 0;
-            ModelComponents modelComponents;
-            std::vector<uint_fast64_t> tmpMarkovianStates;
-            storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !deterministicModel, 0);
-            
-            if(mergeFailedStates) {
-                // Introduce explicit fail state
-                failedIndex = newIndex;
-                newIndex++;
-                transitionMatrixBuilder.newRowGroup(failedIndex);
-                transitionMatrixBuilder.addNextValue(failedIndex, failedIndex, storm::utility::one<ValueType>());
-                STORM_LOG_TRACE("Introduce fail state with id: " << failedIndex);
-                modelComponents.exitRates.push_back(storm::utility::one<ValueType>());
-                tmpMarkovianStates.push_back(failedIndex);
-            }
-            
-            // Initialize generator
-            storm::generator::DftNextStateGenerator<ValueType, uint_fast64_t> generator(mDft, *mStateGenerationInfo);
-            
-            // Explore state space
-            typename storm::generator::DftNextStateGenerator<ValueType, uint_fast64_t>::StateToIdCallback stateToIdCallback = [this] (DFTStatePointer const& state) -> uint_fast64_t {
-                uint_fast64_t id = newIndex++;
-                std::cout << "Added state " << id << std::endl;
-                return id;
-            };
-            
-            uint_fast64_t id = generator.getInitialStates(stateToIdCallback)[0];
-            std::cout << "Initial state " << id << std::endl;
-            DFTStatePointer state = std::make_shared<storm::storage::DFTState<ValueType>>(mDft, *mStateGenerationInfo, newIndex);
-            auto exploreResult = exploreStates(state, rowOffset, transitionMatrixBuilder, tmpMarkovianStates, modelComponents.exitRates);
-            initialStateIndex = exploreResult.first;
-            bool deterministic = exploreResult.second;
-            
-            // Before ending the exploration check for pseudo states which are not initialized yet
-            for (auto & pseudoStatePair : mPseudoStatesMapping) {
-                if (pseudoStatePair.first == 0) {
-                    // Create state from pseudo state and explore
-                    STORM_LOG_ASSERT(stateStorage.stateToId.contains(pseudoStatePair.second), "Pseudo state not contained.");
-                    STORM_LOG_ASSERT(stateStorage.stateToId.getValue(pseudoStatePair.second) >= OFFSET_PSEUDO_STATE, "State is no pseudo state.");
-                    STORM_LOG_TRACE("Create pseudo state from bit vector " << pseudoStatePair.second);
-                    DFTStatePointer pseudoState = std::make_shared<storm::storage::DFTState<ValueType>>(pseudoStatePair.second, mDft, *mStateGenerationInfo, newIndex);
-                    STORM_LOG_ASSERT(pseudoStatePair.second == pseudoState->status(), "Pseudo states do not coincide.");
-                    STORM_LOG_TRACE("Explore pseudo state " << mDft.getStateString(pseudoState) << " with id " << pseudoState->getId());
-                    auto exploreResult = exploreStates(pseudoState, rowOffset, transitionMatrixBuilder, tmpMarkovianStates, modelComponents.exitRates);
-                    deterministic &= exploreResult.second;
-                    STORM_LOG_ASSERT(pseudoStatePair.first == pseudoState->getId(), "Pseudo state ids do not coincide");
-                    STORM_LOG_ASSERT(pseudoState->getId() == exploreResult.first, "Pseudo state ids do not coincide.");
+                ++currentRowGroup;
+
+                if (statesToExplore.empty()) {
+                    explorationFinished = true;
+                    // Before ending the exploration check for pseudo states which are not initialized yet
+                    for ( ; pseudoStatesToCheck < mPseudoStatesMapping.size(); ++pseudoStatesToCheck) {
+                        std::pair<StateType, storm::storage::BitVector> pseudoStatePair = mPseudoStatesMapping[pseudoStatesToCheck];
+                        if (pseudoStatePair.first == 0) {
+                            // Create state from pseudo state and explore
+                            STORM_LOG_ASSERT(stateStorage.stateToId.contains(pseudoStatePair.second), "Pseudo state not contained.");
+                            STORM_LOG_ASSERT(stateStorage.stateToId.getValue(pseudoStatePair.second) >= OFFSET_PSEUDO_STATE, "State is no pseudo state.");
+                            STORM_LOG_TRACE("Create pseudo state from bit vector " << pseudoStatePair.second);
+                            DFTStatePointer pseudoState = std::make_shared<storm::storage::DFTState<ValueType>>(pseudoStatePair.second, dft, *stateGenerationInfo, newIndex);
+                            STORM_LOG_ASSERT(pseudoStatePair.second == pseudoState->status(), "Pseudo states do not coincide.");
+                            STORM_LOG_TRACE("Explore pseudo state " << dft.getStateString(pseudoState) << " with id " << pseudoState->getId());
+
+                            getOrAddStateIndex(pseudoState);
+                            explorationFinished = false;
+                            break;
+                        }
+                    }
                 }
-            }
-            
+
+            } // end exploration
+
+            size_t stateSize = stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0);
+            modelComponents.markovianStates.resize(stateSize);
+
             // Replace pseudo states in matrix
+            // TODO Matthias: avoid hack with fixed int type
             std::vector<uint_fast64_t> pseudoStatesVector;
             for (auto const& pseudoStatePair : mPseudoStatesMapping) {
                 pseudoStatesVector.push_back(pseudoStatePair.first);
             }
             STORM_LOG_ASSERT(std::find(pseudoStatesVector.begin(), pseudoStatesVector.end(), 0) == pseudoStatesVector.end(), "Unexplored pseudo state still contained.");
             transitionMatrixBuilder.replaceColumns(pseudoStatesVector, OFFSET_PSEUDO_STATE);
-            
-            STORM_LOG_DEBUG("Generated " << stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0) << " states");
-            STORM_LOG_DEBUG("Model is " << (deterministic ? "deterministic" : "non-deterministic"));
-            
-            size_t stateSize = stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0);
-            // Build Markov Automaton
-            modelComponents.markovianStates = storm::storage::BitVector(stateSize, tmpMarkovianStates);
+
+
+            // Fix the entries in the matrix according to the (reversed) mapping of row groups to indices
+            STORM_LOG_ASSERT(stateRemapping[initialStateIndex] == initialStateIndex, "Initial state should not be remapped.");
+            // Fix the transition matrix
+            transitionMatrixBuilder.replaceColumns(stateRemapping, 0);
+            // Fix the hash map storing the mapping states -> ids
+            this->stateStorage.stateToId.remap([this] (StateType const& state) { return this->stateRemapping[state]; } );
+
+            STORM_LOG_TRACE("State remapping: " << stateRemapping);
+            STORM_LOG_TRACE("Markovian states: " << modelComponents.markovianStates);
+
+            STORM_LOG_DEBUG("Generated " << stateSize << " states");
+            STORM_LOG_DEBUG("Model is " << (generator.isDeterministicModel() ? "deterministic" : "non-deterministic"));
+
             // Build transition matrix
             modelComponents.transitionMatrix = transitionMatrixBuilder.build(stateSize, stateSize);
             if (stateSize <= 15) {
@@ -236,11 +180,9 @@ namespace storm {
             } else {
                 STORM_LOG_TRACE("Transition matrix: too big to print");
             }
-            STORM_LOG_TRACE("Exit rates: " << modelComponents.exitRates);
-            STORM_LOG_TRACE("Markovian states: " << modelComponents.markovianStates);
-            
+
             // Build state labeling
-            modelComponents.stateLabeling = storm::models::sparse::StateLabeling(stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0));
+            modelComponents.stateLabeling = storm::models::sparse::StateLabeling(stateSize);
             // Initial state is always first state without any failure
             modelComponents.stateLabeling.addLabel("init");
             modelComponents.stateLabeling.addLabelToState("init", initialStateIndex);
@@ -251,52 +193,56 @@ namespace storm {
             if(labelOpts.buildFailSafeLabel) {
                 modelComponents.stateLabeling.addLabel("failsafe");
             }
-            
+
             // Collect labels for all BE
-            std::vector<std::shared_ptr<storage::DFTBE<ValueType>>> basicElements = mDft.getBasicElements();
+            std::vector<std::shared_ptr<storage::DFTBE<ValueType>>> basicElements = dft.getBasicElements();
             for (std::shared_ptr<storage::DFTBE<ValueType>> elem : basicElements) {
                 if(labelOpts.beLabels.count(elem->name()) > 0) {
                     modelComponents.stateLabeling.addLabel(elem->name() + "_fail");
                 }
             }
-            
+
+            // Set labels to states
             if(mergeFailedStates) {
-                modelComponents.stateLabeling.addLabelToState("failed", failedIndex);
+                modelComponents.stateLabeling.addLabelToState("failed", failedStateId);
             }
             for (auto const& stateIdPair : stateStorage.stateToId) {
                 storm::storage::BitVector state = stateIdPair.first;
                 size_t stateId = stateIdPair.second;
-                if (!mergeFailedStates && labelOpts.buildFailLabel && mDft.hasFailed(state, *mStateGenerationInfo)) {
+                if (!mergeFailedStates && labelOpts.buildFailLabel && dft.hasFailed(state, *stateGenerationInfo)) {
                     modelComponents.stateLabeling.addLabelToState("failed", stateId);
                 }
-                if (labelOpts.buildFailSafeLabel && mDft.isFailsafe(state, *mStateGenerationInfo)) {
+                if (labelOpts.buildFailSafeLabel && dft.isFailsafe(state, *stateGenerationInfo)) {
                     modelComponents.stateLabeling.addLabelToState("failsafe", stateId);
                 };
                 // Set fail status for each BE
                 for (std::shared_ptr<storage::DFTBE<ValueType>> elem : basicElements) {
-                    if (labelOpts.beLabels.count(elem->name()) > 0 && storm::storage::DFTState<ValueType>::hasFailed(state, mStateGenerationInfo->getStateIndex(elem->id())) ) {
+                    if (labelOpts.beLabels.count(elem->name()) > 0 && storm::storage::DFTState<ValueType>::hasFailed(state, stateGenerationInfo->getStateIndex(elem->id())) ) {
                         modelComponents.stateLabeling.addLabelToState(elem->name() + "_fail", stateId);
                     }
                 }
             }
-            
+
             std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
-            
-            if (deterministic) {
-                // Turn the probabilities into rates by multiplying each row with the exit rate of the state.
-                // TODO Matthias: avoid transforming back and forth
-                storm::storage::SparseMatrix<ValueType> rateMatrix(modelComponents.transitionMatrix);
-                for (uint_fast64_t row = 0; row < rateMatrix.getRowCount(); ++row) {
-                    STORM_LOG_ASSERT(row < modelComponents.markovianStates.size(), "Row exceeds no. of markovian states.");
-                    if (modelComponents.markovianStates.get(row)) {
-                        for (auto& entry : rateMatrix.getRow(row)) {
-                            entry.setValue(entry.getValue() * modelComponents.exitRates[row]);
-                        }
+
+            if (generator.isDeterministicModel()) {
+                // Build CTMC
+                model = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling));
+            } else {
+                // Build MA
+                // Compute exit rates
+                modelComponents.exitRates = std::vector<ValueType>(stateSize);
+                std::vector<typename storm::storage::SparseMatrix<ValueType>::index_type> indices = modelComponents.transitionMatrix.getRowGroupIndices();
+                for (StateType stateIndex = 0; stateIndex < stateSize; ++stateIndex) {
+                    if (modelComponents.markovianStates[stateIndex]) {
+                        modelComponents.exitRates[stateIndex] = modelComponents.transitionMatrix.getRowSum(indices[stateIndex]);
+                    } else {
+                        modelComponents.exitRates[stateIndex] = storm::utility::zero<ValueType>();
                     }
                 }
-                model = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(std::move(rateMatrix), std::move(modelComponents.exitRates), std::move(modelComponents.stateLabeling));
-            } else {
-                std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma = std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), std::move(modelComponents.markovianStates), std::move(modelComponents.exitRates), true);
+                STORM_LOG_TRACE("Exit rates: " << modelComponents.exitRates);
+
+                std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma = std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), std::move(modelComponents.markovianStates), std::move(modelComponents.exitRates));
                 if (ma->hasOnlyTrivialNondeterminism()) {
                     // Markov automaton can be converted into CTMC
                     model = ma->convertToCTMC();
@@ -325,331 +271,77 @@ namespace storm {
             return eval < threshold;
         }
 
-        
-        template <typename ValueType>
-        std::pair<uint_fast64_t, bool> ExplicitDFTModelBuilderApprox<ValueType>::exploreStates(DFTStatePointer const& state, size_t& rowOffset, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<uint_fast64_t>& markovianStates, std::vector<ValueType>& exitRates) {
-            STORM_LOG_TRACE("Explore state: " << mDft.getStateString(state));
-
-            auto explorePair = checkForExploration(state);
-            if (!explorePair.first) {
-                // State does not need any exploration
-                return std::make_pair(explorePair.second, true);
-            }
-
-            
-            // Initialization
-            // TODO Matthias: set Markovian states directly as bitvector?
-            std::map<uint_fast64_t, ValueType> outgoingRates;
-            std::vector<std::map<uint_fast64_t, ValueType>> outgoingProbabilities;
-            bool hasDependencies = state->nrFailableDependencies() > 0;
-            size_t failableCount = hasDependencies ? state->nrFailableDependencies() : state->nrFailableBEs();
-            size_t smallest = 0;
-            ValueType exitRate = storm::utility::zero<ValueType>();
-            bool deterministic = !hasDependencies;
-
-            // Absorbing state
-            if (mDft.hasFailed(state) || mDft.isFailsafe(state) || state->nrFailableBEs() == 0) {
-                uint_fast64_t stateId = addState(state);
-                STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not coincide.");
-
-                // Add self loop
-                transitionMatrixBuilder.newRowGroup(stateId + rowOffset);
-                transitionMatrixBuilder.addNextValue(stateId + rowOffset, stateId, storm::utility::one<ValueType>());
-                STORM_LOG_TRACE("Added self loop for " << stateId);
-                exitRates.push_back(storm::utility::one<ValueType>());
-                STORM_LOG_ASSERT(exitRates.size()-1 == stateId, "No. of considered states does not match state id.");
-                markovianStates.push_back(stateId);
-                // No further exploration required
-                return std::make_pair(stateId, true);
-            }
-
-            // Let BE fail
-            while (smallest < failableCount) {
-                STORM_LOG_ASSERT(!mDft.hasFailed(state), "Dft has failed.");
-
-                // Construct new state as copy from original one
-                DFTStatePointer newState = std::make_shared<storm::storage::DFTState<ValueType>>(*state);
-                std::pair<std::shared_ptr<storm::storage::DFTBE<ValueType> const>, bool> nextBEPair = newState->letNextBEFail(smallest++);
-                std::shared_ptr<storm::storage::DFTBE<ValueType> const>& nextBE = nextBEPair.first;
-                STORM_LOG_ASSERT(nextBE, "NextBE is null.");
-                STORM_LOG_ASSERT(nextBEPair.second == hasDependencies, "Failure due to dependencies does not match.");
-                STORM_LOG_TRACE("With the failure of: " << nextBE->name() << " [" << nextBE->id() << "] in " << mDft.getStateString(state));
-                
-                if (storm::settings::getModule<storm::settings::modules::DFTSettings>().computeApproximation()) {
-                    if (!storm::utility::isZero(exitRate)) {
-                        ValueType rate = nextBE->activeFailureRate();
-                        ValueType div = rate / exitRate;
-                        if (!storm::utility::isZero(exitRate) && belowThreshold(div)) {
-                            // Set transition directly to failed state
-                            auto resultFind = outgoingRates.find(failedIndex);
-                            if (resultFind != outgoingRates.end()) {
-                                // Add to existing transition
-                                resultFind->second += rate;
-                                STORM_LOG_TRACE("Updated transition to " << resultFind->first << " with rate " << rate << " to new rate " << resultFind->second);
-                            } else {
-                                // Insert new transition
-                                outgoingRates.insert(std::make_pair(failedIndex, rate));
-                                STORM_LOG_TRACE("Added transition to " << failedIndex << " with rate " << rate);
-                            }
-                            exitRate += rate;
-                            std::cout << "IGNORE: " << nextBE->name() << " [" << nextBE->id() << "] with rate " << rate << std::endl;
-                            //STORM_LOG_TRACE("Ignore: " << nextBE->name() << " [" << nextBE->id() << "] with rate " << rate);
-                            continue;
-                        }
-                    }
-                }
-
-                // Propagate failures
-                storm::storage::DFTStateSpaceGenerationQueues<ValueType> queues;
-
-                for (DFTGatePointer parent : nextBE->parents()) {
-                    if (newState->isOperational(parent->id())) {
-                        queues.propagateFailure(parent);
-                    }
-                }
-                for (DFTRestrictionPointer restr : nextBE->restrictions()) {
-                    queues.checkRestrictionLater(restr);
-                }
-
-                while (!queues.failurePropagationDone()) {
-                    DFTGatePointer next = queues.nextFailurePropagation();
-                    next->checkFails(*newState, queues);
-                    newState->updateFailableDependencies(next->id());
-                }
-                
-                while(!queues.restrictionChecksDone()) {
-                    DFTRestrictionPointer next = queues.nextRestrictionCheck();
-                    next->checkFails(*newState, queues);
-                    newState->updateFailableDependencies(next->id());
-                }
-                
-                if(newState->isInvalid()) {
-                    continue;
-                }
-                bool dftFailed = newState->hasFailed(mDft.getTopLevelIndex());
-                
-                while (!dftFailed && !queues.failsafePropagationDone()) {
-                    DFTGatePointer next = queues.nextFailsafePropagation();
-                    next->checkFailsafe(*newState, queues);
-                }
-
-                while (!dftFailed && enableDC && !queues.dontCarePropagationDone()) {
-                    DFTElementPointer next = queues.nextDontCarePropagation();
-                    next->checkDontCareAnymore(*newState, queues);
-                }
-                
-                // Update failable dependencies
-                if (!dftFailed) {
-                    newState->updateFailableDependencies(nextBE->id());
-                    newState->updateDontCareDependencies(nextBE->id());
-                }
-                
-                uint_fast64_t newStateId;
-                if(dftFailed && mergeFailedStates) {
-                    newStateId = failedIndex;
-                } else {
-                    // Explore new state recursively
-                    auto explorePair = exploreStates(newState, rowOffset, transitionMatrixBuilder, markovianStates, exitRates);
-                    newStateId = explorePair.first;
-                    deterministic &= explorePair.second;
-                }
-
-                // Set transitions
-                if (hasDependencies) {
-                    // Failure is due to dependency -> add non-deterministic choice
-                    std::map<uint_fast64_t, ValueType> choiceProbabilities;
-                    std::shared_ptr<storm::storage::DFTDependency<ValueType> const> dependency = mDft.getDependency(state->getDependencyId(smallest-1));
-                    choiceProbabilities.insert(std::make_pair(newStateId, dependency->probability()));
-                    STORM_LOG_TRACE("Added transition to " << newStateId << " with probability " << dependency->probability());
-
-                    if (!storm::utility::isOne(dependency->probability())) {
-                        // Add transition to state where dependency was unsuccessful
-                        DFTStatePointer unsuccessfulState = std::make_shared<storm::storage::DFTState<ValueType>>(*state);
-                        unsuccessfulState->letDependencyBeUnsuccessful(smallest-1);
-                        auto explorePair = exploreStates(unsuccessfulState, rowOffset, transitionMatrixBuilder, markovianStates, exitRates);
-                        uint_fast64_t unsuccessfulStateId = explorePair.first;
-                        deterministic &= explorePair.second;
-                        ValueType remainingProbability = storm::utility::one<ValueType>() - dependency->probability();
-                        choiceProbabilities.insert(std::make_pair(unsuccessfulStateId, remainingProbability));
-                        STORM_LOG_TRACE("Added transition to " << unsuccessfulStateId << " with remaining probability " << remainingProbability);
-                    }
-                    outgoingProbabilities.push_back(choiceProbabilities);
-                } else {
-                    // Set failure rate according to activation
-                    bool isActive = true;
-                    if (mDft.hasRepresentant(nextBE->id())) {
-                        // Active must be checked for the state we are coming from as this state is responsible for the
-                        // rate and not the new state we are going to
-                        isActive = state->isActive(mDft.getRepresentant(nextBE->id())->id());
-                    }
-                    ValueType rate = isActive ? nextBE->activeFailureRate() : nextBE->passiveFailureRate();
-                    STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Rate is 0.");
-                    auto resultFind = outgoingRates.find(newStateId);
-                    if (resultFind != outgoingRates.end()) {
-                        // Add to existing transition
-                        resultFind->second += rate;
-                        STORM_LOG_TRACE("Updated transition to " << resultFind->first << " with " << (isActive ? "active" : "passive") << " rate " << rate << " to new rate " << resultFind->second);
-                    } else {
-                        // Insert new transition
-                        outgoingRates.insert(std::make_pair(newStateId, rate));
-                        STORM_LOG_TRACE("Added transition to " << newStateId << " with " << (isActive ? "active" : "passive") << " rate " << rate);
-                    }
-                    exitRate += rate;
-                }
-
-            } // end while failing BE
-            
-            // Add state
-            uint_fast64_t stateId = addState(state);
-            STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not match.");
-            STORM_LOG_ASSERT(stateId == newIndex-1, "Id does not match no. of states.");
-            
-            if (hasDependencies) {
-                // Add all probability transitions
-                STORM_LOG_ASSERT(outgoingRates.empty(), "Outgoing transitions not empty.");
-                transitionMatrixBuilder.newRowGroup(stateId + rowOffset);
-                for (size_t i = 0; i < outgoingProbabilities.size(); ++i, ++rowOffset) {
-                    STORM_LOG_ASSERT(outgoingProbabilities[i].size() == 1 || outgoingProbabilities[i].size() == 2, "No. of outgoing transitions is not valid.");
-                    for (auto it = outgoingProbabilities[i].begin(); it != outgoingProbabilities[i].end(); ++it)
-                    {
-                        STORM_LOG_TRACE("Set transition from " << stateId << " to " << it->first << " with probability " << it->second);
-                        transitionMatrixBuilder.addNextValue(stateId + rowOffset, it->first, it->second);
-                    }
-                }
-                rowOffset--; // One increment too many
-            } else {
-                // Try to merge pseudo states with their instantiation
-                // TODO Matthias: improve?
-                for (auto it = outgoingRates.begin(); it != outgoingRates.end(); ) {
-                    if (it->first >= OFFSET_PSEUDO_STATE) {
-                        uint_fast64_t newId = it->first - OFFSET_PSEUDO_STATE;
-                        STORM_LOG_ASSERT(newId < mPseudoStatesMapping.size(), "Id is not valid.");
-                        if (mPseudoStatesMapping[newId].first > 0) {
-                            // State exists already
-                            newId = mPseudoStatesMapping[newId].first;
-                            auto itFind = outgoingRates.find(newId);
-                            if (itFind != outgoingRates.end()) {
-                                // Add probability from pseudo state to instantiation
-                                itFind->second += it->second;
-                                STORM_LOG_TRACE("Merged pseudo state " << newId << " adding rate " << it->second << " to total rate of " << itFind->second);
-                            } else {
-                                // Only change id
-                                outgoingRates.emplace(newId, it->second);
-                                STORM_LOG_TRACE("Instantiated pseudo state " << newId << " with rate " << it->second);
-                            }
-                            // Remove pseudo state
-                            it = outgoingRates.erase(it);
-                        } else {
-                            ++it;
-                        }
-                    } else {
-                        ++it;
-                    }
-                }
-                
-                // Add all rate transitions
-                STORM_LOG_ASSERT(outgoingProbabilities.empty(), "Outgoing probabilities not empty.");
-                transitionMatrixBuilder.newRowGroup(state->getId() + rowOffset);
-                STORM_LOG_TRACE("Exit rate for " << state->getId() << ": " << exitRate);
-                for (auto it = outgoingRates.begin(); it != outgoingRates.end(); ++it)
-                {
-                    ValueType probability = it->second / exitRate; // Transform rate to probability
-                    STORM_LOG_TRACE("Set transition from " << state->getId() << " to " << it->first << " with rate " << it->second);
-                    transitionMatrixBuilder.addNextValue(state->getId() + rowOffset, it->first, probability);
-                }
-
-                markovianStates.push_back(state->getId());
-            }
-            
-            STORM_LOG_TRACE("Finished exploring state: " << mDft.getStateString(state));
-            exitRates.push_back(exitRate);
-            STORM_LOG_ASSERT(exitRates.size()-1 == state->getId(), "Id does not match no. of states.");
-            return std::make_pair(state->getId(), deterministic);
-        }
-        
-        template <typename ValueType>
-        std::pair<bool, uint_fast64_t> ExplicitDFTModelBuilderApprox<ValueType>::checkForExploration(DFTStatePointer const& state) {
+        template <typename ValueType, typename StateType>
+        StateType ExplicitDFTModelBuilderApprox<ValueType, StateType>::getOrAddStateIndex(DFTStatePointer const& state) {
+            StateType stateId;
             bool changed = false;
-            if (mStateGenerationInfo->hasSymmetries()) {
+
+            if (stateGenerationInfo->hasSymmetries()) {
                 // Order state by symmetry
-                STORM_LOG_TRACE("Check for symmetry: " << mDft.getStateString(state));
+                STORM_LOG_TRACE("Check for symmetry: " << dft.getStateString(state));
                 changed = state->orderBySymmetry();
-                STORM_LOG_TRACE("State " << (changed ? "changed to " : "did not change") << (changed ? mDft.getStateString(state) : ""));
+                STORM_LOG_TRACE("State " << (changed ? "changed to " : "did not change") << (changed ? dft.getStateString(state) : ""));
             }
-            
+
             if (stateStorage.stateToId.contains(state->status())) {
                 // State already exists
-                uint_fast64_t stateId = stateStorage.stateToId.getValue(state->status());
-                STORM_LOG_TRACE("State " << mDft.getStateString(state) << " with id " << stateId << " already exists");
-                
-                if (changed || stateId < OFFSET_PSEUDO_STATE) {
-                    // State is changed or an explored "normal" state
-                    return std::make_pair(false, stateId);
-                }
-                
-                stateId -= OFFSET_PSEUDO_STATE;
-                STORM_LOG_ASSERT(stateId < mPseudoStatesMapping.size(), "Id not valid.");
-                if (mPseudoStatesMapping[stateId].first > 0) {
-                    // Pseudo state already explored
-                    return std::make_pair(false, mPseudoStatesMapping[stateId].first);
+                stateId = stateStorage.stateToId.getValue(state->status());
+                STORM_LOG_TRACE("State " << dft.getStateString(state) << " with id " << stateId << " already exists");
+
+                if (!changed && stateId >= OFFSET_PSEUDO_STATE) {
+                    // Pseudo state can be created now
+                    STORM_LOG_ASSERT(stateId >= OFFSET_PSEUDO_STATE, "State is no pseudo state.");
+                    stateId -= OFFSET_PSEUDO_STATE;
+                    STORM_LOG_ASSERT(stateId < mPseudoStatesMapping.size(), "Pseudo state not known.");
+                    STORM_LOG_ASSERT(mPseudoStatesMapping[stateId].first == 0, "Pseudo state already created.");
+                    // Create pseudo state now
+                    STORM_LOG_ASSERT(mPseudoStatesMapping[stateId].second == state->status(), "Pseudo states do not coincide.");
+                    state->setId(newIndex++);
+                    mPseudoStatesMapping[stateId].first = state->getId();
+                    stateId = state->getId();
+                    stateStorage.stateToId.setOrAdd(state->status(), stateId);
+                    STORM_LOG_TRACE("Now create state " << dft.getStateString(state) << " with id " << stateId);
+                    statesToExplore.push_front(state);
                 }
-                
-                STORM_LOG_ASSERT(mPseudoStatesMapping[stateId].second == state->status(), "States do not coincide.");
-                STORM_LOG_TRACE("Pseudo state " << mDft.getStateString(state) << " can be explored now");
-                return std::make_pair(true, stateId);
             } else {
-                // State does not exists
+                // State does not exist yet
                 if (changed) {
                     // Remember state for later creation
                     state->setId(mPseudoStatesMapping.size() + OFFSET_PSEUDO_STATE);
                     mPseudoStatesMapping.push_back(std::make_pair(0, state->status()));
-                    stateStorage.stateToId.findOrAdd(state->status(), state->getId());
-                    STORM_LOG_TRACE("Remember state for later creation: " << mDft.getStateString(state));
-                    return std::make_pair(false, state->getId());
+                    stateId = stateStorage.stateToId.findOrAdd(state->status(), state->getId());
+                    STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not match.");
+                    STORM_LOG_TRACE("Remember state for later creation: " << dft.getStateString(state));
+                    // Reserve one slot for the coming state in the remapping
+                    stateRemapping.push_back(0);
                 } else {
-                    // State needs exploration
-                    return std::make_pair(true, 0);
+                    // Create new state
+                    state->setId(newIndex++);
+                    stateId = stateStorage.stateToId.findOrAdd(state->status(), state->getId());
+                    STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not match.");
+                    STORM_LOG_TRACE("New state: " << dft.getStateString(state));
+                    statesToExplore.push_front(state);
+
+                    // Reserve one slot for the new state in the remapping
+                    stateRemapping.push_back(0);
                 }
             }
+            return stateId;
         }
 
-        template <typename ValueType>
-        uint_fast64_t ExplicitDFTModelBuilderApprox<ValueType>::addState(DFTStatePointer const& state) {
-            uint_fast64_t stateId;
-            // TODO remove
-            bool changed = state->orderBySymmetry();
-            STORM_LOG_ASSERT(!changed, "State to add has changed by applying symmetry.");
-            
-            // Check if state already exists
-            if (stateStorage.stateToId.contains(state->status())) {
-                // State already exists
-                stateId = stateStorage.stateToId.getValue(state->status());
-                STORM_LOG_TRACE("State " << mDft.getStateString(state) << " with id " << stateId << " already exists");
-                
-                // Check if possible pseudo state can be created now
-                STORM_LOG_ASSERT(stateId >= OFFSET_PSEUDO_STATE, "State is no pseudo state.");
-                stateId -= OFFSET_PSEUDO_STATE;
-                STORM_LOG_ASSERT(stateId < mPseudoStatesMapping.size(), "Pseudo state not known.");
-                if (mPseudoStatesMapping[stateId].first == 0) {
-                    // Create pseudo state now
-                    STORM_LOG_ASSERT(mPseudoStatesMapping[stateId].second == state->status(), "Pseudo states do not coincide.");
-                    state->setId(newIndex++);
-                    mPseudoStatesMapping[stateId].first = state->getId();
-                    stateId = state->getId();
-                    stateStorage.stateToId.setOrAdd(state->status(), stateId);
-                    STORM_LOG_TRACE("Now create state " << mDft.getStateString(state) << " with id " << stateId);
-                    return stateId;
-                } else {
-                    STORM_LOG_ASSERT(false, "Pseudo state already created.");
-                    return 0;
-                }
-            } else {
-                // Create new state
-                state->setId(newIndex++);
-                stateId = stateStorage.stateToId.findOrAdd(state->status(), state->getId());
-                STORM_LOG_TRACE("New state: " << mDft.getStateString(state));
-                return stateId;
+        template <typename ValueType, typename StateType>
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::setMarkovian(StateType id, bool markovian) {
+            if (id >= modelComponents.markovianStates.size()) {
+                // Resize BitVector
+                modelComponents.markovianStates.resize(modelComponents.markovianStates.size() + INITIAL_BITVECTOR_SIZE);
             }
+            modelComponents.markovianStates.set(id, markovian);
+        }
+
+        template <typename ValueType, typename StateType>
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::setRemapping(StateType id, StateType mappedId) {
+            STORM_LOG_ASSERT(id < stateRemapping.size(), "Invalid index for remapping.");
+            stateRemapping[id] = mappedId;
         }
 
 
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index d03681cbe..247b66ca1 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -12,11 +12,15 @@
 #include <boost/optional/optional.hpp>
 #include <stack>
 #include <unordered_set>
+#include <limits>
 
 namespace storm {
     namespace builder {
 
-        template<typename ValueType>
+        /*!
+         * Build a Markov chain from DFT.
+         */
+        template<typename ValueType, typename StateType = uint32_t>
         class ExplicitDFTModelBuilderApprox {
 
             using DFTElementPointer = std::shared_ptr<storm::storage::DFTElement<ValueType>>;
@@ -43,57 +47,100 @@ namespace storm {
                 std::vector<ValueType> exitRates;
 
                 // A vector that stores a labeling for each choice.
-                boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> choiceLabeling;
+                boost::optional<std::vector<boost::container::flat_set<StateType>>> choiceLabeling;
             };
-            
-            const uint_fast64_t OFFSET_PSEUDO_STATE = UINT_FAST64_MAX / 2;
-            
-            storm::storage::DFT<ValueType> const& mDft;
-            std::shared_ptr<storm::storage::DFTStateGenerationInfo> mStateGenerationInfo;
-            //TODO Matthias: remove when everything works
-            std::vector<std::pair<uint_fast64_t, storm::storage::BitVector>> mPseudoStatesMapping; // vector of (id to concrete state, bitvector)
-            size_t newIndex = 0;
-            bool mergeFailedStates = true;
-            bool enableDC = true;
-            size_t failedIndex = 0;
-            size_t initialStateIndex = 0;
-            
-            // Internal information about the states that were explored.
-            storm::storage::sparse::StateStorage<uint_fast64_t> stateStorage;
 
         public:
+            // A structure holding the labeling options.
             struct LabelOptions {
                 bool buildFailLabel = true;
                 bool buildFailSafeLabel = false;
                 std::set<std::string> beLabels = {};
             };
-            
+
+            /*!
+             * Constructor.
+             *
+             * @param dft DFT.
+             * @param symmetries Symmetries in the dft.
+             * @param enableDC Flag indicating if dont care propagation should be used.
+             */
             ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC);
 
+            /*!
+             * Build model from Dft.
+             *
+             * @param labelOpts Options for labeling.
+             *
+             * @return Built model (either MA or CTMC).
+             */
             std::shared_ptr<storm::models::sparse::Model<ValueType>> buildModel(LabelOptions const& labelOpts);
 
-            // TODO Matthias: only temporary used for avoiding crashing everything
-            std::shared_ptr<storm::models::sparse::Model<ValueType>> buildModelApprox(LabelOptions const& labelOpts);
-            
         private:
-            std::pair<uint_fast64_t, bool> exploreStates(DFTStatePointer const& state, size_t& rowOffset, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<uint_fast64_t>& markovianStates, std::vector<ValueType>& exitRates);
-            
+
             /*!
-             * Adds a state to the explored states and handles pseudo states.
+             * Add a state to the explored states (if not already there). It also handles pseudo states.
              *
              * @param state The state to add.
-             * @return Id of added state.
+             *
+             * @return Id of state.
+             */
+            StateType getOrAddStateIndex(DFTStatePointer const& state);
+
+            /*!
+             * Set if the given state is markovian.
+             *
+             * @param id Id of the state.
+             * @param markovian Flag indicating if the state is markovian.
              */
-            uint_fast64_t addState(DFTStatePointer const& state);
-            
+            void setMarkovian(StateType id, bool markovian);
+
             /*!
-             * Check if state needs an exploration and remember pseudo states for later creation.
+             * Set a mapping from a state id to its new id.
              *
-             * @param state State which might need exploration.
-             * @return Pair of flag indicating whether the state needs exploration now and the state id if the state already
-             * exists.
+             * @param id Id of the state.
+             * @param mappedId New id to use.
              */
-            std::pair<bool, uint_fast64_t> checkForExploration(DFTStatePointer const& state);
+            void setRemapping(StateType id, StateType mappedId);
+
+            // Initial size of the bitvector.
+            const size_t INITIAL_BITVECTOR_SIZE = 20000;
+            // Offset used for pseudo states.
+            const StateType OFFSET_PSEUDO_STATE = std::numeric_limits<StateType>::max() / 2;
+
+            // Dft
+            storm::storage::DFT<ValueType> const& dft;
+
+            // General information for state generation
+            // TODO Matthias: use const reference
+            std::shared_ptr<storm::storage::DFTStateGenerationInfo> stateGenerationInfo;
+
+            // Current id for new state
+            size_t newIndex = 0;
+
+            //TODO Matthias: remove when everything works
+            std::vector<std::pair<StateType, storm::storage::BitVector>> mPseudoStatesMapping; // vector of (id to concrete state, bitvector)
+            //TODO Matthias: make changeable
+            const bool mergeFailedStates = true;
+            size_t failedStateId = 0;
+            size_t initialStateIndex = 0;
+            size_t pseudoStatesToCheck = 0;
+
+            // Flag indication if dont care propagation should be used.
+            bool enableDC = true;
+
+            // Structure for the components of the model.
+            ModelComponents modelComponents;
+
+            // Internal information about the states that were explored.
+            storm::storage::sparse::StateStorage<StateType> stateStorage;
+
+            // A set of states that still need to be explored.
+            std::deque<DFTStatePointer> statesToExplore;
+
+            // A mapping from state indices to the row groups in which they actually reside
+            // TODO Matthias: avoid hack with fixed int type
+            std::vector<uint_fast64_t> stateRemapping;
 
         };
         
diff --git a/src/generator/DftNextStateGenerator.cpp b/src/generator/DftNextStateGenerator.cpp
index 3138fef6a..953a36db4 100644
--- a/src/generator/DftNextStateGenerator.cpp
+++ b/src/generator/DftNextStateGenerator.cpp
@@ -8,13 +8,13 @@ namespace storm {
     namespace generator {
         
         template<typename ValueType, typename StateType>
-        DftNextStateGenerator<ValueType, StateType>::DftNextStateGenerator(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo) : mDft(dft), mStateGenerationInfo(stateGenerationInfo), state(nullptr), comparator() {
-            // Intentionally left empty.
+        DftNextStateGenerator<ValueType, StateType>::DftNextStateGenerator(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, bool enableDC, bool mergeFailedStates) : mDft(dft), mStateGenerationInfo(stateGenerationInfo), state(nullptr), enableDC(enableDC), mergeFailedStates(mergeFailedStates), comparator() {
+            deterministicModel = !mDft.canHaveNondeterminism();
         }
         
         template<typename ValueType, typename StateType>
         bool DftNextStateGenerator<ValueType, StateType>::isDeterministicModel() const {
-            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This functionality is not yet implemented.");
+            return deterministicModel;
         }
         
         template<typename ValueType, typename StateType>
@@ -29,117 +29,201 @@ namespace storm {
         }
         
         template<typename ValueType, typename StateType>
-        void DftNextStateGenerator<ValueType, StateType>::load(std::shared_ptr<storm::storage::DFTState<ValueType>> const& state) {
-            /*// Since almost all subsequent operations are based on the evaluator, we load the state into it now.
-            unpackStateIntoEvaluator(state, variableInformation, evaluator);
-            
-            // Also, we need to store a pointer to the state itself, because we need to be able to access it when expanding it.
-            this->state = &state;*/
-            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This functionality is not yet implemented.");
+        void DftNextStateGenerator<ValueType, StateType>::load(DFTStatePointer const& state) {
+            // TODO Matthias load state from bitvector
+            // Store a pointer to the state itself, because we need to be able to access it when expanding it.
+            this->state = &state;
         }
         
         template<typename ValueType, typename StateType>
         bool DftNextStateGenerator<ValueType, StateType>::satisfies(storm::expressions::Expression const& expression) const {
-            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This functionality is not yet implemented.");
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "The method 'satisfies' is not yet implemented.");
         }
         
         template<typename ValueType, typename StateType>
         StateBehavior<ValueType, StateType> DftNextStateGenerator<ValueType, StateType>::expand(StateToIdCallback const& stateToIdCallback) {
-            /*// Prepare the result, in case we return early.
+            DFTStatePointer currentState = *state;
+            STORM_LOG_TRACE("Explore state: " << mDft.getStateString(currentState));
+
+            // Prepare the result, in case we return early.
             StateBehavior<ValueType, StateType> result;
-            
-            // First, construct the state rewards, as we may return early if there are no choices later and we already
-            // need the state rewards then.
-            for (auto const& rewardModel : selectedRewardModels) {
-                ValueType stateRewardValue = storm::utility::zero<ValueType>();
-                if (rewardModel.get().hasStateRewards()) {
-                    for (auto const& stateReward : rewardModel.get().getStateRewards()) {
-                        if (evaluator.asBool(stateReward.getStatePredicateExpression())) {
-                            stateRewardValue += ValueType(evaluator.asRational(stateReward.getRewardValueExpression()));
-                        }
-                    }
-                }
-                result.addStateReward(stateRewardValue);
-            }
-            
-            // If a terminal expression was set and we must not expand this state, return now.
-            if (terminalExpression && evaluator.asBool(terminalExpression.get())) {
-                return result;
-            }
-            
-            // Get all choices for the state.
-            std::vector<Choice<ValueType>> allChoices = getUnlabeledChoices(*this->state, stateToIdCallback);
-            std::vector<Choice<ValueType>> allLabeledChoices = getLabeledChoices(*this->state, stateToIdCallback);
-            for (auto& choice : allLabeledChoices) {
-                allChoices.push_back(std::move(choice));
-            }
-            
-            std::size_t totalNumberOfChoices = allChoices.size();
-            
-            // If there is not a single choice, we return immediately, because the state has no behavior (other than
-            // the state reward).
-            if (totalNumberOfChoices == 0) {
+
+            // Initialization
+            bool hasDependencies = currentState->nrFailableDependencies() > 0;
+            size_t failableCount = hasDependencies ? currentState->nrFailableDependencies() : currentState->nrFailableBEs();
+            size_t currentFailable = 0;
+            Choice<ValueType, StateType> choice(0, !hasDependencies);
+
+            // Check for absorbing state
+            if (mDft.hasFailed(currentState) || mDft.isFailsafe(currentState) || currentState->nrFailableBEs() == 0) {
+                // Add self loop
+                choice.addProbability(currentState->getId(), storm::utility::one<ValueType>());
+                STORM_LOG_TRACE("Added self loop for " << currentState->getId());
+                // No further exploration required
+                result.addChoice(std::move(choice));
+                result.setExpanded();
                 return result;
             }
-            
-            // If the model is a deterministic model, we need to fuse the choices into one.
-            if (program.isDeterministicModel() && totalNumberOfChoices > 1) {
-                Choice<ValueType> globalChoice;
-                
-                // For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs
-                // this is equal to the number of choices, which is why we initialize it like this here.
-                ValueType totalExitRate = program.isDiscreteTimeModel() ? static_cast<ValueType>(totalNumberOfChoices) : storm::utility::zero<ValueType>();
-                
-                // Iterate over all choices and combine the probabilities/rates into one choice.
-                for (auto const& choice : allChoices) {
-                    for (auto const& stateProbabilityPair : choice) {
-                        if (program.isDiscreteTimeModel()) {
-                            globalChoice.addProbability(stateProbabilityPair.first, stateProbabilityPair.second / totalNumberOfChoices);
-                        } else {
-                            globalChoice.addProbability(stateProbabilityPair.first, stateProbabilityPair.second);
+
+            // Let BE fail
+            while (currentFailable < failableCount) {
+                STORM_LOG_ASSERT(!mDft.hasFailed(currentState), "Dft has failed.");
+
+                // Construct new state as copy from original one
+                DFTStatePointer newState = std::make_shared<storm::storage::DFTState<ValueType>>(*currentState);
+                std::pair<std::shared_ptr<storm::storage::DFTBE<ValueType> const>, bool> nextBEPair = newState->letNextBEFail(currentFailable);
+                std::shared_ptr<storm::storage::DFTBE<ValueType> const>& nextBE = nextBEPair.first;
+                STORM_LOG_ASSERT(nextBE, "NextBE is null.");
+                STORM_LOG_ASSERT(nextBEPair.second == hasDependencies, "Failure due to dependencies does not match.");
+                STORM_LOG_TRACE("With the failure of: " << nextBE->name() << " [" << nextBE->id() << "] in " << mDft.getStateString(currentState));
+
+                /*if (storm::settings::getModule<storm::settings::modules::DFTSettings>().computeApproximation()) {
+                    if (!storm::utility::isZero(exitRate)) {
+                        ValueType rate = nextBE->activeFailureRate();
+                        ValueType div = rate / exitRate;
+                        if (!storm::utility::isZero(exitRate) && belowThreshold(div)) {
+                            // Set transition directly to failed state
+                            auto resultFind = outgoingRates.find(failedIndex);
+                            if (resultFind != outgoingRates.end()) {
+                                // Add to existing transition
+                                resultFind->second += rate;
+                                STORM_LOG_TRACE("Updated transition to " << resultFind->first << " with rate " << rate << " to new rate " << resultFind->second);
+                            } else {
+                                // Insert new transition
+                                outgoingRates.insert(std::make_pair(failedIndex, rate));
+                                STORM_LOG_TRACE("Added transition to " << failedIndex << " with rate " << rate);
+                            }
+                            exitRate += rate;
+                            std::cout << "IGNORE: " << nextBE->name() << " [" << nextBE->id() << "] with rate " << rate << std::endl;
+                            //STORM_LOG_TRACE("Ignore: " << nextBE->name() << " [" << nextBE->id() << "] with rate " << rate);
+                            continue;
                         }
                     }
-                    
-                    if (hasStateActionRewards && !program.isDiscreteTimeModel()) {
-                        totalExitRate += choice.getTotalMass();
+                }*/
+
+                // Propagate
+                storm::storage::DFTStateSpaceGenerationQueues<ValueType> queues;
+
+                // Propagate failure
+                for (DFTGatePointer parent : nextBE->parents()) {
+                    if (newState->isOperational(parent->id())) {
+                        queues.propagateFailure(parent);
+                    }
+                }
+                // Propagate failures
+                while (!queues.failurePropagationDone()) {
+                    DFTGatePointer next = queues.nextFailurePropagation();
+                    next->checkFails(*newState, queues);
+                    newState->updateFailableDependencies(next->id());
+                }
+
+                // Check restrictions
+                for (DFTRestrictionPointer restr : nextBE->restrictions()) {
+                    queues.checkRestrictionLater(restr);
+                }
+                // Check restrictions
+                while(!queues.restrictionChecksDone()) {
+                    DFTRestrictionPointer next = queues.nextRestrictionCheck();
+                    next->checkFails(*newState, queues);
+                    newState->updateFailableDependencies(next->id());
+                }
+
+                if(newState->isInvalid()) {
+                    // Continue with next possible state
+                    ++currentFailable;
+                    continue;
+                }
+
+                StateType newStateId;
+
+                if (newState->hasFailed(mDft.getTopLevelIndex()) && mergeFailedStates) {
+                    // Use unique failed state
+                    newStateId = mergeFailedStateId;
+                } else {
+                    // Propagate failsafe
+                    while (!queues.failsafePropagationDone()) {
+                        DFTGatePointer next = queues.nextFailsafePropagation();
+                        next->checkFailsafe(*newState, queues);
                     }
-                    
-                    if (buildChoiceLabeling) {
-                        globalChoice.addChoiceLabels(choice.getChoiceLabels());
+
+                    // Propagate dont cares
+                    while (enableDC && !queues.dontCarePropagationDone()) {
+                        DFTElementPointer next = queues.nextDontCarePropagation();
+                        next->checkDontCareAnymore(*newState, queues);
                     }
+
+                    // Update failable dependencies
+                    newState->updateFailableDependencies(nextBE->id());
+                    newState->updateDontCareDependencies(nextBE->id());
+
+                    // Add new state
+                    newStateId = stateToIdCallback(newState);
                 }
-                
-                // Now construct the state-action reward for all selected reward models.
-                for (auto const& rewardModel : selectedRewardModels) {
-                    ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
-                    if (rewardModel.get().hasStateActionRewards()) {
-                        for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) {
-                            for (auto const& choice : allChoices) {
-                                if (stateActionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(stateActionReward.getStatePredicateExpression())) {
-                                    stateActionRewardValue += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass() / totalExitRate;
-                                }
-                            }
-                            
-                        }
+
+                // Set transitions
+                if (hasDependencies) {
+                    // Failure is due to dependency -> add non-deterministic choice
+                    std::shared_ptr<storm::storage::DFTDependency<ValueType> const> dependency = mDft.getDependency(currentState->getDependencyId(currentFailable));
+                    choice.addProbability(newStateId, dependency->probability());
+                    STORM_LOG_TRACE("Added transition to " << newStateId << " with probability " << dependency->probability());
+
+                    if (!storm::utility::isOne(dependency->probability())) {
+                        // Add transition to state where dependency was unsuccessful
+                        DFTStatePointer unsuccessfulState = std::make_shared<storm::storage::DFTState<ValueType>>(*currentState);
+                        unsuccessfulState->letDependencyBeUnsuccessful(currentFailable);
+                        // Add state
+                        StateType unsuccessfulStateId = stateToIdCallback(unsuccessfulState);
+                        ValueType remainingProbability = storm::utility::one<ValueType>() - dependency->probability();
+                        choice.addProbability(unsuccessfulStateId, remainingProbability);
+                        STORM_LOG_TRACE("Added transition to " << unsuccessfulStateId << " with remaining probability " << remainingProbability);
                     }
-                    globalChoice.addChoiceReward(stateActionRewardValue);
+                    result.addChoice(std::move(choice));
+                } else {
+                    // Failure is due to "normal" BE failure
+                    // Set failure rate according to activation
+                    bool isActive = true;
+                    if (mDft.hasRepresentant(nextBE->id())) {
+                        // Active must be checked for the state we are coming from as this state is responsible for the
+                        // rate and not the new state we are going to
+                        isActive = currentState->isActive(mDft.getRepresentant(nextBE->id())->id());
+                    }
+                    ValueType rate = isActive ? nextBE->activeFailureRate() : nextBE->passiveFailureRate();
+                    STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Rate is 0.");
+                    choice.addProbability(newStateId, rate);
+                    STORM_LOG_TRACE("Added transition to " << newStateId << " with " << (isActive ? "active" : "passive") << " rate " << rate);
                 }
-                
-                // Move the newly fused choice in place.
-                allChoices.clear();
-                allChoices.push_back(std::move(globalChoice));
-            }
+
+                ++currentFailable;
+            } // end while failing BE
             
-            // Move all remaining choices in place.
-            for (auto& choice : allChoices) {
+            if (!hasDependencies) {
+                // Add all rates as one choice
                 result.addChoice(std::move(choice));
             }
-            
+
+            STORM_LOG_TRACE("Finished exploring state: " << mDft.getStateString(currentState));
             result.setExpanded();
-            return result;*/
-            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This functionality is not yet implemented.");
+            return result;
+        }
+
+        template<typename ValueType, typename StateType>
+        StateBehavior<ValueType, StateType> DftNextStateGenerator<ValueType, StateType>::createMergeFailedState(StateToIdCallback const& stateToIdCallback) {
+            STORM_LOG_ASSERT(mergeFailedStates, "No unique failed state used.");
+            // Introduce explicit fail state
+            DFTStatePointer failedState = std::make_shared<storm::storage::DFTState<ValueType>>(mDft, mStateGenerationInfo, 0);
+            mergeFailedStateId = stateToIdCallback(failedState);
+            STORM_LOG_TRACE("Introduce fail state with id: " << mergeFailedStateId);
+
+            // Add self loop
+            Choice<ValueType, StateType> choice(0, true);
+            choice.addProbability(mergeFailedStateId, storm::utility::one<ValueType>());
+
+            // No further exploration required
+            StateBehavior<ValueType, StateType> result;
+            result.addChoice(std::move(choice));
+            result.setExpanded();
+            return result;
         }
-        
         
         template class DftNextStateGenerator<double>;
         template class DftNextStateGenerator<storm::RationalFunction>;
diff --git a/src/generator/DftNextStateGenerator.h b/src/generator/DftNextStateGenerator.h
index 17a7dd25a..f7c4945c7 100644
--- a/src/generator/DftNextStateGenerator.h
+++ b/src/generator/DftNextStateGenerator.h
@@ -9,15 +9,21 @@
 namespace storm {
     namespace generator {
         
-        template<typename ValueType, typename StateType = uint_fast64_t>
+        /*!
+         * Next state generator for DFTs.
+         */
+        template<typename ValueType, typename StateType = uint32_t>
         class DftNextStateGenerator : public NextStateGenerator<ValueType, std::shared_ptr<storm::storage::DFTState<ValueType>>, StateType> {
 
             using DFTStatePointer = std::shared_ptr<storm::storage::DFTState<ValueType>>;
+            using DFTElementPointer = std::shared_ptr<storm::storage::DFTElement<ValueType>>;
+            using DFTGatePointer = std::shared_ptr<storm::storage::DFTGate<ValueType>>;
+            using DFTRestrictionPointer = std::shared_ptr<storm::storage::DFTRestriction<ValueType>>;
 
         public:
             typedef typename NextStateGenerator<ValueType, DFTStatePointer, StateType>::StateToIdCallback StateToIdCallback;
             
-            DftNextStateGenerator(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo);
+            DftNextStateGenerator(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, bool enableDC, bool mergeFailedStates);
                         
             virtual bool isDeterministicModel() const override;
             virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) override;
@@ -26,15 +32,38 @@ namespace storm {
             virtual StateBehavior<ValueType, StateType> expand(StateToIdCallback const& stateToIdCallback) override;
             virtual bool satisfies(storm::expressions::Expression const& expression) const override;
 
+            /*!
+             * Create unique failed state.
+             *
+             * @param stateToIdCallback Callback for state. The callback should just return the id and not use the state.
+             *
+             * @return Behavior of state.
+             */
+            StateBehavior<ValueType, StateType> createMergeFailedState(StateToIdCallback const& stateToIdCallback);
+
         private:
             
-            // The program used for the generation of next states.
+            // The dft used for the generation of next states.
             storm::storage::DFT<ValueType> const& mDft;
-            
+
+            // General information for the state generation.
             storm::storage::DFTStateGenerationInfo const& mStateGenerationInfo;
-            
-            DFTStatePointer const state;
-            
+
+            // Current state
+            DFTStatePointer const* state;
+
+            // Flag indicating if dont care propagation is enabled.
+            bool enableDC;
+
+            // Flag indication if all failed states should be merged into one.
+            bool mergeFailedStates = true;
+
+            // Id of the merged failed state
+            StateType mergeFailedStateId = 0;
+
+            // Flag indicating if the model is deterministic.
+            bool deterministicModel = true;
+
             // A comparator used to compare constants.
             storm::utility::ConstantsComparator<ValueType> comparator;
         };
diff --git a/src/generator/StateBehavior.cpp b/src/generator/StateBehavior.cpp
index 6ae1f6de0..ccbdd5166 100644
--- a/src/generator/StateBehavior.cpp
+++ b/src/generator/StateBehavior.cpp
@@ -56,7 +56,10 @@ namespace storm {
         }
         
         template class StateBehavior<double>;
+
+#ifdef STORM_HAVE_CARL
         template class StateBehavior<storm::RationalFunction>;
+#endif
 
     }
 }
\ No newline at end of file
diff --git a/src/models/sparse/MarkovAutomaton.cpp b/src/models/sparse/MarkovAutomaton.cpp
index 7b997293f..f8c40ad2f 100644
--- a/src/models/sparse/MarkovAutomaton.cpp
+++ b/src/models/sparse/MarkovAutomaton.cpp
@@ -265,7 +265,7 @@ namespace storm {
             }
             
             template <typename ValueType, typename RewardModelType>
-            std::shared_ptr<storm::models::sparse::Ctmc<ValueType, RewardModelType>> MarkovAutomaton<ValueType, RewardModelType>::convertToCTMC() {
+            std::shared_ptr<storm::models::sparse::Ctmc<ValueType, RewardModelType>> MarkovAutomaton<ValueType, RewardModelType>::convertToCTMC() const {
                 STORM_LOG_TRACE("MA matrix:" << std::endl << this->getTransitionMatrix());
                 STORM_LOG_TRACE("Markovian states: " << getMarkovianStates());
 
diff --git a/src/models/sparse/MarkovAutomaton.h b/src/models/sparse/MarkovAutomaton.h
index 9864f4f85..bb7272f6d 100644
--- a/src/models/sparse/MarkovAutomaton.h
+++ b/src/models/sparse/MarkovAutomaton.h
@@ -150,7 +150,12 @@ namespace storm {
                 
                 bool hasOnlyTrivialNondeterminism() const;
                 
-                std::shared_ptr<storm::models::sparse::Ctmc<ValueType, RewardModelType>> convertToCTMC();
+                /*!
+                 * Convert the MA into a MA by eliminating all states with probabilistic choices.
+                 *
+                 * @return Ctmc.
+                 */
+                std::shared_ptr<storm::models::sparse::Ctmc<ValueType, RewardModelType>> convertToCTMC() const;
                 
                 virtual void writeDotToStream(std::ostream& outStream, bool includeLabeling = true, storm::storage::BitVector const* subsystem = nullptr, std::vector<ValueType> const* firstValue = nullptr, std::vector<ValueType> const* secondValue = nullptr, std::vector<uint_fast64_t> const* stateColoring = nullptr, std::vector<std::string> const* colors = nullptr, std::vector<uint_fast64_t>* scheduler = nullptr, bool finalizeOutput = true) const;
                 
diff --git a/src/models/sparse/StateLabeling.cpp b/src/models/sparse/StateLabeling.cpp
index 7957e6a99..70561c8cb 100644
--- a/src/models/sparse/StateLabeling.cpp
+++ b/src/models/sparse/StateLabeling.cpp
@@ -29,7 +29,7 @@ namespace storm {
                 return true;
             }
             
-            StateLabeling StateLabeling::getSubLabeling(storm::storage::BitVector const& states) {
+            StateLabeling StateLabeling::getSubLabeling(storm::storage::BitVector const& states) const {
                 StateLabeling result(states.getNumberOfSetBits());
                 for (auto const& labelIndexPair : nameToLabelingIndexMap) {
                     result.addLabel(labelIndexPair.first, labelings[labelIndexPair.second] % states);
diff --git a/src/models/sparse/StateLabeling.h b/src/models/sparse/StateLabeling.h
index c7b3411a7..ac8ac730a 100644
--- a/src/models/sparse/StateLabeling.h
+++ b/src/models/sparse/StateLabeling.h
@@ -49,7 +49,7 @@ namespace storm {
                  *
                  * @param states The selected set of states.
                  */
-                StateLabeling getSubLabeling(storm::storage::BitVector const& states);
+                StateLabeling getSubLabeling(storm::storage::BitVector const& states) const;
                 
                 /*!
                  * Adds a new label to the labelings. Initially, no state is labeled with this label.
diff --git a/src/storage/dft/DFT.cpp b/src/storage/dft/DFT.cpp
index 5fdf44ab3..87ee74cdd 100644
--- a/src/storage/dft/DFT.cpp
+++ b/src/storage/dft/DFT.cpp
@@ -528,6 +528,11 @@ namespace storm {
             }
         }
 
+        template<typename ValueType>
+        bool DFT<ValueType>::canHaveNondeterminism() const {
+            return !getDependencies().empty();
+        }
+
         template<typename ValueType>
         DFTColouring<ValueType> DFT<ValueType>::colourDFT() const {
             return DFTColouring<ValueType>(*this);
diff --git a/src/storage/dft/DFT.h b/src/storage/dft/DFT.h
index 7b0177d07..c12204e06 100644
--- a/src/storage/dft/DFT.h
+++ b/src/storage/dft/DFT.h
@@ -198,6 +198,8 @@ namespace storm {
                 }
                 return elements;
             }
+
+            bool canHaveNondeterminism() const;
             
             std::vector<DFT<ValueType>> topModularisation() const;
             
diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index 9a0a16dba..156f99d14 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -9,11 +9,11 @@ namespace storm {
         DFTState<ValueType>::DFTState(DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(dft.stateVectorSize()), mId(id), mDft(dft), mStateGenerationInfo(stateGenerationInfo)  {
             
             // Initialize uses
-            for(size_t id  : mDft.getSpareIndices()) {
-                std::shared_ptr<DFTGate<ValueType> const> elem = mDft.getGate(id);
+            for(size_t spareId  : mDft.getSpareIndices()) {
+                std::shared_ptr<DFTGate<ValueType> const> elem = mDft.getGate(spareId);
                 STORM_LOG_ASSERT(elem->isSpareGate(), "Element is no spare gate.");
                 STORM_LOG_ASSERT(elem->nrChildren() > 0, "Element has no child.");
-                this->setUses(id, elem->children()[0]->id());
+                this->setUses(spareId, elem->children()[0]->id());
             }
             
             // Initialize activation
diff --git a/src/utility/vector.cpp b/src/utility/vector.cpp
index 20af3c628..44e480029 100644
--- a/src/utility/vector.cpp
+++ b/src/utility/vector.cpp
@@ -1,8 +1,9 @@
 #include "src/utility/vector.h"
 
-//template<typename ValueType>
-//std::ostream& operator<<(std::ostream& out, std::vector<ValueType> const& vector) {
-std::ostream& operator<<(std::ostream& out, std::vector<double> const& vector) {
+// Template was causing problems as Carl has the same function
+/*
+template<typename ValueType>
+std::ostream& operator<<(std::ostream& out, std::vector<ValueType> const& vector) {
     out << "vector (" << vector.size() << ") [ ";
     for (uint_fast64_t i = 0; i < vector.size() - 1; ++i) {
         out << vector[i] << ", ";
@@ -13,5 +14,26 @@ std::ostream& operator<<(std::ostream& out, std::vector<double> const& vector) {
 }
 
 // Explicitly instantiate functions.
-//template std::ostream& operator<<(std::ostream& out, std::vector<double> const& vector);
-//template std::ostream& operator<<(std::ostream& out, std::vector<uint_fast64_t> const& vector);
\ No newline at end of file
+template std::ostream& operator<<(std::ostream& out, std::vector<double> const& vector);
+template std::ostream& operator<<(std::ostream& out, std::vector<uint_fast64_t> const& vector);
+*/
+
+std::ostream& operator<<(std::ostream& out, std::vector<double> const& vector) {
+    out << "vector (" << vector.size() << ") [ ";
+    for (uint_fast64_t i = 0; i < vector.size() - 1; ++i) {
+        out << vector[i] << ", ";
+    }
+    out << vector.back();
+    out << " ]";
+    return out;
+}
+
+std::ostream& operator<<(std::ostream& out, std::vector<uint_fast64_t> const& vector) {
+    out << "vector (" << vector.size() << ") [ ";
+    for (uint_fast64_t i = 0; i < vector.size() - 1; ++i) {
+        out << vector[i] << ", ";
+    }
+    out << vector.back();
+    out << " ]";
+    return out;
+}
\ No newline at end of file
diff --git a/src/utility/vector.h b/src/utility/vector.h
index 0a4da1e03..a767f5fcc 100644
--- a/src/utility/vector.h
+++ b/src/utility/vector.h
@@ -19,6 +19,7 @@
 //template<typename ValueType>
 //std::ostream& operator<<(std::ostream& out, std::vector<ValueType> const& vector);
 std::ostream& operator<<(std::ostream& out, std::vector<double> const& vector);
+std::ostream& operator<<(std::ostream& out, std::vector<uint_fast64_t> const& vector);
 
 namespace storm {
     namespace utility {

From cfc082417ba8239a8d19d77b89fa1dab69f18819 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Mon, 26 Sep 2016 18:58:47 +0200
Subject: [PATCH 12/65] Refactoring

Former-commit-id: b3896c45a40b79181bf8b87dfe93813ca2e99093
---
 resources/3rdparty/CMakeLists.txt        |   4 +-
 src/CMakeLists.txt                       |   2 +
 src/generator/DftNextStateGenerator.cpp  |  41 +++--
 src/generator/DftNextStateGenerator.h    |   5 +-
 src/modelchecker/DFTAnalyser.h           | 201 ---------------------
 src/modelchecker/dft/DFTModelChecker.cpp | 214 +++++++++++++++++++++++
 src/modelchecker/dft/DFTModelChecker.h   | 104 +++++++++++
 src/storm-dyftee.cpp                     |  20 ++-
 8 files changed, 359 insertions(+), 232 deletions(-)
 delete mode 100644 src/modelchecker/DFTAnalyser.h
 create mode 100644 src/modelchecker/dft/DFTModelChecker.cpp
 create mode 100644 src/modelchecker/dft/DFTModelChecker.h

diff --git a/resources/3rdparty/CMakeLists.txt b/resources/3rdparty/CMakeLists.txt
index 9b30445f3..b9a1a1f75 100644
--- a/resources/3rdparty/CMakeLists.txt
+++ b/resources/3rdparty/CMakeLists.txt
@@ -18,7 +18,7 @@ ExternalProject_Add(
     DOWNLOAD_COMMAND ""
     PREFIX ${CMAKE_CURRENT_BINARY_DIR}/glpk-4.57
     SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/glpk-4.57
-    CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/glpk-4.57/configure --prefix=${CMAKE_CURRENT_BINARY_DIR}/glpk-4.57  --libdir=${CMAKE_CURRENT_BINARY_DIR}/glpk-4.57/lib CC=${CMAKE_C_COMPILER}
+    CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/glpk-4.57/configure --prefix=${CMAKE_CURRENT_BINARY_DIR}/glpk-4.57 --libdir=${CMAKE_CURRENT_BINARY_DIR}/glpk-4.57/lib CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER}
     BUILD_COMMAND make "CFLAGS=-O2 -w"
     INSTALL_COMMAND make install
     BUILD_IN_SOURCE 0
@@ -33,7 +33,7 @@ ExternalProject_Add(
     SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cudd-3.0.0
     PREFIX ${CMAKE_CURRENT_BINARY_DIR}/cudd-3.0.0
     UPDATE_COMMAND autoreconf
-    CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cudd-3.0.0/configure  --enable-shared   --enable-obj --prefix=${CMAKE_CURRENT_BINARY_DIR}/cudd-3.0.0 --libdir=${CMAKE_CURRENT_BINARY_DIR}/cudd-3.0.0/lib CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER}
+    CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cudd-3.0.0/configure --enable-shared --enable-obj --prefix=${CMAKE_CURRENT_BINARY_DIR}/cudd-3.0.0 --libdir=${CMAKE_CURRENT_BINARY_DIR}/cudd-3.0.0/lib CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER}
     BUILD_COMMAND make "CFLAGS=-O2 -w"
     INSTALL_COMMAND make install
     BUILD_IN_SOURCE 0
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 34b3cf77b..87b31189e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -22,6 +22,7 @@ file(GLOB_RECURSE STORM_MODELCHECKER_PRCTL_HELPER_FILES ${PROJECT_SOURCE_DIR}/sr
 file(GLOB STORM_MODELCHECKER_CSL_FILES ${PROJECT_SOURCE_DIR}/src/modelchecker/csl/*.h ${PROJECT_SOURCE_DIR}/src/modelchecker/csl/*.cpp)
 file(GLOB_RECURSE STORM_MODELCHECKER_CSL_HELPER_FILES ${PROJECT_SOURCE_DIR}/src/modelchecker/csl/helper/*.h ${PROJECT_SOURCE_DIR}/src/modelchecker/csl/helper/*.cpp)
 file(GLOB_RECURSE STORM_MODELCHECKER_REACHABILITY_FILES ${PROJECT_SOURCE_DIR}/src/modelchecker/reachability/*.h ${PROJECT_SOURCE_DIR}/src/modelchecker/reachability/*.cpp)
+file(GLOB_RECURSE STORM_MODELCHECKER_DFT_FILES ${PROJECT_SOURCE_DIR}/src/modelchecker/dft/*.h ${PROJECT_SOURCE_DIR}/src/modelchecker/dft/*.cpp)
 file(GLOB_RECURSE STORM_MODELCHECKER_EXPLORATION_FILES ${PROJECT_SOURCE_DIR}/src/modelchecker/exploration/*.h ${PROJECT_SOURCE_DIR}/src/modelchecker/exploration/*.cpp)
 file(GLOB_RECURSE STORM_MODELCHECKER_PROPOSITIONAL_FILES ${PROJECT_SOURCE_DIR}/src/modelchecker/propositional/*.h ${PROJECT_SOURCE_DIR}/src/modelchecker/propositional/*.cpp)
 file(GLOB_RECURSE STORM_MODELCHECKER_RESULTS_FILES ${PROJECT_SOURCE_DIR}/src/modelchecker/results/*.h ${PROJECT_SOURCE_DIR}/src/modelchecker/results/*.cpp)
@@ -75,6 +76,7 @@ source_group(modelchecker\\prctl FILES ${STORM_MODELCHECKER_PRCTL_FILES})
 source_group(modelchecker\\prctl\\helper FILES ${STORM_MODELCHECKER_PRCTL_HELPER_FILES})
 source_group(modelchecker\\csl FILES ${STORM_MODELCHECKER_CSL_FILES})
 source_group(modelchecker\\csl\\helper FILES ${STORM_MODELCHECKER_CSL_HELPER_FILES})
+source_group(modelchecker\\dft FILES ${STORM_MODELCHECKER_DFT_FILES})
 source_group(modelchecker\\exploration FILES ${STORM_MODELCHECKER_EXPLORATION_FILES})
 source_group(modelchecker\\reachability FILES ${STORM_MODELCHECKER_REACHABILITY_FILES})
 source_group(modelchecker\\propositional FILES ${STORM_MODELCHECKER_PROPOSITIONAL_FILES})
diff --git a/src/generator/DftNextStateGenerator.cpp b/src/generator/DftNextStateGenerator.cpp
index 953a36db4..1f39fe2cf 100644
--- a/src/generator/DftNextStateGenerator.cpp
+++ b/src/generator/DftNextStateGenerator.cpp
@@ -27,12 +27,18 @@ namespace storm {
             initialState->setId(id);
             return {id};
         }
-        
+
+        template<typename ValueType, typename StateType>
+        void DftNextStateGenerator<ValueType, StateType>::load(CompressedState const& state) {
+            // Load the state from bitvector
+            size_t id = 0; //TODO Matthias: set correct id
+            this->state = std::make_shared<storm::storage::DFTState<ValueType>>(state, mDft, mStateGenerationInfo, id);
+        }
+
         template<typename ValueType, typename StateType>
         void DftNextStateGenerator<ValueType, StateType>::load(DFTStatePointer const& state) {
-            // TODO Matthias load state from bitvector
             // Store a pointer to the state itself, because we need to be able to access it when expanding it.
-            this->state = &state;
+            this->state = state;
         }
         
         template<typename ValueType, typename StateType>
@@ -42,23 +48,22 @@ namespace storm {
         
         template<typename ValueType, typename StateType>
         StateBehavior<ValueType, StateType> DftNextStateGenerator<ValueType, StateType>::expand(StateToIdCallback const& stateToIdCallback) {
-            DFTStatePointer currentState = *state;
-            STORM_LOG_TRACE("Explore state: " << mDft.getStateString(currentState));
+            STORM_LOG_TRACE("Explore state: " << mDft.getStateString(state));
 
             // Prepare the result, in case we return early.
             StateBehavior<ValueType, StateType> result;
 
             // Initialization
-            bool hasDependencies = currentState->nrFailableDependencies() > 0;
-            size_t failableCount = hasDependencies ? currentState->nrFailableDependencies() : currentState->nrFailableBEs();
+            bool hasDependencies = state->nrFailableDependencies() > 0;
+            size_t failableCount = hasDependencies ? state->nrFailableDependencies() : state->nrFailableBEs();
             size_t currentFailable = 0;
             Choice<ValueType, StateType> choice(0, !hasDependencies);
 
             // Check for absorbing state
-            if (mDft.hasFailed(currentState) || mDft.isFailsafe(currentState) || currentState->nrFailableBEs() == 0) {
+            if (mDft.hasFailed(state) || mDft.isFailsafe(state) || state->nrFailableBEs() == 0) {
                 // Add self loop
-                choice.addProbability(currentState->getId(), storm::utility::one<ValueType>());
-                STORM_LOG_TRACE("Added self loop for " << currentState->getId());
+                choice.addProbability(state->getId(), storm::utility::one<ValueType>());
+                STORM_LOG_TRACE("Added self loop for " << state->getId());
                 // No further exploration required
                 result.addChoice(std::move(choice));
                 result.setExpanded();
@@ -67,15 +72,15 @@ namespace storm {
 
             // Let BE fail
             while (currentFailable < failableCount) {
-                STORM_LOG_ASSERT(!mDft.hasFailed(currentState), "Dft has failed.");
+                STORM_LOG_ASSERT(!mDft.hasFailed(state), "Dft has failed.");
 
                 // Construct new state as copy from original one
-                DFTStatePointer newState = std::make_shared<storm::storage::DFTState<ValueType>>(*currentState);
+                DFTStatePointer newState = std::make_shared<storm::storage::DFTState<ValueType>>(*state);
                 std::pair<std::shared_ptr<storm::storage::DFTBE<ValueType> const>, bool> nextBEPair = newState->letNextBEFail(currentFailable);
                 std::shared_ptr<storm::storage::DFTBE<ValueType> const>& nextBE = nextBEPair.first;
                 STORM_LOG_ASSERT(nextBE, "NextBE is null.");
                 STORM_LOG_ASSERT(nextBEPair.second == hasDependencies, "Failure due to dependencies does not match.");
-                STORM_LOG_TRACE("With the failure of: " << nextBE->name() << " [" << nextBE->id() << "] in " << mDft.getStateString(currentState));
+                STORM_LOG_TRACE("With the failure of: " << nextBE->name() << " [" << nextBE->id() << "] in " << mDft.getStateString(state));
 
                 /*if (storm::settings::getModule<storm::settings::modules::DFTSettings>().computeApproximation()) {
                     if (!storm::utility::isZero(exitRate)) {
@@ -163,13 +168,13 @@ namespace storm {
                 // Set transitions
                 if (hasDependencies) {
                     // Failure is due to dependency -> add non-deterministic choice
-                    std::shared_ptr<storm::storage::DFTDependency<ValueType> const> dependency = mDft.getDependency(currentState->getDependencyId(currentFailable));
+                    std::shared_ptr<storm::storage::DFTDependency<ValueType> const> dependency = mDft.getDependency(state->getDependencyId(currentFailable));
                     choice.addProbability(newStateId, dependency->probability());
                     STORM_LOG_TRACE("Added transition to " << newStateId << " with probability " << dependency->probability());
 
                     if (!storm::utility::isOne(dependency->probability())) {
                         // Add transition to state where dependency was unsuccessful
-                        DFTStatePointer unsuccessfulState = std::make_shared<storm::storage::DFTState<ValueType>>(*currentState);
+                        DFTStatePointer unsuccessfulState = std::make_shared<storm::storage::DFTState<ValueType>>(*state);
                         unsuccessfulState->letDependencyBeUnsuccessful(currentFailable);
                         // Add state
                         StateType unsuccessfulStateId = stateToIdCallback(unsuccessfulState);
@@ -185,7 +190,7 @@ namespace storm {
                     if (mDft.hasRepresentant(nextBE->id())) {
                         // Active must be checked for the state we are coming from as this state is responsible for the
                         // rate and not the new state we are going to
-                        isActive = currentState->isActive(mDft.getRepresentant(nextBE->id())->id());
+                        isActive = state->isActive(mDft.getRepresentant(nextBE->id())->id());
                     }
                     ValueType rate = isActive ? nextBE->activeFailureRate() : nextBE->passiveFailureRate();
                     STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Rate is 0.");
@@ -201,7 +206,7 @@ namespace storm {
                 result.addChoice(std::move(choice));
             }
 
-            STORM_LOG_TRACE("Finished exploring state: " << mDft.getStateString(currentState));
+            STORM_LOG_TRACE("Finished exploring state: " << mDft.getStateString(state));
             result.setExpanded();
             return result;
         }
@@ -228,4 +233,4 @@ namespace storm {
         template class DftNextStateGenerator<double>;
         template class DftNextStateGenerator<storm::RationalFunction>;
     }
-}
\ No newline at end of file
+}
diff --git a/src/generator/DftNextStateGenerator.h b/src/generator/DftNextStateGenerator.h
index f7c4945c7..beab8f5f0 100644
--- a/src/generator/DftNextStateGenerator.h
+++ b/src/generator/DftNextStateGenerator.h
@@ -29,6 +29,7 @@ namespace storm {
             virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) override;
 
             virtual void load(DFTStatePointer const& state) override;
+            void load(CompressedState const& state);
             virtual StateBehavior<ValueType, StateType> expand(StateToIdCallback const& stateToIdCallback) override;
             virtual bool satisfies(storm::expressions::Expression const& expression) const override;
 
@@ -50,7 +51,7 @@ namespace storm {
             storm::storage::DFTStateGenerationInfo const& mStateGenerationInfo;
 
             // Current state
-            DFTStatePointer const* state;
+            DFTStatePointer state;
 
             // Flag indicating if dont care propagation is enabled.
             bool enableDC;
@@ -71,4 +72,4 @@ namespace storm {
     }
 }
 
-#endif /* STORM_GENERATOR_DFTNEXTSTATEGENERATOR_H_ */
\ No newline at end of file
+#endif /* STORM_GENERATOR_DFTNEXTSTATEGENERATOR_H_ */
diff --git a/src/modelchecker/DFTAnalyser.h b/src/modelchecker/DFTAnalyser.h
deleted file mode 100644
index cc1e34696..000000000
--- a/src/modelchecker/DFTAnalyser.h
+++ /dev/null
@@ -1,201 +0,0 @@
-#pragma once
-
-#include "src/logic/Formula.h"
-#include "src/parser/DFTGalileoParser.h"
-#include "src/builder/ExplicitDFTModelBuilder.h"
-#include "src/builder/ExplicitDFTModelBuilderApprox.h"
-#include "src/modelchecker/results/CheckResult.h"
-#include "src/utility/storm.h"
-#include "src/storage/dft/DFTIsomorphism.h"
-#include "src/settings/modules/DFTSettings.h"
-#include "src/utility/bitoperations.h"
-
-
-#include <chrono>
-
-template<typename ValueType>
-class DFTAnalyser {
-    
-    std::chrono::duration<double> buildingTime = std::chrono::duration<double>::zero();
-    std::chrono::duration<double> explorationTime = std::chrono::duration<double>::zero();
-    std::chrono::duration<double> bisimulationTime = std::chrono::duration<double>::zero();
-    std::chrono::duration<double> modelCheckingTime = std::chrono::duration<double>::zero();
-    std::chrono::duration<double> totalTime = std::chrono::duration<double>::zero();
-    ValueType checkResult = storm::utility::zero<ValueType>();
-public:
-    void check(storm::storage::DFT<ValueType> const& origDft , std::shared_ptr<const storm::logic::Formula> const& formula, bool symred = true, bool allowModularisation = true, bool enableDC = true) {
-        
-        // Building DFT
-        std::chrono::high_resolution_clock::time_point totalStart = std::chrono::high_resolution_clock::now();
-        
-        
-        // Optimizing DFT
-        storm::storage::DFT<ValueType> dft = origDft.optimize();
-        checkResult = checkHelper(dft, formula, symred, allowModularisation, enableDC);
-        totalTime = std::chrono::high_resolution_clock::now() - totalStart;
-            
-        
-            
-    }
-    
-private:
-    ValueType checkHelper(storm::storage::DFT<ValueType> const& dft , std::shared_ptr<const storm::logic::Formula> const& formula, bool symred = true, bool allowModularisation = true, bool enableDC = true)  {
-        STORM_LOG_TRACE("Check helper called");
-        bool invResults = false;
-        std::vector<storm::storage::DFT<ValueType>> dfts = {dft};
-        std::vector<ValueType> res;
-        size_t nrK = 0; // K out of M 
-        size_t nrM = 0; // K out of M
-        
-        if(allowModularisation) {
-            if(dft.topLevelType() == storm::storage::DFTElementType::AND) {
-                STORM_LOG_TRACE("top modularisation called AND");
-                dfts = dft.topModularisation();
-                STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
-                nrK = dfts.size();
-                nrM = dfts.size();
-            }
-            if(dft.topLevelType() == storm::storage::DFTElementType::OR) {
-                STORM_LOG_TRACE("top modularisation called OR");
-                dfts = dft.topModularisation();
-                STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
-                nrK = 0;
-                nrM = dfts.size();
-                invResults = true;
-            }
-            if(dft.topLevelType() == storm::storage::DFTElementType::VOT) {
-                STORM_LOG_TRACE("top modularisation called VOT");
-                dfts = dft.topModularisation();
-                STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
-                nrK = std::static_pointer_cast<storm::storage::DFTVot<ValueType> const>(dft.getTopLevelGate())->threshold();
-                nrM = dfts.size();
-                if(nrK <= nrM/2) {
-                    nrK -= 1;
-                    invResults = true;
-                }
-            }
-            if(dfts.size() > 1) {
-                STORM_LOG_TRACE("Recursive CHECK Call");
-                for(auto const ft : dfts) {
-                    res.push_back(checkHelper(ft, formula, symred, allowModularisation));
-                }
-            }
-        } 
-        if(res.empty()) {
-            // Model based modularisation.
-            auto const& models = buildMarkovModels(dfts, formula, symred, enableDC);
-
-
-            for (auto const& model : models) {
-                // Model checking
-                STORM_LOG_INFO("Model checking...");
-                std::chrono::high_resolution_clock::time_point modelCheckingStart = std::chrono::high_resolution_clock::now();
-                std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySparseModel(model, formula));
-                STORM_LOG_INFO("Model checking done.");
-                STORM_LOG_ASSERT(result, "Result does not exist.");
-                result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
-                modelCheckingTime += std::chrono::high_resolution_clock::now() -  modelCheckingStart;
-                res.push_back(result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second);
-            }
-        }
-        if(nrM <= 1) {
-            // No modularisation done.
-            STORM_LOG_ASSERT(res.size()==1, "Result size not 1.");
-            return res[0];
-        }
-        
-        STORM_LOG_TRACE("Combining all results... K=" << nrK << "; M=" << nrM << "; invResults=" << (invResults?"On":"Off"));
-        ValueType result = storm::utility::zero<ValueType>();
-        int limK = invResults ? -1 : nrM+1;
-        int chK = invResults ? -1 : 1;
-        for(int cK = nrK; cK != limK; cK += chK ) {
-            STORM_LOG_ASSERT(cK >= 0, "ck negative.");
-            size_t permutation = smallestIntWithNBitsSet(static_cast<size_t>(cK));
-            do {
-                STORM_LOG_TRACE("Permutation="<<permutation);
-                ValueType permResult = storm::utility::one<ValueType>();
-                for(size_t i = 0; i < res.size(); ++i) {
-                    if(permutation & (1 << i)) {
-                        permResult *= res[i];
-                    } else {
-                        permResult *= storm::utility::one<ValueType>() - res[i];
-                    }
-                }
-                STORM_LOG_TRACE("Result for permutation:"<<permResult);
-                permutation = nextBitPermutation(permutation);
-                result += permResult;
-            } while(permutation < (1 << nrM) && permutation != 0);
-        }
-        if(invResults) {
-            return storm::utility::one<ValueType>() - result;
-        }
-        return result;
-    }
-    
-    
-    std::vector<std::shared_ptr<storm::models::sparse::Model<ValueType>>> buildMarkovModels(std::vector<storm::storage::DFT<ValueType>> const&  dfts,   std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool enableDC) {
-        std::vector<std::shared_ptr<storm::models::sparse::Model<ValueType>>> models;
-        for(auto& dft : dfts) {
-            std::chrono::high_resolution_clock::time_point buildingStart = std::chrono::high_resolution_clock::now();
-
-            std::map<size_t, std::vector<std::vector<size_t>>> emptySymmetry;
-            storm::storage::DFTIndependentSymmetries symmetries(emptySymmetry);
-            if(symred) {
-                auto colouring = dft.colourDFT();
-                symmetries = dft.findSymmetries(colouring);
-                STORM_LOG_INFO("Found " << symmetries.groups.size() << " symmetries.");
-                STORM_LOG_TRACE("Symmetries: " << std::endl << symmetries);
-            }
-            std::chrono::high_resolution_clock::time_point buildingEnd = std::chrono::high_resolution_clock::now();
-            buildingTime += buildingEnd - buildingStart;
-            
-            // Building Markov Automaton
-            STORM_LOG_INFO("Building Model...");
-            std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
-            // TODO Matthias: use only one builder if everything works again
-            if (storm::settings::getModule<storm::settings::modules::DFTSettings>().computeApproximation()) {
-                storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
-                typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
-                model = builder.buildModel(labeloptions);
-            } else {
-                storm::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries, enableDC);
-                typename storm::builder::ExplicitDFTModelBuilder<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
-                model = builder.buildModel(labeloptions);
-            }
-            //model->printModelInformationToStream(std::cout);
-            STORM_LOG_INFO("No. states (Explored): " << model->getNumberOfStates());
-            STORM_LOG_INFO("No. transitions (Explored): " << model->getNumberOfTransitions());
-            std::chrono::high_resolution_clock::time_point explorationEnd = std::chrono::high_resolution_clock::now();
-            explorationTime += explorationEnd -buildingEnd;
-
-            // Bisimulation
-            if (model->isOfType(storm::models::ModelType::Ctmc) && storm::settings::getModule<storm::settings::modules::GeneralSettings>().isBisimulationSet()) {
-                STORM_LOG_INFO("Bisimulation...");
-                model =  storm::performDeterministicSparseBisimulationMinimization<storm::models::sparse::Ctmc<ValueType>>(model->template as<storm::models::sparse::Ctmc<ValueType>>(), {formula}, storm::storage::BisimulationType::Weak)->template as<storm::models::sparse::Ctmc<ValueType>>();
-                //model->printModelInformationToStream(std::cout);
-            }
-            STORM_LOG_INFO("No. states (Bisimulation): " << model->getNumberOfStates());
-            STORM_LOG_INFO("No. transitions (Bisimulation): " << model->getNumberOfTransitions());
-            bisimulationTime += std::chrono::high_resolution_clock::now() - explorationEnd;
-            models.push_back(model);
-        }
-        return models;
-    }
-    
-public:
-    void printTimings(std::ostream& os = std::cout) {
-        os << "Times:" << std::endl;
-        os << "Building:\t" << buildingTime.count() << std::endl;
-        os << "Exploration:\t" << explorationTime.count() << std::endl;
-        os << "Bisimulation:\t" << bisimulationTime.count() << std::endl;
-        os << "Modelchecking:\t" << modelCheckingTime.count() << std::endl;
-        os << "Total:\t\t" << totalTime.count() << std::endl;
-    }
-    
-    void printResult(std::ostream& os = std::cout) {
-        
-        os << "Result: [";
-        os << checkResult << "]" << std::endl;
-    }
-    
-};
diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
new file mode 100644
index 000000000..3aa3ed27b
--- /dev/null
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -0,0 +1,214 @@
+#include "src/modelchecker/dft/DFTModelChecker.h"
+
+#include "src/builder/ExplicitDFTModelBuilder.h"
+#include "src/builder/ExplicitDFTModelBuilderApprox.h"
+#include "src/storage/dft/DFTIsomorphism.h"
+#include "src/settings/modules/DFTSettings.h"
+#include "src/utility/bitoperations.h"
+
+namespace storm {
+    namespace modelchecker {
+
+        template<typename ValueType>
+        DFTModelChecker<ValueType>::DFTModelChecker() {
+            // Intentionally left empty.
+        }
+
+        template<typename ValueType>
+        void DFTModelChecker<ValueType>::check(storm::storage::DFT<ValueType> const& origDft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool allowModularisation, bool enableDC) {
+            std::chrono::high_resolution_clock::time_point totalStart = std::chrono::high_resolution_clock::now();
+            // Optimizing DFT
+            storm::storage::DFT<ValueType> dft = origDft.optimize();
+            checkResult = checkHelper(dft, formula, symred, allowModularisation, enableDC);
+            totalTime = std::chrono::high_resolution_clock::now() - totalStart;
+        }
+
+        template<typename ValueType>
+        ValueType DFTModelChecker<ValueType>::checkHelper(storm::storage::DFT<ValueType> const& dft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool allowModularisation, bool enableDC)  {
+            STORM_LOG_TRACE("Check helper called");
+            bool invResults = false;
+            std::vector<storm::storage::DFT<ValueType>> dfts = {dft};
+            std::vector<ValueType> res;
+            size_t nrK = 0; // K out of M
+            size_t nrM = 0; // K out of M
+
+            // Try modularisation
+            if(allowModularisation) {
+                if(dft.topLevelType() == storm::storage::DFTElementType::AND) {
+                    STORM_LOG_TRACE("top modularisation called AND");
+                    dfts = dft.topModularisation();
+                    STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
+                    nrK = dfts.size();
+                    nrM = dfts.size();
+                }
+                if(dft.topLevelType() == storm::storage::DFTElementType::OR) {
+                    STORM_LOG_TRACE("top modularisation called OR");
+                    dfts = dft.topModularisation();
+                    STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
+                    nrK = 0;
+                    nrM = dfts.size();
+                    invResults = true;
+                }
+                if(dft.topLevelType() == storm::storage::DFTElementType::VOT) {
+                    STORM_LOG_TRACE("top modularisation called VOT");
+                    dfts = dft.topModularisation();
+                    STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
+                    nrK = std::static_pointer_cast<storm::storage::DFTVot<ValueType> const>(dft.getTopLevelGate())->threshold();
+                    nrM = dfts.size();
+                    if(nrK <= nrM/2) {
+                        nrK -= 1;
+                        invResults = true;
+                    }
+                }
+                if(dfts.size() > 1) {
+                    STORM_LOG_TRACE("Recursive CHECK Call");
+                    for(auto const ft : dfts) {
+                        res.push_back(checkHelper(ft, formula, symred, allowModularisation, enableDC));
+                    }
+                }
+            }
+
+            if(res.empty()) {
+                // Model based modularisation.
+                auto const& models = buildMarkovModels(dfts, formula, symred, enableDC);
+                
+                for (auto const& model : models) {
+                    // Model checking
+                    STORM_LOG_INFO("Model checking...");
+                    std::chrono::high_resolution_clock::time_point modelCheckingStart = std::chrono::high_resolution_clock::now();
+                    std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySparseModel(model, formula));
+                    STORM_LOG_INFO("Model checking done.");
+                    STORM_LOG_ASSERT(result, "Result does not exist.");
+                    result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
+                    modelCheckingTime += std::chrono::high_resolution_clock::now() -  modelCheckingStart;
+                    res.push_back(result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second);
+                }
+            }
+            if(nrM <= 1) {
+                // No modularisation done.
+                STORM_LOG_ASSERT(res.size()==1, "Result size not 1.");
+                return res[0];
+            }
+
+            STORM_LOG_TRACE("Combining all results... K=" << nrK << "; M=" << nrM << "; invResults=" << (invResults?"On":"Off"));
+            ValueType result = storm::utility::zero<ValueType>();
+            int limK = invResults ? -1 : nrM+1;
+            int chK = invResults ? -1 : 1;
+            for(int cK = nrK; cK != limK; cK += chK ) {
+                STORM_LOG_ASSERT(cK >= 0, "ck negative.");
+                size_t permutation = smallestIntWithNBitsSet(static_cast<size_t>(cK));
+                do {
+                    STORM_LOG_TRACE("Permutation="<<permutation);
+                    ValueType permResult = storm::utility::one<ValueType>();
+                    for(size_t i = 0; i < res.size(); ++i) {
+                        if(permutation & (1 << i)) {
+                            permResult *= res[i];
+                        } else {
+                            permResult *= storm::utility::one<ValueType>() - res[i];
+                        }
+                    }
+                    STORM_LOG_TRACE("Result for permutation:"<<permResult);
+                    permutation = nextBitPermutation(permutation);
+                    result += permResult;
+                } while(permutation < (1 << nrM) && permutation != 0);
+            }
+            if(invResults) {
+                return storm::utility::one<ValueType>() - result;
+            }
+            return result;
+        }
+
+        template<typename ValueType>
+        std::vector<ValueType> DFTModelChecker<ValueType>::checkModel(std::vector<storm::storage::DFT<ValueType>> const& dfts, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool enableDC, double approximationError) {
+            std::vector<ValueType> results;
+
+            auto const& models = buildMarkovModels(dfts, formula, symred, enableDC);
+
+            for (auto const& model : models) {
+                // Model checking
+                STORM_LOG_INFO("Model checking...");
+                std::chrono::high_resolution_clock::time_point modelCheckingStart = std::chrono::high_resolution_clock::now();
+                std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySparseModel(model, formula));
+                STORM_LOG_INFO("Model checking done.");
+                STORM_LOG_ASSERT(result, "Result does not exist.");
+                result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
+                modelCheckingTime += std::chrono::high_resolution_clock::now() -  modelCheckingStart;
+                results.push_back(result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second);
+            }
+            return results;
+        }
+
+        template<typename ValueType>
+        std::vector<std::shared_ptr<storm::models::sparse::Model<ValueType>>> DFTModelChecker<ValueType>::buildMarkovModels(std::vector<storm::storage::DFT<ValueType>> const& dfts, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool enableDC, double approximationError) {
+            std::vector<std::shared_ptr<storm::models::sparse::Model<ValueType>>> models;
+            for(auto& dft : dfts) {
+                std::chrono::high_resolution_clock::time_point buildingStart = std::chrono::high_resolution_clock::now();
+
+                std::map<size_t, std::vector<std::vector<size_t>>> emptySymmetry;
+                storm::storage::DFTIndependentSymmetries symmetries(emptySymmetry);
+                if(symred) {
+                    auto colouring = dft.colourDFT();
+                    symmetries = dft.findSymmetries(colouring);
+                    STORM_LOG_INFO("Found " << symmetries.groups.size() << " symmetries.");
+                    STORM_LOG_TRACE("Symmetries: " << std::endl << symmetries);
+                }
+                std::chrono::high_resolution_clock::time_point buildingEnd = std::chrono::high_resolution_clock::now();
+                buildingTime += buildingEnd - buildingStart;
+
+                // Building Markov Automaton
+                STORM_LOG_INFO("Building Model...");
+                std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
+                // TODO Matthias: use only one builder if everything works again
+                if (storm::settings::getModule<storm::settings::modules::DFTSettings>().computeApproximation()) {
+                    storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
+                    typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
+                    model = builder.buildModel(labeloptions);
+                } else {
+                    storm::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries, enableDC);
+                    typename storm::builder::ExplicitDFTModelBuilder<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
+                    model = builder.buildModel(labeloptions);
+                }
+                //model->printModelInformationToStream(std::cout);
+                STORM_LOG_INFO("No. states (Explored): " << model->getNumberOfStates());
+                STORM_LOG_INFO("No. transitions (Explored): " << model->getNumberOfTransitions());
+                std::chrono::high_resolution_clock::time_point explorationEnd = std::chrono::high_resolution_clock::now();
+                explorationTime += explorationEnd -buildingEnd;
+
+                // Bisimulation
+                if (model->isOfType(storm::models::ModelType::Ctmc) && storm::settings::getModule<storm::settings::modules::GeneralSettings>().isBisimulationSet()) {
+                    STORM_LOG_INFO("Bisimulation...");
+                    model =  storm::performDeterministicSparseBisimulationMinimization<storm::models::sparse::Ctmc<ValueType>>(model->template as<storm::models::sparse::Ctmc<ValueType>>(), {formula}, storm::storage::BisimulationType::Weak)->template as<storm::models::sparse::Ctmc<ValueType>>();
+                    //model->printModelInformationToStream(std::cout);
+                }
+                STORM_LOG_INFO("No. states (Bisimulation): " << model->getNumberOfStates());
+                STORM_LOG_INFO("No. transitions (Bisimulation): " << model->getNumberOfTransitions());
+                bisimulationTime += std::chrono::high_resolution_clock::now() - explorationEnd;
+                models.push_back(model);
+            }
+            return models;
+        }
+
+        template<typename ValueType>
+        void DFTModelChecker<ValueType>::printTimings(std::ostream& os) {
+            os << "Times:" << std::endl;
+            os << "Building:\t" << buildingTime.count() << std::endl;
+            os << "Exploration:\t" << explorationTime.count() << std::endl;
+            os << "Bisimulation:\t" << bisimulationTime.count() << std::endl;
+            os << "Modelchecking:\t" << modelCheckingTime.count() << std::endl;
+            os << "Total:\t\t" << totalTime.count() << std::endl;
+        }
+
+        template<typename ValueType>
+        void DFTModelChecker<ValueType>::printResult(std::ostream& os) {
+            os << "Result: [";
+            os << checkResult << "]" << std::endl;
+        }
+
+
+        template class DFTModelChecker<double>;
+
+#ifdef STORM_HAVE_CARL
+        template class DFTModelChecker<storm::RationalFunction>;
+#endif
+    }
+}
diff --git a/src/modelchecker/dft/DFTModelChecker.h b/src/modelchecker/dft/DFTModelChecker.h
new file mode 100644
index 000000000..0867ed094
--- /dev/null
+++ b/src/modelchecker/dft/DFTModelChecker.h
@@ -0,0 +1,104 @@
+#ifndef STORM_MODELCHECKER_DFT_DFTMODELCHECKER_H_
+
+#include "src/logic/Formula.h"
+#include "src/modelchecker/results/CheckResult.h"
+#include "src/storage/dft/DFT.h"
+#include "src/utility/storm.h"
+
+#include <chrono>
+
+
+namespace storm {
+    namespace modelchecker {
+
+        /**
+         * Analyser for DFTs.
+         */
+        template<typename ValueType>
+        class DFTModelChecker {
+
+        public:
+
+            /**
+             * Constructor.
+             */
+            DFTModelChecker();
+
+            /**
+             * Main method for checking DFTs.
+             *
+             * @param origDft             Original DFT
+             * @param formula             Formula to check for
+             * @param symred              Flag indicating if symmetry reduction should be used
+             * @param allowModularisation Flag indication if modularisation is allowed
+             * @param enableDC            Flag indicating if dont care propagation should be used
+             */
+            void check(storm::storage::DFT<ValueType> const& origDft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred = true, bool allowModularisation = true, bool enableDC = true);
+
+            /**
+             * Print timings of all operations to stream.
+             *
+             * @param os Output stream to write to.
+             */
+            void printTimings(std::ostream& os = std::cout);
+
+            /**
+             * Print result to stream.
+             *
+             * @param os Output stream to write to.
+             */
+            void printResult(std::ostream& os = std::cout);
+
+        private:
+            // Timing values
+            std::chrono::duration<double> buildingTime = std::chrono::duration<double>::zero();
+            std::chrono::duration<double> explorationTime = std::chrono::duration<double>::zero();
+            std::chrono::duration<double> bisimulationTime = std::chrono::duration<double>::zero();
+            std::chrono::duration<double> modelCheckingTime = std::chrono::duration<double>::zero();
+            std::chrono::duration<double> totalTime = std::chrono::duration<double>::zero();
+            // Model checking result
+            ValueType checkResult = storm::utility::zero<ValueType>();
+
+            /**
+             * Internal helper for model checking a DFT.
+             *
+             * @param dft                 DFT
+             * @param formula             Formula to check for
+             * @param symred              Flag indicating if symmetry reduction should be used
+             * @param allowModularisation Flag indication if modularisation is allowed
+             * @param enableDC            Flag indicating if dont care propagation should be used
+             *
+             * @return Model checking result
+             */
+            ValueType checkHelper(storm::storage::DFT<ValueType> const& dft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool allowModularisation, bool enableDC);
+
+            /**
+             * Check the Dfts via model checking.
+             *
+             * @param dfts               Vector of Dfts
+             * @param formula            Formula to check for
+             * @param symred             Flag indicating if symmetry reduction should be used
+             * @param enableDC           Flag indicating if dont care propagation should be used
+             * @param approximationError Error allowed for approximation. Value 0 indicates no approximation
+             *
+             * @return Vector of results for each model
+             */
+            std::vector<ValueType> checkModel(std::vector<storm::storage::DFT<ValueType>> const& dfts, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool enableDC, double approximationError = 0.0);
+
+            /**
+             * Build markov models from DFTs.
+             *
+             * @param dfts               Vector of Dfts
+             * @param formula            Formula to check for
+             * @param symred             Flag indicating if symmetry reduction should be used
+             * @param enableDC           Flag indicating if dont care propagation should be used
+             * @param approximationError Error allowed for approximation. Value 0 indicates no approximation
+             *
+             * @return Vector of markov models corresponding to DFTs.
+             */
+            std::vector<std::shared_ptr<storm::models::sparse::Model<ValueType>>> buildMarkovModels(std::vector<storm::storage::DFT<ValueType>> const& dfts, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool enableDC, double approximationError = 0.0);
+
+        };
+    }
+}
+#endif /* STORM_MODELCHECKER_DFT_DFTMODELCHECKER_H_ */
diff --git a/src/storm-dyftee.cpp b/src/storm-dyftee.cpp
index 4cfd1f58f..89fc1da7b 100644
--- a/src/storm-dyftee.cpp
+++ b/src/storm-dyftee.cpp
@@ -1,12 +1,12 @@
-#include "logic/Formula.h"
-#include "utility/initialize.h"
-#include "utility/storm.h"
-#include "modelchecker/DFTAnalyser.h"
+#include "src/logic/Formula.h"
+#include "src/utility/initialize.h"
+#include "src/utility/storm.h"
+#include "src/parser/DFTGalileoParser.h"
+#include "src/modelchecker/dft/DFTModelChecker.h"
 #include "src/cli/cli.h"
 #include "src/exceptions/BaseException.h"
 #include "src/utility/macros.h"
 #include "src/builder/DftSmtBuilder.h"
-#include <boost/lexical_cast.hpp>
 
 #include "src/settings/modules/GeneralSettings.h"
 #include "src/settings/modules/DFTSettings.h"
@@ -24,6 +24,8 @@
 //#include "src/settings/modules/ParametricSettings.h"
 #include "src/settings/modules/SparseDtmcEliminationModelCheckerSettings.h"
 
+#include <boost/lexical_cast.hpp>
+
 /*!
  * Load DFT from filename, build corresponding Model and check against given property.
  *
@@ -39,10 +41,10 @@ void analyzeDFT(std::string filename, std::string property, bool symred = false,
     std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::parseFormulasForExplicit(property);
     STORM_LOG_ASSERT(formulas.size() == 1, "Wrong number of formulas.");
     
-    DFTAnalyser<ValueType> analyser;
-    analyser.check(dft, formulas[0], symred, allowModularisation, enableDC);
-    analyser.printTimings();
-    analyser.printResult();
+    storm::modelchecker::DFTModelChecker<ValueType> modelChecker;
+    modelChecker.check(dft, formulas[0], symred, allowModularisation, enableDC);
+    modelChecker.printTimings();
+    modelChecker.printResult();
 }
 
 template<typename ValueType>

From d3d360b50a6c216f6a9a903558e91ea52e86326d Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Fri, 30 Sep 2016 17:55:16 +0200
Subject: [PATCH 13/65] First version of DFT approximation

Former-commit-id: 1d95ad491438283366cbcb19bdb0a2c46f95d791
---
 examples/dft/approx.dft                       |   5 +
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 172 ++++++---
 src/builder/ExplicitDFTModelBuilderApprox.h   |  67 +++-
 src/generator/DftNextStateGenerator.cpp       |  83 +++--
 src/generator/DftNextStateGenerator.h         |  23 +-
 src/modelchecker/dft/DFTModelChecker.cpp      | 347 +++++++++++-------
 src/modelchecker/dft/DFTModelChecker.h        |  66 ++--
 src/settings/modules/DFTSettings.cpp          |  18 +-
 src/settings/modules/DFTSettings.h            |  20 +-
 src/storage/dft/DFTState.cpp                  |  10 +-
 src/storage/dft/DFTState.h                    |  17 +
 src/storm-dyftee.cpp                          |  20 +-
 12 files changed, 566 insertions(+), 282 deletions(-)
 create mode 100644 examples/dft/approx.dft

diff --git a/examples/dft/approx.dft b/examples/dft/approx.dft
new file mode 100644
index 000000000..38c7faba0
--- /dev/null
+++ b/examples/dft/approx.dft
@@ -0,0 +1,5 @@
+toplevel "A";
+"A" and "B" "C" "D";
+"B" lambda=0.1 dorm=0;
+"C" lambda=10 dorm=0;
+"D" lambda=0.1 dorm=0;
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 9ff34b734..74c448c25 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -12,28 +12,29 @@
 namespace storm {
     namespace builder {
 
-        template <typename ValueType, typename StateType>
+        template<typename ValueType, typename StateType>
         ExplicitDFTModelBuilderApprox<ValueType, StateType>::ModelComponents::ModelComponents() : transitionMatrix(), stateLabeling(), markovianStates(), exitRates(), choiceLabeling() {
             // Intentionally left empty.
         }
 
-        template <typename ValueType, typename StateType>
+        template<typename ValueType, typename StateType>
         ExplicitDFTModelBuilderApprox<ValueType, StateType>::ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC) : dft(dft), enableDC(enableDC), stateStorage(((dft.stateVectorSize() / 64) + 1) * 64) {
             // stateVectorSize is bound for size of bitvector
-
             stateGenerationInfo = std::make_shared<storm::storage::DFTStateGenerationInfo>(dft.buildStateGenerationInfo(symmetries));
         }
 
-        template <typename ValueType, typename StateType>
-        std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilderApprox<ValueType, StateType>::buildModel(LabelOptions const& labelOpts) {
+        template<typename ValueType, typename StateType>
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::buildModel(LabelOptions const& labelOpts, double approximationError) {
             STORM_LOG_TRACE("Generating DFT state space");
 
             // Initialize
             StateType currentRowGroup = 0;
             StateType currentRow = 0;
+            size_t pseudoStatesToCheck = 0;
             modelComponents.markovianStates = storm::storage::BitVector(INITIAL_BITVECTOR_SIZE);
             // Create generator
             storm::generator::DftNextStateGenerator<ValueType, StateType> generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates);
+            generator.setApproximationError(approximationError);
             // Create sparse matrix builder
             storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !generator.isDeterministicModel(), 0);
 
@@ -87,41 +88,55 @@ namespace storm {
                 // Remember that this row group was actually filled with the transitions of a different state
                 setRemapping(currentState->getId(), currentRowGroup);
 
-                // Explore state
-                generator.load(currentState);
-                storm::generator::StateBehavior<ValueType, StateType> behavior = generator.expand(stateToIdCallback);
-
-                STORM_LOG_ASSERT(!behavior.empty(), "Behavior is empty.");
-                setMarkovian(currentRowGroup, behavior.begin()->isMarkovian());
-
                 // If the model is nondeterministic, we need to open a row group.
                 if (!generator.isDeterministicModel()) {
                     transitionMatrixBuilder.newRowGroup(currentRow);
                 }
 
-                // Now add all choices.
-                for (auto const& choice : behavior) {
-                    // Add the probabilistic behavior to the matrix.
-                    for (auto const& stateProbabilityPair : choice) {
-
-                        // Check that pseudo state and its instantiation do not appear together
-                        // TODO Matthias: prove that this is not possible and remove
-                        if (stateProbabilityPair.first >= OFFSET_PSEUDO_STATE) {
-                            StateType newId = stateProbabilityPair.first - OFFSET_PSEUDO_STATE;
-                            STORM_LOG_ASSERT(newId < mPseudoStatesMapping.size(), "Id is not valid.");
-                            if (mPseudoStatesMapping[newId].first > 0) {
-                                // State exists already
-                                newId = mPseudoStatesMapping[newId].first;
-                                for (auto itFind = choice.begin(); itFind != choice.end(); ++itFind) {
-                                    STORM_LOG_ASSERT(itFind->first != newId, "Pseudo state and instantiation occur together in a distribution.");
+                // Try to explore the next state
+                generator.load(currentState);
+
+                if (currentState->isSkip()) {
+                    // Skip the current state
+                    STORM_LOG_TRACE("Skip expansion of state: " << dft.getStateString(currentState));
+                    setMarkovian(currentRowGroup, true);
+                    // Add transition to target state with temporary value 0
+                    // TODO Matthias: what to do when there is no unique target state?
+                    transitionMatrixBuilder.addNextValue(currentRow, failedStateId, storm::utility::zero<ValueType>());
+                    // Remember skipped state
+                    skippedStates[currentRow] = currentState;
+                    ++currentRow;
+                } else {
+                    // Explore the current state
+                    storm::generator::StateBehavior<ValueType, StateType> behavior = generator.expand(stateToIdCallback);
+                    STORM_LOG_ASSERT(!behavior.empty(), "Behavior is empty.");
+                    setMarkovian(currentRowGroup, behavior.begin()->isMarkovian());
+
+                    // Now add all choices.
+                    for (auto const& choice : behavior) {
+                        // Add the probabilistic behavior to the matrix.
+                        for (auto const& stateProbabilityPair : choice) {
+
+                            // Check that pseudo state and its instantiation do not appear together
+                            // TODO Matthias: prove that this is not possible and remove
+                            if (stateProbabilityPair.first >= OFFSET_PSEUDO_STATE) {
+                                StateType newId = stateProbabilityPair.first - OFFSET_PSEUDO_STATE;
+                                STORM_LOG_ASSERT(newId < mPseudoStatesMapping.size(), "Id is not valid.");
+                                if (mPseudoStatesMapping[newId].first > 0) {
+                                    // State exists already
+                                    newId = mPseudoStatesMapping[newId].first;
+                                    for (auto itFind = choice.begin(); itFind != choice.end(); ++itFind) {
+                                        STORM_LOG_ASSERT(itFind->first != newId, "Pseudo state and instantiation occur together in a distribution.");
+                                    }
                                 }
                             }
-                        }
 
-                        transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second);
+                            transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second);
+                        }
+                        ++currentRow;
                     }
-                    ++currentRow;
                 }
+
                 ++currentRowGroup;
 
                 if (statesToExplore.empty()) {
@@ -149,6 +164,7 @@ namespace storm {
 
             size_t stateSize = stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0);
             modelComponents.markovianStates.resize(stateSize);
+            modelComponents.deterministicModel = generator.isDeterministicModel();
 
             // Replace pseudo states in matrix
             // TODO Matthias: avoid hack with fixed int type
@@ -169,8 +185,8 @@ namespace storm {
 
             STORM_LOG_TRACE("State remapping: " << stateRemapping);
             STORM_LOG_TRACE("Markovian states: " << modelComponents.markovianStates);
-
             STORM_LOG_DEBUG("Generated " << stateSize << " states");
+            STORM_LOG_DEBUG("Skipped " << skippedStates.size() << " states");
             STORM_LOG_DEBUG("Model is " << (generator.isDeterministicModel() ? "deterministic" : "non-deterministic"));
 
             // Build transition matrix
@@ -222,18 +238,42 @@ namespace storm {
                     }
                 }
             }
+        }
 
-            std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
+        template<typename ValueType, typename StateType>
+        std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilderApprox<ValueType, StateType>::getModel() {
+            STORM_LOG_ASSERT(skippedStates.size() == 0, "Concrete model has skipped states");
+            return createModel(false);
+        }
+
+        template<typename ValueType, typename StateType>
+        std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilderApprox<ValueType, StateType>::getModelApproximation(bool lowerBound) {
+            // TODO Matthias: handle case with no skipped states
+            if (lowerBound) {
+                changeMatrixLowerBound(modelComponents.transitionMatrix);
+            } else {
+                changeMatrixUpperBound(modelComponents.transitionMatrix);
+            }
+            return createModel(true);
+        }
 
-            if (generator.isDeterministicModel()) {
+        template<typename ValueType, typename StateType>
+        std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilderApprox<ValueType, StateType>::createModel(bool copy) {
+            if (modelComponents.deterministicModel) {
                 // Build CTMC
-                model = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling));
+                if (copy) {
+                    return std::make_shared<storm::models::sparse::Ctmc<ValueType>>(modelComponents.transitionMatrix, modelComponents.stateLabeling);
+
+                } else {
+                    return std::make_shared<storm::models::sparse::Ctmc<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling));
+                }
             } else {
                 // Build MA
                 // Compute exit rates
-                modelComponents.exitRates = std::vector<ValueType>(stateSize);
+                // TODO Matthias: avoid computing multiple times
+                modelComponents.exitRates = std::vector<ValueType>(modelComponents.markovianStates.size());
                 std::vector<typename storm::storage::SparseMatrix<ValueType>::index_type> indices = modelComponents.transitionMatrix.getRowGroupIndices();
-                for (StateType stateIndex = 0; stateIndex < stateSize; ++stateIndex) {
+                for (StateType stateIndex = 0; stateIndex < modelComponents.markovianStates.size(); ++stateIndex) {
                     if (modelComponents.markovianStates[stateIndex]) {
                         modelComponents.exitRates[stateIndex] = modelComponents.transitionMatrix.getRowSum(indices[stateIndex]);
                     } else {
@@ -242,36 +282,52 @@ namespace storm {
                 }
                 STORM_LOG_TRACE("Exit rates: " << modelComponents.exitRates);
 
-                std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma = std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), std::move(modelComponents.markovianStates), std::move(modelComponents.exitRates));
+                std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma;
+                if (copy) {
+                    ma = std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(modelComponents.transitionMatrix, modelComponents.stateLabeling, modelComponents.markovianStates, modelComponents.exitRates);
+                } else {
+                    ma = std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), std::move(modelComponents.markovianStates), std::move(modelComponents.exitRates));
+                }
                 if (ma->hasOnlyTrivialNondeterminism()) {
                     // Markov automaton can be converted into CTMC
-                    model = ma->convertToCTMC();
+                    return ma->convertToCTMC();
                 } else {
-                    model = ma;
+                    return ma;
                 }
             }
-            
-            return model;
-
         }
-        
-        template<>
-        bool belowThreshold(double const& number) {
-            return number < 0.1;
+
+        template<typename ValueType, typename StateType>
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::changeMatrixLowerBound(storm::storage::SparseMatrix<ValueType> & matrix) const {
+            // Set lower bound for skipped states
+            for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
+                auto matrixEntry = matrix.getRow(it->first).begin();
+                STORM_LOG_ASSERT(matrixEntry->getColumn() == failedStateId, "Transition has wrong target state.");
+                // Get the lower bound by considering the failure of the BE with the highest rate
+                // The list is sorted by rate, therefore we consider the first BE for the highest failure rate
+                matrixEntry->setValue(it->second->getFailableBERate(0));
+            }
         }
 
-        template<>
-        bool belowThreshold(storm::RationalFunction const& number) {
-            storm::RationalFunction threshold = storm::utility::one<storm::RationalFunction>() / 10;
-            std::cout << number << " < " << threshold << ": " << (number < threshold) << std::endl;
-            std::map<storm::Variable, storm::RationalNumber> mapping;
-            
-            storm::RationalFunction eval(number.evaluate(mapping));
-            std::cout << "Evaluated: " << eval << std::endl;
-            return eval < threshold;
+        template<typename ValueType, typename StateType>
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::changeMatrixUpperBound(storm::storage::SparseMatrix<ValueType> & matrix) const {
+            // Set uppper bound for skipped states
+            for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
+                auto matrixEntry = matrix.getRow(it->first).begin();
+                STORM_LOG_ASSERT(matrixEntry->getColumn() == failedStateId, "Transition has wrong target state.");
+                // Get the upper bound by considering the failure of all BEs
+                // The used formula for the rate is 1/( 1/a + 1/b + ...)
+                // TODO Matthias: improve by using closed formula for AND of all BEs
+                ValueType newRate = storm::utility::zero<ValueType>();
+                for (size_t index = 0; index < it->second->nrFailableBEs(); ++index) {
+                    newRate += storm::utility::one<ValueType>() / it->second->getFailableBERate(index);
+                }
+                newRate = storm::utility::one<ValueType>() / newRate;
+                matrixEntry->setValue(newRate);
+            }
         }
 
-        template <typename ValueType, typename StateType>
+        template<typename ValueType, typename StateType>
         StateType ExplicitDFTModelBuilderApprox<ValueType, StateType>::getOrAddStateIndex(DFTStatePointer const& state) {
             StateType stateId;
             bool changed = false;
@@ -329,7 +385,7 @@ namespace storm {
             return stateId;
         }
 
-        template <typename ValueType, typename StateType>
+        template<typename ValueType, typename StateType>
         void ExplicitDFTModelBuilderApprox<ValueType, StateType>::setMarkovian(StateType id, bool markovian) {
             if (id >= modelComponents.markovianStates.size()) {
                 // Resize BitVector
@@ -338,7 +394,7 @@ namespace storm {
             modelComponents.markovianStates.set(id, markovian);
         }
 
-        template <typename ValueType, typename StateType>
+        template<typename ValueType, typename StateType>
         void ExplicitDFTModelBuilderApprox<ValueType, StateType>::setRemapping(StateType id, StateType mappedId) {
             STORM_LOG_ASSERT(id < stateRemapping.size(), "Invalid index for remapping.");
             stateRemapping[id] = mappedId;
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index 247b66ca1..fa529f221 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -48,6 +48,9 @@ namespace storm {
 
                 // A vector that stores a labeling for each choice.
                 boost::optional<std::vector<boost::container::flat_set<StateType>>> choiceLabeling;
+
+                // A flag indicating if the model is deterministic.
+                bool deterministicModel;
             };
 
         public:
@@ -68,13 +71,28 @@ namespace storm {
             ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC);
 
             /*!
-             * Build model from Dft.
+             * Build model from DFT.
              *
-             * @param labelOpts Options for labeling.
+             * @param labelOpts          Options for labeling.
+             * @param approximationError Error allowed for approximation.
+             */
+            void buildModel(LabelOptions const& labelOpts, double approximationError = 0.0);
+
+            /*!
+             * Get the built model.
              *
-             * @return Built model (either MA or CTMC).
+             * @return The model built from the DFT.
              */
-            std::shared_ptr<storm::models::sparse::Model<ValueType>> buildModel(LabelOptions const& labelOpts);
+            std::shared_ptr<storm::models::sparse::Model<ValueType>> getModel();
+
+            /*!
+             * Get the built approximation model for either the lower or upper bound.
+             *
+             * @param lowerBound If true, the lower bound model is returned, else the upper bound model
+             *
+             * @return The model built from the DFT.
+             */
+            std::shared_ptr<storm::models::sparse::Model<ValueType>> getModelApproximation(bool lowerBound = true);
 
         private:
 
@@ -103,6 +121,31 @@ namespace storm {
              */
             void setRemapping(StateType id, StateType mappedId);
 
+            /**
+             * Change matrix to reflect the lower approximation bound.
+             *
+             * @param matrix Matrix to change. The change are reflected here.
+             */
+            void changeMatrixLowerBound(storm::storage::SparseMatrix<ValueType> & matrix) const;
+
+            /*!
+             * Change matrix to reflect the upper approximation bound.
+             *
+             * @param matrix Matrix to change. The change are reflected here.
+             */
+            void changeMatrixUpperBound(storm::storage::SparseMatrix<ValueType> & matrix) const;
+
+            /*!
+             * Create the model model from the model components.
+             *
+             * @param copy If true, all elements of the model component are copied (used for approximation). If false
+             *             they are moved to reduce the memory overhead.
+             *
+             * @return The model built from the model components.
+             */
+            std::shared_ptr<storm::models::sparse::Model<ValueType>> createModel(bool copy);
+
+
             // Initial size of the bitvector.
             const size_t INITIAL_BITVECTOR_SIZE = 20000;
             // Offset used for pseudo states.
@@ -118,13 +161,17 @@ namespace storm {
             // Current id for new state
             size_t newIndex = 0;
 
-            //TODO Matthias: remove when everything works
-            std::vector<std::pair<StateType, storm::storage::BitVector>> mPseudoStatesMapping; // vector of (id to concrete state, bitvector)
+            // Mapping from pseudo states to (id of concrete state, bitvector)
+            std::vector<std::pair<StateType, storm::storage::BitVector>> mPseudoStatesMapping;
+
             //TODO Matthias: make changeable
             const bool mergeFailedStates = true;
+
+            // Id of failed state
             size_t failedStateId = 0;
+
+            // Id of initial state
             size_t initialStateIndex = 0;
-            size_t pseudoStatesToCheck = 0;
 
             // Flag indication if dont care propagation should be used.
             bool enableDC = true;
@@ -142,10 +189,10 @@ namespace storm {
             // TODO Matthias: avoid hack with fixed int type
             std::vector<uint_fast64_t> stateRemapping;
 
+            // Holds all skipped states which were not yet expanded. More concrete it is a mapping from matrix indices
+            // to the corresponding skipped state.
+            std::unordered_map<StateType, DFTStatePointer> skippedStates;
         };
-        
-        template<typename ValueType>
-        bool belowThreshold(ValueType const& number);
     }
 }
 
diff --git a/src/generator/DftNextStateGenerator.cpp b/src/generator/DftNextStateGenerator.cpp
index 1f39fe2cf..f468c673e 100644
--- a/src/generator/DftNextStateGenerator.cpp
+++ b/src/generator/DftNextStateGenerator.cpp
@@ -8,7 +8,7 @@ namespace storm {
     namespace generator {
         
         template<typename ValueType, typename StateType>
-        DftNextStateGenerator<ValueType, StateType>::DftNextStateGenerator(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, bool enableDC, bool mergeFailedStates) : mDft(dft), mStateGenerationInfo(stateGenerationInfo), state(nullptr), enableDC(enableDC), mergeFailedStates(mergeFailedStates), comparator() {
+        DftNextStateGenerator<ValueType, StateType>::DftNextStateGenerator(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, bool enableDC, bool mergeFailedStates) : mDft(dft), mStateGenerationInfo(stateGenerationInfo), state(nullptr), enableDC(enableDC), mergeFailedStates(mergeFailedStates) {
             deterministicModel = !mDft.canHaveNondeterminism();
         }
         
@@ -60,7 +60,7 @@ namespace storm {
             Choice<ValueType, StateType> choice(0, !hasDependencies);
 
             // Check for absorbing state
-            if (mDft.hasFailed(state) || mDft.isFailsafe(state) || state->nrFailableBEs() == 0) {
+            if (mDft.hasFailed(state) || mDft.isFailsafe(state) || failableCount == 0) {
                 // Add self loop
                 choice.addProbability(state->getId(), storm::utility::one<ValueType>());
                 STORM_LOG_TRACE("Added self loop for " << state->getId());
@@ -82,30 +82,6 @@ namespace storm {
                 STORM_LOG_ASSERT(nextBEPair.second == hasDependencies, "Failure due to dependencies does not match.");
                 STORM_LOG_TRACE("With the failure of: " << nextBE->name() << " [" << nextBE->id() << "] in " << mDft.getStateString(state));
 
-                /*if (storm::settings::getModule<storm::settings::modules::DFTSettings>().computeApproximation()) {
-                    if (!storm::utility::isZero(exitRate)) {
-                        ValueType rate = nextBE->activeFailureRate();
-                        ValueType div = rate / exitRate;
-                        if (!storm::utility::isZero(exitRate) && belowThreshold(div)) {
-                            // Set transition directly to failed state
-                            auto resultFind = outgoingRates.find(failedIndex);
-                            if (resultFind != outgoingRates.end()) {
-                                // Add to existing transition
-                                resultFind->second += rate;
-                                STORM_LOG_TRACE("Updated transition to " << resultFind->first << " with rate " << rate << " to new rate " << resultFind->second);
-                            } else {
-                                // Insert new transition
-                                outgoingRates.insert(std::make_pair(failedIndex, rate));
-                                STORM_LOG_TRACE("Added transition to " << failedIndex << " with rate " << rate);
-                            }
-                            exitRate += rate;
-                            std::cout << "IGNORE: " << nextBE->name() << " [" << nextBE->id() << "] with rate " << rate << std::endl;
-                            //STORM_LOG_TRACE("Ignore: " << nextBE->name() << " [" << nextBE->id() << "] with rate " << rate);
-                            continue;
-                        }
-                    }
-                }*/
-
                 // Propagate
                 storm::storage::DFTStateSpaceGenerationQueues<ValueType> queues;
 
@@ -139,8 +115,8 @@ namespace storm {
                     continue;
                 }
 
+                // Get the id of the successor state
                 StateType newStateId;
-
                 if (newState->hasFailed(mDft.getTopLevelIndex()) && mergeFailedStates) {
                     // Use unique failed state
                     newStateId = mergeFailedStateId;
@@ -168,17 +144,17 @@ namespace storm {
                 // Set transitions
                 if (hasDependencies) {
                     // Failure is due to dependency -> add non-deterministic choice
-                    std::shared_ptr<storm::storage::DFTDependency<ValueType> const> dependency = mDft.getDependency(state->getDependencyId(currentFailable));
-                    choice.addProbability(newStateId, dependency->probability());
-                    STORM_LOG_TRACE("Added transition to " << newStateId << " with probability " << dependency->probability());
+                    ValueType probability = mDft.getDependency(state->getDependencyId(currentFailable))->probability();
+                    choice.addProbability(newStateId, probability);
+                    STORM_LOG_TRACE("Added transition to " << newStateId << " with probability " << probability);
 
-                    if (!storm::utility::isOne(dependency->probability())) {
+                    if (!storm::utility::isOne(probability)) {
                         // Add transition to state where dependency was unsuccessful
                         DFTStatePointer unsuccessfulState = std::make_shared<storm::storage::DFTState<ValueType>>(*state);
                         unsuccessfulState->letDependencyBeUnsuccessful(currentFailable);
                         // Add state
                         StateType unsuccessfulStateId = stateToIdCallback(unsuccessfulState);
-                        ValueType remainingProbability = storm::utility::one<ValueType>() - dependency->probability();
+                        ValueType remainingProbability = storm::utility::one<ValueType>() - probability;
                         choice.addProbability(unsuccessfulStateId, remainingProbability);
                         STORM_LOG_TRACE("Added transition to " << unsuccessfulStateId << " with remaining probability " << remainingProbability);
                     }
@@ -188,14 +164,21 @@ namespace storm {
                     // Set failure rate according to activation
                     bool isActive = true;
                     if (mDft.hasRepresentant(nextBE->id())) {
-                        // Active must be checked for the state we are coming from as this state is responsible for the
-                        // rate and not the new state we are going to
+                        // Active must be checked for the state we are coming from as this state is responsible for the rate
                         isActive = state->isActive(mDft.getRepresentant(nextBE->id())->id());
                     }
                     ValueType rate = isActive ? nextBE->activeFailureRate() : nextBE->passiveFailureRate();
                     STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Rate is 0.");
                     choice.addProbability(newStateId, rate);
-                    STORM_LOG_TRACE("Added transition to " << newStateId << " with " << (isActive ? "active" : "passive") << " rate " << rate);
+                    STORM_LOG_TRACE("Added transition to " << newStateId << " with " << (isActive ? "active" : "passive") << " failure rate " << rate);
+
+                    // Check if new state needs expansion for approximation
+                    if (approximationError > 0.0) {
+                        if (checkSkipState(newState, rate, choice.getTotalMass(), approximationError)) {
+                            STORM_LOG_TRACE("Will skip state " << newStateId);
+                            newState->markSkip();
+                        }
+                    }
                 }
 
                 ++currentFailable;
@@ -229,6 +212,36 @@ namespace storm {
             result.setExpanded();
             return result;
         }
+
+        template<typename ValueType, typename StateType>
+        void DftNextStateGenerator<ValueType, StateType>::setApproximationError(double approximationError) {
+            this->approximationError = approximationError;
+        }
+
+        template<typename ValueType, typename StateType>
+        bool DftNextStateGenerator<ValueType, StateType>::checkSkipState(DFTStatePointer const& state, ValueType rate, ValueType exitRate, double approximationError) {
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Approximation works only for double.");
+        }
+
+        template<>
+        bool DftNextStateGenerator<double>::checkSkipState(DFTStatePointer const& state, double rate, double exitRate, double approximationError) {
+            if (mDft.hasFailed(state) || mDft.isFailsafe(state) ||  (state->nrFailableDependencies() == 0 && state->nrFailableBEs() == 0)) {
+                // Do not skip absorbing state
+                return false;
+            }
+            // Skip if the rate to reach this state is low compared to all other outgoing rates from the predecessor
+            return rate/exitRate < approximationError;
+        }
+
+        template<>
+        bool DftNextStateGenerator<storm::RationalFunction>::checkSkipState(DFTStatePointer const& state, storm::RationalFunction rate, storm::RationalFunction exitRate, double approximationError) {
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Approximation works only for double.");
+            /*std::cout << (rate / exitRate) << " < " << threshold << ": " << (number < threshold) << std::endl;
+            std::map<storm::Variable, storm::RationalNumber> mapping;
+            storm::RationalFunction eval(number.evaluate(mapping));
+            std::cout << "Evaluated: " << eval << std::endl;
+            return eval < threshold;*/
+        }
         
         template class DftNextStateGenerator<double>;
         template class DftNextStateGenerator<storm::RationalFunction>;
diff --git a/src/generator/DftNextStateGenerator.h b/src/generator/DftNextStateGenerator.h
index beab8f5f0..7c9e1bb48 100644
--- a/src/generator/DftNextStateGenerator.h
+++ b/src/generator/DftNextStateGenerator.h
@@ -42,6 +42,13 @@ namespace storm {
              */
             StateBehavior<ValueType, StateType> createMergeFailedState(StateToIdCallback const& stateToIdCallback);
 
+            /*!
+             * Set a new value for the allowed approximation error.
+             *
+             * @param approximationError Allowed approximation error.
+             */
+            void setApproximationError(double approximationError);
+
         private:
             
             // The dft used for the generation of next states.
@@ -65,8 +72,20 @@ namespace storm {
             // Flag indicating if the model is deterministic.
             bool deterministicModel = true;
 
-            // A comparator used to compare constants.
-            storm::utility::ConstantsComparator<ValueType> comparator;
+            // Allowed approximation error.
+            double approximationError = 0.0;
+
+            /*!
+             * Check if the given state should be skipped for expansion.
+             *
+             * @param state              State to check for expansion
+             * @param rate               Rate of current state
+             * @param exitRate           Exit rates of all outgoing transitions
+             * @param approximationError Allowed approximation error
+             *
+             * @return True, if the given state should be skipped.
+             */
+            bool checkSkipState(DFTStatePointer const& state, ValueType rate, ValueType exitRate, double approximationError);
         };
         
     }
diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index 3aa3ed27b..1c0772bf8 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -11,158 +11,213 @@ namespace storm {
 
         template<typename ValueType>
         DFTModelChecker<ValueType>::DFTModelChecker() {
-            // Intentionally left empty.
+            checkResult = storm::utility::zero<ValueType>();
         }
 
         template<typename ValueType>
-        void DFTModelChecker<ValueType>::check(storm::storage::DFT<ValueType> const& origDft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool allowModularisation, bool enableDC) {
+        void DFTModelChecker<ValueType>::check(storm::storage::DFT<ValueType> const& origDft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool allowModularisation, bool enableDC, double approximationError) {
+            // Initialize
+            this->buildingTime = std::chrono::duration<double>::zero();
+            this->explorationTime = std::chrono::duration<double>::zero();
+            this->bisimulationTime = std::chrono::duration<double>::zero();
+            this->modelCheckingTime = std::chrono::duration<double>::zero();
+            this->totalTime = std::chrono::duration<double>::zero();
+            this->approximationError = approximationError;
             std::chrono::high_resolution_clock::time_point totalStart = std::chrono::high_resolution_clock::now();
+
             // Optimizing DFT
             storm::storage::DFT<ValueType> dft = origDft.optimize();
-            checkResult = checkHelper(dft, formula, symred, allowModularisation, enableDC);
-            totalTime = std::chrono::high_resolution_clock::now() - totalStart;
+
+            // TODO Matthias: check that all paths reach the target state!
+
+            // Checking DFT
+            checkResult = checkHelper(dft, formula, symred, allowModularisation, enableDC, approximationError);
+            this->totalTime = std::chrono::high_resolution_clock::now() - totalStart;
         }
 
         template<typename ValueType>
-        ValueType DFTModelChecker<ValueType>::checkHelper(storm::storage::DFT<ValueType> const& dft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool allowModularisation, bool enableDC)  {
+        typename DFTModelChecker<ValueType>::dft_result DFTModelChecker<ValueType>::checkHelper(storm::storage::DFT<ValueType> const& dft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool allowModularisation, bool enableDC, double approximationError)  {
             STORM_LOG_TRACE("Check helper called");
-            bool invResults = false;
-            std::vector<storm::storage::DFT<ValueType>> dfts = {dft};
-            std::vector<ValueType> res;
-            size_t nrK = 0; // K out of M
-            size_t nrM = 0; // K out of M
+            bool modularisationPossible = allowModularisation;
 
             // Try modularisation
-            if(allowModularisation) {
-                if(dft.topLevelType() == storm::storage::DFTElementType::AND) {
-                    STORM_LOG_TRACE("top modularisation called AND");
-                    dfts = dft.topModularisation();
-                    STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
-                    nrK = dfts.size();
-                    nrM = dfts.size();
-                }
-                if(dft.topLevelType() == storm::storage::DFTElementType::OR) {
-                    STORM_LOG_TRACE("top modularisation called OR");
-                    dfts = dft.topModularisation();
-                    STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
-                    nrK = 0;
-                    nrM = dfts.size();
-                    invResults = true;
-                }
-                if(dft.topLevelType() == storm::storage::DFTElementType::VOT) {
-                    STORM_LOG_TRACE("top modularisation called VOT");
-                    dfts = dft.topModularisation();
-                    STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
-                    nrK = std::static_pointer_cast<storm::storage::DFTVot<ValueType> const>(dft.getTopLevelGate())->threshold();
-                    nrM = dfts.size();
-                    if(nrK <= nrM/2) {
-                        nrK -= 1;
+            if(modularisationPossible) {
+                bool invResults = false;
+                std::vector<storm::storage::DFT<ValueType>> dfts;
+                size_t nrK = 0; // K out of M
+                size_t nrM = 0; // K out of M
+
+                switch (dft.topLevelType()) {
+                    case storm::storage::DFTElementType::AND:
+                        STORM_LOG_TRACE("top modularisation called AND");
+                        dfts = dft.topModularisation();
+                        STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
+                        nrK = dfts.size();
+                        nrM = dfts.size();
+                        modularisationPossible = dfts.size() > 1;
+                        break;
+                    case storm::storage::DFTElementType::OR:
+                        STORM_LOG_TRACE("top modularisation called OR");
+                        dfts = dft.topModularisation();
+                        STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
+                        nrK = 0;
+                        nrM = dfts.size();
                         invResults = true;
-                    }
+                        modularisationPossible = dfts.size() > 1;
+                        break;
+                    case storm::storage::DFTElementType::VOT:
+                        STORM_LOG_TRACE("top modularisation called VOT");
+                        dfts = dft.topModularisation();
+                        STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
+                        nrK = std::static_pointer_cast<storm::storage::DFTVot<ValueType> const>(dft.getTopLevelGate())->threshold();
+                        nrM = dfts.size();
+                        if(nrK <= nrM/2) {
+                            nrK -= 1;
+                            invResults = true;
+                        }
+                        modularisationPossible = dfts.size() > 1;
+                        break;
+                    default:
+                        // No static gate -> no modularisation applicable
+                        modularisationPossible = false;
+                        break;
                 }
-                if(dfts.size() > 1) {
+
+                if(modularisationPossible) {
                     STORM_LOG_TRACE("Recursive CHECK Call");
+                    // TODO Matthias: enable modularisation for approximation
+                    STORM_LOG_ASSERT(approximationError == 0.0, "Modularisation not possible for approximation.");
+
+                    // Recursively call model checking
+                    std::vector<ValueType> res;
                     for(auto const ft : dfts) {
-                        res.push_back(checkHelper(ft, formula, symred, allowModularisation, enableDC));
+                        dft_result ftResult = checkHelper(ft, formula, symred, true, enableDC, 0.0);
+                        res.push_back(boost::get<ValueType>(ftResult));
                     }
-                }
-            }
 
-            if(res.empty()) {
-                // Model based modularisation.
-                auto const& models = buildMarkovModels(dfts, formula, symred, enableDC);
-                
-                for (auto const& model : models) {
-                    // Model checking
-                    STORM_LOG_INFO("Model checking...");
-                    std::chrono::high_resolution_clock::time_point modelCheckingStart = std::chrono::high_resolution_clock::now();
-                    std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySparseModel(model, formula));
-                    STORM_LOG_INFO("Model checking done.");
-                    STORM_LOG_ASSERT(result, "Result does not exist.");
-                    result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
-                    modelCheckingTime += std::chrono::high_resolution_clock::now() -  modelCheckingStart;
-                    res.push_back(result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second);
+                    // Combine modularisation results
+                    STORM_LOG_TRACE("Combining all results... K=" << nrK << "; M=" << nrM << "; invResults=" << (invResults?"On":"Off"));
+                    ValueType result = storm::utility::zero<ValueType>();
+                    int limK = invResults ? -1 : nrM+1;
+                    int chK = invResults ? -1 : 1;
+                    for(int cK = nrK; cK != limK; cK += chK ) {
+                        STORM_LOG_ASSERT(cK >= 0, "ck negative.");
+                        size_t permutation = smallestIntWithNBitsSet(static_cast<size_t>(cK));
+                        do {
+                            STORM_LOG_TRACE("Permutation="<<permutation);
+                            ValueType permResult = storm::utility::one<ValueType>();
+                            for(size_t i = 0; i < res.size(); ++i) {
+                                if(permutation & (1 << i)) {
+                                    permResult *= res[i];
+                                } else {
+                                    permResult *= storm::utility::one<ValueType>() - res[i];
+                                }
+                            }
+                            STORM_LOG_TRACE("Result for permutation:"<<permResult);
+                            permutation = nextBitPermutation(permutation);
+                            result += permResult;
+                        } while(permutation < (1 << nrM) && permutation != 0);
+                    }
+                    if(invResults) {
+                        result = storm::utility::one<ValueType>() - result;
+                    }
+                    return result;
                 }
             }
-            if(nrM <= 1) {
-                // No modularisation done.
-                STORM_LOG_ASSERT(res.size()==1, "Result size not 1.");
-                return res[0];
-            }
 
-            STORM_LOG_TRACE("Combining all results... K=" << nrK << "; M=" << nrM << "; invResults=" << (invResults?"On":"Off"));
-            ValueType result = storm::utility::zero<ValueType>();
-            int limK = invResults ? -1 : nrM+1;
-            int chK = invResults ? -1 : 1;
-            for(int cK = nrK; cK != limK; cK += chK ) {
-                STORM_LOG_ASSERT(cK >= 0, "ck negative.");
-                size_t permutation = smallestIntWithNBitsSet(static_cast<size_t>(cK));
-                do {
-                    STORM_LOG_TRACE("Permutation="<<permutation);
-                    ValueType permResult = storm::utility::one<ValueType>();
-                    for(size_t i = 0; i < res.size(); ++i) {
-                        if(permutation & (1 << i)) {
-                            permResult *= res[i];
-                        } else {
-                            permResult *= storm::utility::one<ValueType>() - res[i];
-                        }
-                    }
-                    STORM_LOG_TRACE("Result for permutation:"<<permResult);
-                    permutation = nextBitPermutation(permutation);
-                    result += permResult;
-                } while(permutation < (1 << nrM) && permutation != 0);
-            }
-            if(invResults) {
-                return storm::utility::one<ValueType>() - result;
-            }
-            return result;
+            // If we are here, no modularisation was possible
+            STORM_LOG_ASSERT(!modularisationPossible, "Modularisation should not be possible.");
+            return checkDFT(dft, formula, symred, enableDC, approximationError);
         }
 
         template<typename ValueType>
-        std::vector<ValueType> DFTModelChecker<ValueType>::checkModel(std::vector<storm::storage::DFT<ValueType>> const& dfts, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool enableDC, double approximationError) {
-            std::vector<ValueType> results;
+        typename DFTModelChecker<ValueType>::dft_result DFTModelChecker<ValueType>::checkDFT(storm::storage::DFT<ValueType> const& dft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool enableDC, double approximationError) {
+            std::chrono::high_resolution_clock::time_point buildingStart = std::chrono::high_resolution_clock::now();
 
-            auto const& models = buildMarkovModels(dfts, formula, symred, enableDC);
-
-            for (auto const& model : models) {
-                // Model checking
-                STORM_LOG_INFO("Model checking...");
-                std::chrono::high_resolution_clock::time_point modelCheckingStart = std::chrono::high_resolution_clock::now();
-                std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySparseModel(model, formula));
-                STORM_LOG_INFO("Model checking done.");
-                STORM_LOG_ASSERT(result, "Result does not exist.");
-                result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
-                modelCheckingTime += std::chrono::high_resolution_clock::now() -  modelCheckingStart;
-                results.push_back(result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second);
+            // Find symmetries
+            std::map<size_t, std::vector<std::vector<size_t>>> emptySymmetry;
+            storm::storage::DFTIndependentSymmetries symmetries(emptySymmetry);
+            if(symred) {
+                auto colouring = dft.colourDFT();
+                symmetries = dft.findSymmetries(colouring);
+                STORM_LOG_INFO("Found " << symmetries.groups.size() << " symmetries.");
+                STORM_LOG_TRACE("Symmetries: " << std::endl << symmetries);
             }
-            return results;
-        }
+            std::chrono::high_resolution_clock::time_point buildingEnd = std::chrono::high_resolution_clock::now();
+            buildingTime += buildingEnd - buildingStart;
 
-        template<typename ValueType>
-        std::vector<std::shared_ptr<storm::models::sparse::Model<ValueType>>> DFTModelChecker<ValueType>::buildMarkovModels(std::vector<storm::storage::DFT<ValueType>> const& dfts, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool enableDC, double approximationError) {
-            std::vector<std::shared_ptr<storm::models::sparse::Model<ValueType>>> models;
-            for(auto& dft : dfts) {
-                std::chrono::high_resolution_clock::time_point buildingStart = std::chrono::high_resolution_clock::now();
-
-                std::map<size_t, std::vector<std::vector<size_t>>> emptySymmetry;
-                storm::storage::DFTIndependentSymmetries symmetries(emptySymmetry);
-                if(symred) {
-                    auto colouring = dft.colourDFT();
-                    symmetries = dft.findSymmetries(colouring);
-                    STORM_LOG_INFO("Found " << symmetries.groups.size() << " symmetries.");
-                    STORM_LOG_TRACE("Symmetries: " << std::endl << symmetries);
-                }
-                std::chrono::high_resolution_clock::time_point buildingEnd = std::chrono::high_resolution_clock::now();
-                buildingTime += buildingEnd - buildingStart;
+            if (approximationError > 0.0) {
+                // Build approximate Markov Automata for lower and upper bound
+                double currentApproximationError = approximationError;
+                approximation_result approxResult = std::make_pair(storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>());
+                std::chrono::high_resolution_clock::time_point explorationStart;
+                std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
+                storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
+                typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
 
-                // Building Markov Automaton
+                size_t iteration = 0;
+                do {
+                    // Iteratively build finer models
+                    // TODO Matthias: implement refinement
+                    STORM_LOG_ASSERT(iteration < 1, "Iterative refinement not yet implemented.");
+                    explorationStart = std::chrono::high_resolution_clock::now();
+                    STORM_LOG_INFO("Building model...");
+                    // TODO Matthias refine model using existing model and MC results
+                    currentApproximationError = pow(0.1, iteration) * approximationError;
+                    builder.buildModel(labeloptions, currentApproximationError);
+                    // TODO Matthias: possible to do bisimulation on approximated model and not on concrete one?
+
+                    // Build model for lower bound
+                    STORM_LOG_INFO("Getting model for lower bound...");
+                    model = builder.getModelApproximation(true);
+                    //model->printModelInformationToStream(std::cout);
+                    STORM_LOG_INFO("No. states (Explored): " << model->getNumberOfStates());
+                    STORM_LOG_INFO("No. transitions (Explored): " << model->getNumberOfTransitions());
+                    if (model->getNumberOfStates() <= 15) {
+                        STORM_LOG_TRACE("Transition matrix: " << std::endl << model->getTransitionMatrix());
+                    } else {
+                        STORM_LOG_TRACE("Transition matrix: too big to print");
+                    }
+                    explorationTime += std::chrono::high_resolution_clock::now() - explorationStart;
+                    // Check lower bound
+                    std::unique_ptr<storm::modelchecker::CheckResult> result = checkModel(model, formula);
+                    result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
+                    approxResult.first = result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second;
+
+                    // Build model for upper bound
+                    STORM_LOG_INFO("Getting model for upper bound...");
+                    explorationStart = std::chrono::high_resolution_clock::now();
+                    model = builder.getModelApproximation(false);
+                    //model->printModelInformationToStream(std::cout);
+                    STORM_LOG_INFO("No. states (Explored): " << model->getNumberOfStates());
+                    STORM_LOG_INFO("No. transitions (Explored): " << model->getNumberOfTransitions());
+                    if (model->getNumberOfStates() <= 15) {
+                        STORM_LOG_TRACE("Transition matrix: " << std::endl << model->getTransitionMatrix());
+                    } else {
+                        STORM_LOG_TRACE("Transition matrix: too big to print");
+                    }
+                    explorationTime += std::chrono::high_resolution_clock::now() - explorationStart;
+                    // Check upper bound
+                    result = checkModel(model, formula);
+                    result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
+                    approxResult.second = result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second;
+
+                    ++iteration;
+                    STORM_LOG_TRACE("Result after iteration " << iteration << ": (" << approxResult.first << ", " << approxResult.second << ")");
+                } while (!isApproximationSufficient(approxResult.first, approxResult.second, approximationError));
+
+                STORM_LOG_INFO("Finished approximation after " << iteration << " iteration" << (iteration > 1 ? "s." : "."));
+                return approxResult;
+            } else {
+                // Build a single Markov Automaton
                 STORM_LOG_INFO("Building Model...");
                 std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
                 // TODO Matthias: use only one builder if everything works again
-                if (storm::settings::getModule<storm::settings::modules::DFTSettings>().computeApproximation()) {
+                if (approximationError >= 0.0) {
                     storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
                     typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
-                    model = builder.buildModel(labeloptions);
+                    builder.buildModel(labeloptions);
+                    model = builder.getModel();
                 } else {
                     storm::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries, enableDC);
                     typename storm::builder::ExplicitDFTModelBuilder<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
@@ -171,21 +226,45 @@ namespace storm {
                 //model->printModelInformationToStream(std::cout);
                 STORM_LOG_INFO("No. states (Explored): " << model->getNumberOfStates());
                 STORM_LOG_INFO("No. transitions (Explored): " << model->getNumberOfTransitions());
-                std::chrono::high_resolution_clock::time_point explorationEnd = std::chrono::high_resolution_clock::now();
-                explorationTime += explorationEnd -buildingEnd;
+                explorationTime += std::chrono::high_resolution_clock::now() - buildingEnd;
 
-                // Bisimulation
-                if (model->isOfType(storm::models::ModelType::Ctmc) && storm::settings::getModule<storm::settings::modules::GeneralSettings>().isBisimulationSet()) {
-                    STORM_LOG_INFO("Bisimulation...");
-                    model =  storm::performDeterministicSparseBisimulationMinimization<storm::models::sparse::Ctmc<ValueType>>(model->template as<storm::models::sparse::Ctmc<ValueType>>(), {formula}, storm::storage::BisimulationType::Weak)->template as<storm::models::sparse::Ctmc<ValueType>>();
-                    //model->printModelInformationToStream(std::cout);
-                }
+                // Model checking
+                std::unique_ptr<storm::modelchecker::CheckResult> result = checkModel(model, formula);
+                result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
+                return result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second;
+            }
+        }
+
+        template<typename ValueType>
+        std::unique_ptr<storm::modelchecker::CheckResult> DFTModelChecker<ValueType>::checkModel(std::shared_ptr<storm::models::sparse::Model<ValueType>>& model, std::shared_ptr<const storm::logic::Formula> const& formula) {
+            // Bisimulation
+            std::chrono::high_resolution_clock::time_point bisimulationStart = std::chrono::high_resolution_clock::now();
+            if (model->isOfType(storm::models::ModelType::Ctmc) && storm::settings::getModule<storm::settings::modules::GeneralSettings>().isBisimulationSet()) {
+                STORM_LOG_INFO("Bisimulation...");
+                model =  storm::performDeterministicSparseBisimulationMinimization<storm::models::sparse::Ctmc<ValueType>>(model->template as<storm::models::sparse::Ctmc<ValueType>>(), {formula}, storm::storage::BisimulationType::Weak)->template as<storm::models::sparse::Ctmc<ValueType>>();
                 STORM_LOG_INFO("No. states (Bisimulation): " << model->getNumberOfStates());
                 STORM_LOG_INFO("No. transitions (Bisimulation): " << model->getNumberOfTransitions());
-                bisimulationTime += std::chrono::high_resolution_clock::now() - explorationEnd;
-                models.push_back(model);
             }
-            return models;
+            std::chrono::high_resolution_clock::time_point bisimulationEnd = std::chrono::high_resolution_clock::now();
+            bisimulationTime += bisimulationEnd - bisimulationStart;
+
+            // Check the model
+            STORM_LOG_INFO("Model checking...");
+            std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySparseModel(model, formula));
+            STORM_LOG_INFO("Model checking done.");
+            STORM_LOG_ASSERT(result, "Result does not exist.");
+            modelCheckingTime += std::chrono::high_resolution_clock::now() - bisimulationEnd;
+            return result;
+        }
+
+        template<typename ValueType>
+        bool DFTModelChecker<ValueType>::isApproximationSufficient(ValueType lowerBound, ValueType upperBound, double approximationError) {
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Approximation works only for double.");
+        }
+
+        template<>
+        bool DFTModelChecker<double>::isApproximationSufficient(double lowerBound, double upperBound, double approximationError) {
+            return upperBound - lowerBound <= approximationError;
         }
 
         template<typename ValueType>
@@ -201,7 +280,13 @@ namespace storm {
         template<typename ValueType>
         void DFTModelChecker<ValueType>::printResult(std::ostream& os) {
             os << "Result: [";
-            os << checkResult << "]" << std::endl;
+            if (this->approximationError > 0.0) {
+                approximation_result result = boost::get<approximation_result>(checkResult);
+                os << "(" << result.first << ", " << result.second << ")";
+            } else {
+                os << boost::get<ValueType>(checkResult);
+            }
+            os << "]" << std::endl;
         }
 
 
diff --git a/src/modelchecker/dft/DFTModelChecker.h b/src/modelchecker/dft/DFTModelChecker.h
index 0867ed094..62bb5afe4 100644
--- a/src/modelchecker/dft/DFTModelChecker.h
+++ b/src/modelchecker/dft/DFTModelChecker.h
@@ -11,20 +11,23 @@
 namespace storm {
     namespace modelchecker {
 
-        /**
+        /*!
          * Analyser for DFTs.
          */
         template<typename ValueType>
         class DFTModelChecker {
 
+            typedef std::pair<ValueType, ValueType> approximation_result;
+            typedef boost::variant<ValueType, approximation_result> dft_result;
+
         public:
 
-            /**
+            /*!
              * Constructor.
              */
             DFTModelChecker();
 
-            /**
+            /*!
              * Main method for checking DFTs.
              *
              * @param origDft             Original DFT
@@ -32,17 +35,18 @@ namespace storm {
              * @param symred              Flag indicating if symmetry reduction should be used
              * @param allowModularisation Flag indication if modularisation is allowed
              * @param enableDC            Flag indicating if dont care propagation should be used
+             * @param approximationError  Error allowed for approximation. Value 0 indicates no approximation
              */
-            void check(storm::storage::DFT<ValueType> const& origDft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred = true, bool allowModularisation = true, bool enableDC = true);
+            void check(storm::storage::DFT<ValueType> const& origDft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred = true, bool allowModularisation = true, bool enableDC = true, double approximationError = 0.0);
 
-            /**
+            /*!
              * Print timings of all operations to stream.
              *
              * @param os Output stream to write to.
              */
             void printTimings(std::ostream& os = std::cout);
 
-            /**
+            /*!
              * Print result to stream.
              *
              * @param os Output stream to write to.
@@ -50,16 +54,21 @@ namespace storm {
             void printResult(std::ostream& os = std::cout);
 
         private:
+
             // Timing values
             std::chrono::duration<double> buildingTime = std::chrono::duration<double>::zero();
             std::chrono::duration<double> explorationTime = std::chrono::duration<double>::zero();
             std::chrono::duration<double> bisimulationTime = std::chrono::duration<double>::zero();
             std::chrono::duration<double> modelCheckingTime = std::chrono::duration<double>::zero();
             std::chrono::duration<double> totalTime = std::chrono::duration<double>::zero();
+
             // Model checking result
-            ValueType checkResult = storm::utility::zero<ValueType>();
+            dft_result checkResult;
+
+            // Allowed error bound for approximation
+            double approximationError;
 
-            /**
+            /*!
              * Internal helper for model checking a DFT.
              *
              * @param dft                 DFT
@@ -67,36 +76,45 @@ namespace storm {
              * @param symred              Flag indicating if symmetry reduction should be used
              * @param allowModularisation Flag indication if modularisation is allowed
              * @param enableDC            Flag indicating if dont care propagation should be used
+             * @param approximationError  Error allowed for approximation. Value 0 indicates no approximation
              *
-             * @return Model checking result
+             * @return Model checking result (or in case of approximation two results for lower and upper bound)
              */
-            ValueType checkHelper(storm::storage::DFT<ValueType> const& dft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool allowModularisation, bool enableDC);
+            dft_result checkHelper(storm::storage::DFT<ValueType> const& dft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool allowModularisation, bool enableDC, double approximationError);
 
-            /**
-             * Check the Dfts via model checking.
+            /*!
+             * Check model generated from DFT.
              *
-             * @param dfts               Vector of Dfts
+             * @param dft                The DFT
              * @param formula            Formula to check for
              * @param symred             Flag indicating if symmetry reduction should be used
              * @param enableDC           Flag indicating if dont care propagation should be used
              * @param approximationError Error allowed for approximation. Value 0 indicates no approximation
              *
-             * @return Vector of results for each model
+             * @return Model checking result
              */
-            std::vector<ValueType> checkModel(std::vector<storm::storage::DFT<ValueType>> const& dfts, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool enableDC, double approximationError = 0.0);
+            dft_result checkDFT(storm::storage::DFT<ValueType> const& dft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool enableDC, double approximationError = 0.0);
 
-            /**
-             * Build markov models from DFTs.
+            /*!
+             * Check the given markov model for the given property.
              *
-             * @param dfts               Vector of Dfts
-             * @param formula            Formula to check for
-             * @param symred             Flag indicating if symmetry reduction should be used
-             * @param enableDC           Flag indicating if dont care propagation should be used
-             * @param approximationError Error allowed for approximation. Value 0 indicates no approximation
+             * @param model   Model to check
+             * @param formula Formula to check for
+             *
+             * @return Model checking result
+             */
+            std::unique_ptr<storm::modelchecker::CheckResult> checkModel(std::shared_ptr<storm::models::sparse::Model<ValueType>>& model, std::shared_ptr<const storm::logic::Formula> const& formula);
+
+            /*!
+             * Checks if the computed approximation is sufficient, i.e. upperBound - lowerBound <= approximationError.
+             *
+             * @param lowerBound         The lower bound on the result.
+             * @param upperBound         The upper bound on the result.
+             * @param approximationError The allowed error for approximating.
              *
-             * @return Vector of markov models corresponding to DFTs.
+             * @return True, if the approximation is sufficient.
              */
-            std::vector<std::shared_ptr<storm::models::sparse::Model<ValueType>>> buildMarkovModels(std::vector<storm::storage::DFT<ValueType>> const& dfts, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool enableDC, double approximationError = 0.0);
+            bool isApproximationSufficient(ValueType lowerBound, ValueType upperBound, double approximationError);
 
         };
     }
diff --git a/src/settings/modules/DFTSettings.cpp b/src/settings/modules/DFTSettings.cpp
index 416a8a5af..c27009a85 100644
--- a/src/settings/modules/DFTSettings.cpp
+++ b/src/settings/modules/DFTSettings.cpp
@@ -21,8 +21,8 @@ namespace storm {
             const std::string DFTSettings::symmetryReductionOptionShortName = "symred";
             const std::string DFTSettings::modularisationOptionName = "modularisation";
             const std::string DFTSettings::disableDCOptionName = "disabledc";
-            const std::string DFTSettings::computeApproximationOptionName = "approximation";
-            const std::string DFTSettings::computeApproximationOptionShortName = "approx";
+            const std::string DFTSettings::approximationErrorOptionName = "approximation";
+            const std::string DFTSettings::approximationErrorOptionShortName = "approx";
             const std::string DFTSettings::propExpectedTimeOptionName = "expectedtime";
             const std::string DFTSettings::propExpectedTimeOptionShortName = "mttf";
             const std::string DFTSettings::propProbabilityOptionName = "probability";
@@ -39,7 +39,7 @@ namespace storm {
                 this->addOption(storm::settings::OptionBuilder(moduleName, symmetryReductionOptionName, false, "Exploit symmetric structure of model.").setShortName(symmetryReductionOptionShortName).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, modularisationOptionName, false, "Use modularisation (not applicable for expected time).").build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, disableDCOptionName, false, "Disable Dont Care propagation.").build());
-                this->addOption(storm::settings::OptionBuilder(moduleName, computeApproximationOptionName, false, "Compute an approximation.").setShortName(computeApproximationOptionShortName).build());
+                this->addOption(storm::settings::OptionBuilder(moduleName, approximationErrorOptionName, false, "Approximation error allowed.").setShortName(approximationErrorOptionShortName).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("error", "The approximation error to use.").addValidationFunctionDouble(storm::settings::ArgumentValidators::doubleGreaterValidatorIncluding(0.0)).build()).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, propExpectedTimeOptionName, false, "Compute expected time of system failure.").setShortName(propExpectedTimeOptionShortName).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, propProbabilityOptionName, false, "Compute probability of system failure.").build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, propTimeBoundOptionName, false, "Compute probability of system failure up to given timebound.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("time", "The timebound to use.").addValidationFunctionDouble(storm::settings::ArgumentValidators::doubleGreaterValidatorExcluding(0.0)).build()).build());
@@ -69,11 +69,15 @@ namespace storm {
             bool DFTSettings::isDisableDC() const {
                 return this->getOption(disableDCOptionName).getHasOptionBeenSet();
             }
-            
-            bool DFTSettings::computeApproximation() const {
-                return this->getOption(computeApproximationOptionName).getHasOptionBeenSet();
+
+            bool DFTSettings::isApproximationErrorSet() const {
+                return this->getOption(approximationErrorOptionName).getHasOptionBeenSet();
             }
-            
+
+            double DFTSettings::getApproximationError() const {
+                return this->getOption(approximationErrorOptionName).getArgumentByName("error").getValueAsDouble();
+            }
+
             bool DFTSettings::usePropExpectedTime() const {
                 return this->getOption(propExpectedTimeOptionName).getHasOptionBeenSet();
             }
diff --git a/src/settings/modules/DFTSettings.h b/src/settings/modules/DFTSettings.h
index f21752f7f..bb83a7475 100644
--- a/src/settings/modules/DFTSettings.h
+++ b/src/settings/modules/DFTSettings.h
@@ -32,10 +32,7 @@ namespace storm {
                  * @return The name of the file that contains the dft specification.
                  */
                 std::string getDftFilename() const;
-                
-                //expectedtime, probability, timebound, prob
-                //min, max
-                
+
                 /*!
                  * Retrieves whether the option to use symmetry reduction is set.
                  *
@@ -62,8 +59,15 @@ namespace storm {
                  *
                  * @return True iff the option was set.
                  */
-                bool computeApproximation() const;
-                
+                bool isApproximationErrorSet() const;
+
+                /*!
+                 * Retrieves the error allowed for approximation the model checking result.
+                 *
+                 * @return The allowed errorbound.
+                 */
+                double getApproximationError() const;
+
                 /*!
                  * Retrieves whether the property expected time should be used.
                  *
@@ -129,8 +133,8 @@ namespace storm {
                 static const std::string symmetryReductionOptionShortName;
                 static const std::string modularisationOptionName;
                 static const std::string disableDCOptionName;
-                static const std::string computeApproximationOptionName;
-                static const std::string computeApproximationOptionShortName;
+                static const std::string approximationErrorOptionName;
+                static const std::string approximationErrorOptionShortName;
                 static const std::string propExpectedTimeOptionName;
                 static const std::string propExpectedTimeOptionShortName;
                 static const std::string propProbabilityOptionName;
diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index 156f99d14..a38bd21b8 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -204,8 +204,14 @@ namespace storm {
         }
 
         template<typename ValueType>
-        std::pair<std::shared_ptr<DFTBE<ValueType> const>, bool> DFTState<ValueType>::letNextBEFail(size_t index)
-        {
+        ValueType DFTState<ValueType>::getFailableBERate(size_t index) const {
+            STORM_LOG_ASSERT(index < nrFailableBEs(), "Index invalid.");
+            // TODO Matthias: get passive failure rate when applicable
+            return mDft.getBasicElement(mIsCurrentlyFailableBE[index])->activeFailureRate();
+        }
+
+        template<typename ValueType>
+        std::pair<std::shared_ptr<DFTBE<ValueType> const>, bool> DFTState<ValueType>::letNextBEFail(size_t index) {
             STORM_LOG_TRACE("currently failable: " << getCurrentlyFailableString());
             if (nrFailableDependencies() > 0) {
                 // Consider failure due to dependency
diff --git a/src/storage/dft/DFTState.h b/src/storage/dft/DFTState.h
index 8562559b3..5558e63ae 100644
--- a/src/storage/dft/DFTState.h
+++ b/src/storage/dft/DFTState.h
@@ -31,6 +31,7 @@ namespace storm {
             bool mValid = true;
             const DFT<ValueType>& mDft;
             const DFTStateGenerationInfo& mStateGenerationInfo;
+            bool mSkip = false;
             
         public:
             DFTState(DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id);
@@ -95,6 +96,14 @@ namespace storm {
             bool isInvalid() const {
                 return !mValid;
             }
+
+            void markSkip() {
+                mSkip = true;
+            }
+
+            bool isSkip() const {
+                return mSkip;
+            }
             
             storm::storage::BitVector const& status() const {
                 return mStatus;
@@ -145,6 +154,14 @@ namespace storm {
                 return mIsCurrentlyFailableBE.size();
             }
 
+            /** Get the failure rate of the currently failable BE on the given index.
+             *
+             * @param index Index of BE in list of currently failable BEs.
+             *
+             * @return Failure rate of the BE.
+             */
+            ValueType getFailableBERate(size_t index) const;
+
             size_t nrFailableDependencies() const {
                 return mFailableDependencies.size();
             }
diff --git a/src/storm-dyftee.cpp b/src/storm-dyftee.cpp
index 89fc1da7b..51061050e 100644
--- a/src/storm-dyftee.cpp
+++ b/src/storm-dyftee.cpp
@@ -33,20 +33,25 @@
  * @param property PCTC formula capturing the property to check.
  */
 template <typename ValueType>
-void analyzeDFT(std::string filename, std::string property, bool symred = false, bool allowModularisation = false, bool enableDC = true) {
+void analyzeDFT(std::string filename, std::string property, bool symred, bool allowModularisation, bool enableDC, double approximationError) {
     std::cout << "Running DFT analysis on file " << filename << " with property " << property << std::endl;
 
     storm::parser::DFTGalileoParser<ValueType> parser;
     storm::storage::DFT<ValueType> dft = parser.parseDFT(filename);
     std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::parseFormulasForExplicit(property);
     STORM_LOG_ASSERT(formulas.size() == 1, "Wrong number of formulas.");
-    
+
     storm::modelchecker::DFTModelChecker<ValueType> modelChecker;
-    modelChecker.check(dft, formulas[0], symred, allowModularisation, enableDC);
+    modelChecker.check(dft, formulas[0], symred, allowModularisation, enableDC, approximationError);
     modelChecker.printTimings();
     modelChecker.printResult();
 }
 
+/*!
+ * Analyze the DFT with use of SMT solving.
+ *
+ * @param filename Path to DFT file in Galileo format.
+ */
 template<typename ValueType>
 void analyzeWithSMT(std::string filename) {
     std::cout << "Running DFT analysis on file " << filename << " with use of SMT" << std::endl;
@@ -163,11 +168,16 @@ int main(const int argc, const char** argv) {
         
         STORM_LOG_ASSERT(!pctlFormula.empty(), "Pctl formula empty.");
 
+        double approximationError = 0.0;
+        if (dftSettings.isApproximationErrorSet()) {
+            approximationError = dftSettings.getApproximationError();
+        }
+
         // From this point on we are ready to carry out the actual computations.
         if (parametric) {
-            analyzeDFT<storm::RationalFunction>(dftSettings.getDftFilename(), pctlFormula, dftSettings.useSymmetryReduction(), allowModular && dftSettings.useModularisation(), !dftSettings.isDisableDC() );
+            analyzeDFT<storm::RationalFunction>(dftSettings.getDftFilename(), pctlFormula, dftSettings.useSymmetryReduction(), allowModular && dftSettings.useModularisation(), !dftSettings.isDisableDC(), approximationError);
         } else {
-            analyzeDFT<double>(dftSettings.getDftFilename(), pctlFormula, dftSettings.useSymmetryReduction(), allowModular && dftSettings.useModularisation(), !dftSettings.isDisableDC());
+            analyzeDFT<double>(dftSettings.getDftFilename(), pctlFormula, dftSettings.useSymmetryReduction(), allowModular && dftSettings.useModularisation(), !dftSettings.isDisableDC(), approximationError);
         }
         
         // All operations have now been performed, so we clean up everything and terminate.

From aab45d4eabe6097de9c9f3e409e456cc64f989a5 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Mon, 10 Oct 2016 16:40:10 +0200
Subject: [PATCH 14/65] Naive iterative refinement of approximation

Former-commit-id: e1620cdefd307b984df1ac164a77797d3c838c99
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 321 ++++++++++++------
 src/builder/ExplicitDFTModelBuilderApprox.h   | 147 ++++++--
 src/generator/DftNextStateGenerator.cpp       |   2 +-
 src/generator/DftNextStateGenerator.h         |   2 +-
 src/modelchecker/dft/DFTModelChecker.cpp      |  25 +-
 src/storage/dft/DFTState.h                    |   4 +-
 6 files changed, 340 insertions(+), 161 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 74c448c25..b9eda6308 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -6,7 +6,6 @@
 #include <src/exceptions/UnexpectedException.h>
 #include "src/settings/modules/DFTSettings.h"
 #include "src/settings/SettingsManager.h"
-#include "src/generator/DftNextStateGenerator.h"
 #include <map>
 
 namespace storm {
@@ -18,80 +17,212 @@ namespace storm {
         }
 
         template<typename ValueType, typename StateType>
-        ExplicitDFTModelBuilderApprox<ValueType, StateType>::ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC) : dft(dft), enableDC(enableDC), stateStorage(((dft.stateVectorSize() / 64) + 1) * 64) {
+        ExplicitDFTModelBuilderApprox<ValueType, StateType>::MatrixBuilder::MatrixBuilder(bool canHaveNondeterminism) : mappingOffset(0), stateRemapping(), currentRowGroup(0), currentRow(0) {
+            // Create matrix builder
+            builder = storm::storage::SparseMatrixBuilder<ValueType>(0, 0, 0, false, canHaveNondeterminism, 0);
+        }
+
+        template<typename ValueType, typename StateType>
+        ExplicitDFTModelBuilderApprox<ValueType, StateType>::ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC) : dft(dft), stateGenerationInfo(std::make_shared<storm::storage::DFTStateGenerationInfo>(dft.buildStateGenerationInfo(symmetries))), enableDC(enableDC), generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates), matrixBuilder(!generator.isDeterministicModel()), stateStorage(((dft.stateVectorSize() / 64) + 1) * 64) {
             // stateVectorSize is bound for size of bitvector
-            stateGenerationInfo = std::make_shared<storm::storage::DFTStateGenerationInfo>(dft.buildStateGenerationInfo(symmetries));
         }
 
         template<typename ValueType, typename StateType>
-        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::buildModel(LabelOptions const& labelOpts, double approximationError) {
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::buildModel(LabelOptions const& labelOpts, bool firstTime, double approximationError) {
             STORM_LOG_TRACE("Generating DFT state space");
 
             // Initialize
-            StateType currentRowGroup = 0;
-            StateType currentRow = 0;
-            size_t pseudoStatesToCheck = 0;
-            modelComponents.markovianStates = storm::storage::BitVector(INITIAL_BITVECTOR_SIZE);
-            // Create generator
-            storm::generator::DftNextStateGenerator<ValueType, StateType> generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates);
             generator.setApproximationError(approximationError);
-            // Create sparse matrix builder
-            storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !generator.isDeterministicModel(), 0);
 
-            if(mergeFailedStates) {
-                // Introduce explicit fail state
-                storm::generator::StateBehavior<ValueType, StateType> behavior = generator.createMergeFailedState([this] (DFTStatePointer const& state) {
+            if (firstTime) {
+                // Initialize
+                modelComponents.markovianStates = storm::storage::BitVector(INITIAL_BITVECTOR_SIZE);
+
+                if(mergeFailedStates) {
+                    // Introduce explicit fail state
+                    storm::generator::StateBehavior<ValueType, StateType> behavior = generator.createMergeFailedState([this] (DFTStatePointer const& state) {
                         this->failedStateId = newIndex++;
-                        stateRemapping.push_back(0);
+                        matrixBuilder.stateRemapping.push_back(0);
                         return this->failedStateId;
                     } );
 
-                setRemapping(failedStateId, currentRowGroup);
+                    matrixBuilder.setRemapping(failedStateId);
+                    STORM_LOG_ASSERT(!behavior.empty(), "Behavior is empty.");
+                    matrixBuilder.newRowGroup();
+                    setMarkovian(behavior.begin()->isMarkovian());
+
+                    // Now add self loop.
+                    // TODO Matthias: maybe use general method.
+                    STORM_LOG_ASSERT(behavior.getNumberOfChoices() == 1, "Wrong number of choices for failed state.");
+                    STORM_LOG_ASSERT(behavior.begin()->size() == 1, "Wrong number of transitions for failed state.");
+                    std::pair<StateType, ValueType> stateProbabilityPair = *(behavior.begin()->begin());
+                    STORM_LOG_ASSERT(stateProbabilityPair.first == failedStateId, "No self loop for failed state.");
+                    STORM_LOG_ASSERT(storm::utility::isOne<ValueType>(stateProbabilityPair.second), "Probability for failed state != 1.");
+                    matrixBuilder.addTransition(stateProbabilityPair.first, stateProbabilityPair.second);
+                    matrixBuilder.finishRow();
+                }
+
+                // Build initial state
+                this->stateStorage.initialStateIndices = generator.getInitialStates(std::bind(&ExplicitDFTModelBuilderApprox::getOrAddStateIndex, this, std::placeholders::_1));
+                STORM_LOG_ASSERT(stateStorage.initialStateIndices.size() == 1, "Only one initial state assumed.");
+                initialStateIndex = stateStorage.initialStateIndices[0];
+                STORM_LOG_TRACE("Initial state: " << initialStateIndex);
+
+            } else {
+                initializeNextIteration();
+            }
+
+            exploreStateSpace();
+
+            size_t stateSize = stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0);
+            modelComponents.markovianStates.resize(stateSize);
+            modelComponents.deterministicModel = generator.isDeterministicModel();
+
+            // Replace pseudo states in matrix
+            // TODO Matthias: avoid hack with fixed int type
+            std::vector<uint_fast64_t> pseudoStatesVector;
+            for (auto const& pseudoStatePair : mPseudoStatesMapping) {
+                pseudoStatesVector.push_back(pseudoStatePair.first);
+            }
+            STORM_LOG_ASSERT(std::find(pseudoStatesVector.begin(), pseudoStatesVector.end(), 0) == pseudoStatesVector.end(), "Unexplored pseudo state still contained.");
+            matrixBuilder.builder.replaceColumns(pseudoStatesVector, OFFSET_PSEUDO_STATE);
+            mPseudoStatesMapping.clear();
+
+            // Fix the entries in the transition matrix according to the mapping of ids to row group indices
+            STORM_LOG_ASSERT(matrixBuilder.stateRemapping[initialStateIndex] == initialStateIndex, "Initial state should not be remapped.");
+            // TODO Matthias: do not consider all rows?
+            matrixBuilder.remap();
+
+            STORM_LOG_TRACE("State remapping: " << matrixBuilder.stateRemapping);
+            STORM_LOG_TRACE("Markovian states: " << modelComponents.markovianStates);
+            STORM_LOG_DEBUG("Generated " << stateSize << " states");
+            STORM_LOG_DEBUG("Skipped " << skippedStates.size() << " states");
+            STORM_LOG_DEBUG("Model is " << (generator.isDeterministicModel() ? "deterministic" : "non-deterministic"));
+
+            // Build transition matrix
+            modelComponents.transitionMatrix = matrixBuilder.builder.build(stateSize, stateSize);
+            if (stateSize <= 15) {
+                STORM_LOG_TRACE("Transition matrix: " << std::endl << modelComponents.transitionMatrix);
+            } else {
+                STORM_LOG_TRACE("Transition matrix: too big to print");
+            }
 
-                STORM_LOG_ASSERT(!behavior.empty(), "Behavior is empty.");
-                setMarkovian(currentRowGroup, behavior.begin()->isMarkovian());
+            buildLabeling(labelOpts);
+        }
 
-                // If the model is nondeterministic, we need to open a row group.
-                if (!generator.isDeterministicModel()) {
-                    transitionMatrixBuilder.newRowGroup(currentRow);
+        template<typename ValueType, typename StateType>
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::initializeNextIteration() {
+            STORM_LOG_TRACE("Refining DFT state space");
+
+            // Initialize matrix builder again
+            // TODO Matthias: avoid copy
+            std::vector<uint_fast64_t> copyRemapping = matrixBuilder.stateRemapping;
+            matrixBuilder = MatrixBuilder(!generator.isDeterministicModel());
+            matrixBuilder.stateRemapping = copyRemapping;
+            StateType nrStates = modelComponents.transitionMatrix.getRowGroupCount();
+            STORM_LOG_ASSERT(nrStates == matrixBuilder.stateRemapping.size(), "No. of states does not coincide with mapping size.");
+
+            // Start by creating a remapping from the old indices to the new indices
+            std::vector<StateType> indexRemapping = std::vector<StateType>(nrStates, 0);
+            auto iterSkipped = skippedStates.begin();
+            size_t skippedBefore = 0;
+            for (size_t i = 0; i < indexRemapping.size(); ++i) {
+                while (iterSkipped->first <= i) {
+                    ++skippedBefore;
+                    ++iterSkipped;
                 }
+                indexRemapping[i] = i - skippedBefore;
+            }
 
-                // Now add self loop.
-                // TODO Matthias: maybe use general method.
-                STORM_LOG_ASSERT(behavior.getNumberOfChoices() == 1, "Wrong number of choices for failed state.");
-                STORM_LOG_ASSERT(behavior.begin()->size() == 1, "Wrong number of transitions for failed state.");
-                std::pair<StateType, ValueType> stateProbabilityPair = *(behavior.begin()->begin());
-                STORM_LOG_ASSERT(stateProbabilityPair.first == failedStateId, "No self loop for failed state.");
-                STORM_LOG_ASSERT(storm::utility::isOne<ValueType>(stateProbabilityPair.second), "Probability for failed state != 1.");
-                transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second);
-                ++currentRow;
-                ++currentRowGroup;
+            // Set remapping
+            size_t nrExpandedStates = nrStates - skippedBefore;
+            matrixBuilder.mappingOffset = nrStates;
+            STORM_LOG_TRACE("# expanded states: " << nrExpandedStates);
+            StateType skippedIndex = nrExpandedStates;
+            std::map<StateType, DFTStatePointer> skippedStatesNew;
+            for (size_t id = 0; id < matrixBuilder.stateRemapping.size(); ++id) {
+                StateType index = matrixBuilder.stateRemapping[id];
+                auto itFind = skippedStates.find(index);
+                if (itFind != skippedStates.end()) {
+                    // Set new mapping for skipped state
+                    matrixBuilder.stateRemapping[id] = skippedIndex;
+                    skippedStatesNew[skippedIndex] = itFind->second;
+                    indexRemapping[index] = skippedIndex;
+                    ++skippedIndex;
+                } else {
+                    // Set new mapping for expanded state
+                    matrixBuilder.stateRemapping[id] = indexRemapping[index];
+                }
+            }
+            STORM_LOG_TRACE("New state remapping: " << matrixBuilder.stateRemapping);
+            std::stringstream ss;
+            ss << "Index remapping:" << std::endl;
+            for (auto tmp : indexRemapping) {
+                ss << tmp << " ";
+            }
+            STORM_LOG_TRACE(ss.str());
+
+            // Remap markovian states
+            storm::storage::BitVector markovianStatesNew = storm::storage::BitVector(modelComponents.markovianStates.size(), true);
+            // Iterate over all not set bits
+            modelComponents.markovianStates.complement();
+            size_t index = modelComponents.markovianStates.getNextSetIndex(0);
+            while (index < modelComponents.markovianStates.size()) {
+                markovianStatesNew.set(indexRemapping[index], false);
+                index = modelComponents.markovianStates.getNextSetIndex(index);
             }
+            STORM_LOG_ASSERT(modelComponents.markovianStates.size() - modelComponents.markovianStates.getNumberOfSetBits() == markovianStatesNew.getNumberOfSetBits(), "Remapping of markovian states is wrong.");
+            STORM_LOG_ASSERT(markovianStatesNew.size() == nrStates, "No. of states does not coincide with markovian size.");
+            modelComponents.markovianStates = markovianStatesNew;
+
+            // Build submatrix for expanded states
+            // TODO Matthias: only use row groups when necessary
+            for (StateType oldRowGroup = 0; oldRowGroup < modelComponents.transitionMatrix.getRowGroupCount(); ++oldRowGroup) {
+                if (indexRemapping[oldRowGroup] < nrExpandedStates) {
+                    // State is expanded -> copy to new matrix
+                    matrixBuilder.newRowGroup();
+                    for (StateType oldRow = modelComponents.transitionMatrix.getRowGroupIndices()[oldRowGroup]; oldRow < modelComponents.transitionMatrix.getRowGroupIndices()[oldRowGroup+1]; ++oldRow) {
+                        for (typename storm::storage::SparseMatrix<ValueType>::const_iterator itEntry = modelComponents.transitionMatrix.begin(oldRow); itEntry != modelComponents.transitionMatrix.end(oldRow); ++itEntry) {
+                            auto itFind = skippedStates.find(itEntry->getColumn());
+                            if (itFind != skippedStates.end()) {
+                                // Set id for skipped states as we remap it later
+                                matrixBuilder.addTransition(matrixBuilder.mappingOffset + itFind->second->getId(), itEntry->getValue());
+                            } else {
+                                // Set newly remapped index for expanded states
+                                matrixBuilder.addTransition(indexRemapping[itEntry->getColumn()], itEntry->getValue());
+                            }
+                        }
+                        matrixBuilder.finishRow();
+                    }
+                }
+            }
+
+            skippedStates = skippedStatesNew;
 
-            // Create a callback for the next-state generator to enable it to add states
-            std::function<StateType (DFTStatePointer const&)> stateToIdCallback = std::bind(&ExplicitDFTModelBuilderApprox::getOrAddStateIndex, this, std::placeholders::_1);
+            STORM_LOG_ASSERT(matrixBuilder.getCurrentRowGroup() == nrExpandedStates, "Row group size does not match.");
 
-            // Build initial states
-            this->stateStorage.initialStateIndices = generator.getInitialStates(stateToIdCallback);
-            STORM_LOG_ASSERT(stateStorage.initialStateIndices.size() == 1, "Only one initial state assumed.");
-            StateType initialStateIndex = stateStorage.initialStateIndices[0];
-            STORM_LOG_TRACE("Initial state: " << initialStateIndex);
+            // Explore all skipped states now
+            for (auto const& skippedState : skippedStates) {
+                skippedState.second->setSkip(false);
+                statesToExplore.push_front(skippedState.second);
+            }
+            skippedStates.clear();
+        }
 
-            // Explore state space
+        template<typename ValueType, typename StateType>
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::exploreStateSpace() {
             bool explorationFinished = false;
+            size_t pseudoStatesToCheck = 0;
             while (!explorationFinished) {
                 // Get the first state in the queue
                 DFTStatePointer currentState = statesToExplore.front();
                 STORM_LOG_ASSERT(stateStorage.stateToId.getValue(currentState->status()) == currentState->getId(), "Ids of states do not coincide.");
                 statesToExplore.pop_front();
 
-                // Remember that this row group was actually filled with the transitions of a different state
-                setRemapping(currentState->getId(), currentRowGroup);
+                // Remember that the current row group was actually filled with the transitions of a different state
+                matrixBuilder.setRemapping(currentState->getId());
 
-                // If the model is nondeterministic, we need to open a row group.
-                if (!generator.isDeterministicModel()) {
-                    transitionMatrixBuilder.newRowGroup(currentRow);
-                }
+                matrixBuilder.newRowGroup();
 
                 // Try to explore the next state
                 generator.load(currentState);
@@ -99,18 +230,18 @@ namespace storm {
                 if (currentState->isSkip()) {
                     // Skip the current state
                     STORM_LOG_TRACE("Skip expansion of state: " << dft.getStateString(currentState));
-                    setMarkovian(currentRowGroup, true);
+                    setMarkovian(true);
                     // Add transition to target state with temporary value 0
                     // TODO Matthias: what to do when there is no unique target state?
-                    transitionMatrixBuilder.addNextValue(currentRow, failedStateId, storm::utility::zero<ValueType>());
+                    matrixBuilder.addTransition(failedStateId, storm::utility::zero<ValueType>());
                     // Remember skipped state
-                    skippedStates[currentRow] = currentState;
-                    ++currentRow;
+                    skippedStates[matrixBuilder.getCurrentRowGroup() - 1] = currentState;
+                    matrixBuilder.finishRow();
                 } else {
                     // Explore the current state
-                    storm::generator::StateBehavior<ValueType, StateType> behavior = generator.expand(stateToIdCallback);
+                    storm::generator::StateBehavior<ValueType, StateType> behavior = generator.expand(std::bind(&ExplicitDFTModelBuilderApprox::getOrAddStateIndex, this, std::placeholders::_1));
                     STORM_LOG_ASSERT(!behavior.empty(), "Behavior is empty.");
-                    setMarkovian(currentRowGroup, behavior.begin()->isMarkovian());
+                    setMarkovian(behavior.begin()->isMarkovian());
 
                     // Now add all choices.
                     for (auto const& choice : behavior) {
@@ -130,15 +261,12 @@ namespace storm {
                                     }
                                 }
                             }
-
-                            transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second);
+                            matrixBuilder.addTransition(matrixBuilder.mappingOffset + stateProbabilityPair.first, stateProbabilityPair.second);
                         }
-                        ++currentRow;
+                        matrixBuilder.finishRow();
                     }
                 }
 
-                ++currentRowGroup;
-
                 if (statesToExplore.empty()) {
                     explorationFinished = true;
                     // Before ending the exploration check for pseudo states which are not initialized yet
@@ -161,45 +289,13 @@ namespace storm {
                 }
 
             } // end exploration
+        }
 
-            size_t stateSize = stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0);
-            modelComponents.markovianStates.resize(stateSize);
-            modelComponents.deterministicModel = generator.isDeterministicModel();
-
-            // Replace pseudo states in matrix
-            // TODO Matthias: avoid hack with fixed int type
-            std::vector<uint_fast64_t> pseudoStatesVector;
-            for (auto const& pseudoStatePair : mPseudoStatesMapping) {
-                pseudoStatesVector.push_back(pseudoStatePair.first);
-            }
-            STORM_LOG_ASSERT(std::find(pseudoStatesVector.begin(), pseudoStatesVector.end(), 0) == pseudoStatesVector.end(), "Unexplored pseudo state still contained.");
-            transitionMatrixBuilder.replaceColumns(pseudoStatesVector, OFFSET_PSEUDO_STATE);
-
-
-            // Fix the entries in the matrix according to the (reversed) mapping of row groups to indices
-            STORM_LOG_ASSERT(stateRemapping[initialStateIndex] == initialStateIndex, "Initial state should not be remapped.");
-            // Fix the transition matrix
-            transitionMatrixBuilder.replaceColumns(stateRemapping, 0);
-            // Fix the hash map storing the mapping states -> ids
-            this->stateStorage.stateToId.remap([this] (StateType const& state) { return this->stateRemapping[state]; } );
-
-            STORM_LOG_TRACE("State remapping: " << stateRemapping);
-            STORM_LOG_TRACE("Markovian states: " << modelComponents.markovianStates);
-            STORM_LOG_DEBUG("Generated " << stateSize << " states");
-            STORM_LOG_DEBUG("Skipped " << skippedStates.size() << " states");
-            STORM_LOG_DEBUG("Model is " << (generator.isDeterministicModel() ? "deterministic" : "non-deterministic"));
-
-            // Build transition matrix
-            modelComponents.transitionMatrix = transitionMatrixBuilder.build(stateSize, stateSize);
-            if (stateSize <= 15) {
-                STORM_LOG_TRACE("Transition matrix: " << std::endl << modelComponents.transitionMatrix);
-            } else {
-                STORM_LOG_TRACE("Transition matrix: too big to print");
-            }
-
+        template<typename ValueType, typename StateType>
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::buildLabeling(LabelOptions const& labelOpts) {
             // Build state labeling
-            modelComponents.stateLabeling = storm::models::sparse::StateLabeling(stateSize);
-            // Initial state is always first state without any failure
+            modelComponents.stateLabeling = storm::models::sparse::StateLabeling(modelComponents.transitionMatrix.getRowGroupCount());
+            // Initial state
             modelComponents.stateLabeling.addLabel("init");
             modelComponents.stateLabeling.addLabelToState("init", initialStateIndex);
             // Label all states corresponding to their status (failed, failsafe, failed BE)
@@ -259,13 +355,14 @@ namespace storm {
 
         template<typename ValueType, typename StateType>
         std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilderApprox<ValueType, StateType>::createModel(bool copy) {
+            std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
+
             if (modelComponents.deterministicModel) {
                 // Build CTMC
                 if (copy) {
-                    return std::make_shared<storm::models::sparse::Ctmc<ValueType>>(modelComponents.transitionMatrix, modelComponents.stateLabeling);
-
+                    model = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(modelComponents.transitionMatrix, modelComponents.stateLabeling);
                 } else {
-                    return std::make_shared<storm::models::sparse::Ctmc<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling));
+                    model = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling));
                 }
             } else {
                 // Build MA
@@ -290,11 +387,21 @@ namespace storm {
                 }
                 if (ma->hasOnlyTrivialNondeterminism()) {
                     // Markov automaton can be converted into CTMC
-                    return ma->convertToCTMC();
+                    // TODO Matthias: change components which were not moved accordingly
+                    model = ma->convertToCTMC();
                 } else {
-                    return ma;
+                    model = ma;
                 }
             }
+
+            STORM_LOG_DEBUG("No. states: " << model->getNumberOfStates());
+            STORM_LOG_DEBUG("No. transitions: " << model->getNumberOfTransitions());
+            if (model->getNumberOfStates() <= 15) {
+                STORM_LOG_TRACE("Transition matrix: " << std::endl << model->getTransitionMatrix());
+            } else {
+                STORM_LOG_TRACE("Transition matrix: too big to print");
+            }
+            return model;
         }
 
         template<typename ValueType, typename StateType>
@@ -369,7 +476,7 @@ namespace storm {
                     STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not match.");
                     STORM_LOG_TRACE("Remember state for later creation: " << dft.getStateString(state));
                     // Reserve one slot for the coming state in the remapping
-                    stateRemapping.push_back(0);
+                    matrixBuilder.stateRemapping.push_back(0);
                 } else {
                     // Create new state
                     state->setId(newIndex++);
@@ -379,25 +486,19 @@ namespace storm {
                     statesToExplore.push_front(state);
 
                     // Reserve one slot for the new state in the remapping
-                    stateRemapping.push_back(0);
+                    matrixBuilder.stateRemapping.push_back(0);
                 }
             }
             return stateId;
         }
 
         template<typename ValueType, typename StateType>
-        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::setMarkovian(StateType id, bool markovian) {
-            if (id >= modelComponents.markovianStates.size()) {
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::setMarkovian(bool markovian) {
+            if (matrixBuilder.getCurrentRowGroup() > modelComponents.markovianStates.size()) {
                 // Resize BitVector
                 modelComponents.markovianStates.resize(modelComponents.markovianStates.size() + INITIAL_BITVECTOR_SIZE);
             }
-            modelComponents.markovianStates.set(id, markovian);
-        }
-
-        template<typename ValueType, typename StateType>
-        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::setRemapping(StateType id, StateType mappedId) {
-            STORM_LOG_ASSERT(id < stateRemapping.size(), "Invalid index for remapping.");
-            stateRemapping[id] = mappedId;
+            modelComponents.markovianStates.set(matrixBuilder.getCurrentRowGroup() - 1, markovian);
         }
 
 
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index fa529f221..3f8af519f 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -4,6 +4,7 @@
 #include <src/models/sparse/StateLabeling.h>
 #include <src/models/sparse/StandardRewardModel.h>
 #include <src/models/sparse/Model.h>
+#include "src/generator/DftNextStateGenerator.h"
 #include <src/storage/SparseMatrix.h>
 #include "src/storage/sparse/StateStorage.h"
 #include <src/storage/dft/DFT.h>
@@ -32,6 +33,7 @@ namespace storm {
 
             // A structure holding the individual components of a model.
             struct ModelComponents {
+                // Constructor
                 ModelComponents();
 
                 // The transition matrix.
@@ -53,6 +55,87 @@ namespace storm {
                 bool deterministicModel;
             };
 
+            // A class holding the information for building the transition matrix.
+            class MatrixBuilder {
+            public:
+                // Constructor
+                MatrixBuilder(bool canHaveNondeterminism);
+
+                /*!
+                 * Set a mapping from a state id to the index in the matrix.
+                 *
+                 * @param id Id of the state.
+                 */
+                void setRemapping(StateType id) {
+                    STORM_LOG_ASSERT(id < stateRemapping.size(), "Invalid index for remapping.");
+                    stateRemapping[id] = currentRowGroup;
+                }
+
+                /*!
+                 * Create a new row group if the model is nondeterministic.
+                 */
+                void newRowGroup() {
+                    if (canHaveNondeterminism) {
+                        builder.newRowGroup(currentRow);
+                    }
+                    ++currentRowGroup;
+                }
+
+                /*!
+                 * Add a transition from the current row.
+                 *
+                 * @param index Target index
+                 * @param value Value of transition
+                 */
+                void addTransition(StateType index, ValueType value) {
+                    builder.addNextValue(currentRow, index, value);
+                }
+
+                /*!
+                 * Finish the current row.
+                 */
+                void finishRow() {
+                    ++currentRow;
+                }
+
+                /*!
+                 * Remap the columns in the matrix.
+                 */
+                void remap() {
+                    builder.replaceColumns(stateRemapping, mappingOffset);
+                }
+
+                /*!
+                 * Get the current row group.
+                 *
+                 * @return The current row group.
+                 */
+                StateType getCurrentRowGroup() {
+                    return currentRowGroup;
+                }
+
+                // Flag indicating if row groups are needed.
+                bool canHaveNondeterminism;
+
+                // Matrix builder.
+                storm::storage::SparseMatrixBuilder<ValueType> builder;
+
+                // Offset to distinguish states which will not be remapped anymore and those which will.
+                size_t mappingOffset;
+
+                // A mapping from state ids to the row group indices in which they actually reside.
+                // TODO Matthias: avoid hack with fixed int type
+                std::vector<uint_fast64_t> stateRemapping;
+
+            private:
+
+                // Index of the current row group.
+                StateType currentRowGroup;
+
+                // Index of the current row.
+                StateType currentRow;
+            };
+
         public:
             // A structure holding the labeling options.
             struct LabelOptions {
@@ -74,9 +157,10 @@ namespace storm {
              * Build model from DFT.
              *
              * @param labelOpts          Options for labeling.
+             * @param firstTime          Flag indicating if the model is built for the first time or rebuilt.
              * @param approximationError Error allowed for approximation.
              */
-            void buildModel(LabelOptions const& labelOpts, double approximationError = 0.0);
+            void buildModel(LabelOptions const& labelOpts, bool firstTime, double approximationError = 0.0);
 
             /*!
              * Get the built model.
@@ -96,6 +180,23 @@ namespace storm {
 
         private:
 
+            /*!
+             * Explore state space of DFT.
+             */
+            void exploreStateSpace();
+
+            /*!
+             * Initialize the matrix for a refinement iteration.
+             */
+            void initializeNextIteration();
+
+            /*!
+             * Build the labeling.
+             *
+             * @param labelOpts Options for labeling.
+             */
+            void buildLabeling(LabelOptions const& labelOpts);
+
             /*!
              * Add a state to the explored states (if not already there). It also handles pseudo states.
              *
@@ -106,20 +207,11 @@ namespace storm {
             StateType getOrAddStateIndex(DFTStatePointer const& state);
 
             /*!
-             * Set if the given state is markovian.
+             * Set markovian flag for the current state.
              *
-             * @param id Id of the state.
              * @param markovian Flag indicating if the state is markovian.
              */
-            void setMarkovian(StateType id, bool markovian);
-
-            /*!
-             * Set a mapping from a state id to its new id.
-             *
-             * @param id Id of the state.
-             * @param mappedId New id to use.
-             */
-            void setRemapping(StateType id, StateType mappedId);
+            void setMarkovian(bool markovian);
 
             /**
              * Change matrix to reflect the lower approximation bound.
@@ -158,40 +250,43 @@ namespace storm {
             // TODO Matthias: use const reference
             std::shared_ptr<storm::storage::DFTStateGenerationInfo> stateGenerationInfo;
 
-            // Current id for new state
-            size_t newIndex = 0;
-
-            // Mapping from pseudo states to (id of concrete state, bitvector)
-            std::vector<std::pair<StateType, storm::storage::BitVector>> mPseudoStatesMapping;
+            // Flag indication if dont care propagation should be used.
+            bool enableDC = true;
 
             //TODO Matthias: make changeable
             const bool mergeFailedStates = true;
 
+            // Current id for new state
+            size_t newIndex = 0;
+
             // Id of failed state
             size_t failedStateId = 0;
 
             // Id of initial state
             size_t initialStateIndex = 0;
 
-            // Flag indication if dont care propagation should be used.
-            bool enableDC = true;
+            // Mapping from pseudo states to (id of concrete state, bitvector representation)
+            std::vector<std::pair<StateType, storm::storage::BitVector>> mPseudoStatesMapping;
+
+            // Next state generator for exploring the state space
+            storm::generator::DftNextStateGenerator<ValueType, StateType> generator;
 
             // Structure for the components of the model.
             ModelComponents modelComponents;
 
+            // Structure for the transition matrix builder.
+            MatrixBuilder matrixBuilder;
+
             // Internal information about the states that were explored.
             storm::storage::sparse::StateStorage<StateType> stateStorage;
 
             // A set of states that still need to be explored.
             std::deque<DFTStatePointer> statesToExplore;
 
-            // A mapping from state indices to the row groups in which they actually reside
-            // TODO Matthias: avoid hack with fixed int type
-            std::vector<uint_fast64_t> stateRemapping;
-
-            // Holds all skipped states which were not yet expanded. More concrete it is a mapping from matrix indices
-            // to the corresponding skipped state.
-            std::unordered_map<StateType, DFTStatePointer> skippedStates;
+            // Holds all skipped states which were not yet expanded. More concretely it is a mapping from matrix indices
+            // to the corresponding skipped states.
+            // Notice that we need an ordered map here to easily iterate in increasing order over state ids.
+            std::map<StateType, DFTStatePointer> skippedStates;
         };
     }
 }
diff --git a/src/generator/DftNextStateGenerator.cpp b/src/generator/DftNextStateGenerator.cpp
index f468c673e..119ff9342 100644
--- a/src/generator/DftNextStateGenerator.cpp
+++ b/src/generator/DftNextStateGenerator.cpp
@@ -176,7 +176,7 @@ namespace storm {
                     if (approximationError > 0.0) {
                         if (checkSkipState(newState, rate, choice.getTotalMass(), approximationError)) {
                             STORM_LOG_TRACE("Will skip state " << newStateId);
-                            newState->markSkip();
+                            newState->setSkip(true);
                         }
                     }
                 }
diff --git a/src/generator/DftNextStateGenerator.h b/src/generator/DftNextStateGenerator.h
index 7c9e1bb48..6fa815e44 100644
--- a/src/generator/DftNextStateGenerator.h
+++ b/src/generator/DftNextStateGenerator.h
@@ -70,7 +70,7 @@ namespace storm {
             StateType mergeFailedStateId = 0;
 
             // Flag indicating if the model is deterministic.
-            bool deterministicModel = true;
+            bool deterministicModel = false;
 
             // Allowed approximation error.
             double approximationError = 0.0;
diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index 1c0772bf8..7ac2f1a8a 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -158,26 +158,17 @@ namespace storm {
                 size_t iteration = 0;
                 do {
                     // Iteratively build finer models
-                    // TODO Matthias: implement refinement
-                    STORM_LOG_ASSERT(iteration < 1, "Iterative refinement not yet implemented.");
                     explorationStart = std::chrono::high_resolution_clock::now();
                     STORM_LOG_INFO("Building model...");
                     // TODO Matthias refine model using existing model and MC results
                     currentApproximationError = pow(0.1, iteration) * approximationError;
-                    builder.buildModel(labeloptions, currentApproximationError);
+                    builder.buildModel(labeloptions, iteration < 1, currentApproximationError);
+
                     // TODO Matthias: possible to do bisimulation on approximated model and not on concrete one?
 
                     // Build model for lower bound
                     STORM_LOG_INFO("Getting model for lower bound...");
                     model = builder.getModelApproximation(true);
-                    //model->printModelInformationToStream(std::cout);
-                    STORM_LOG_INFO("No. states (Explored): " << model->getNumberOfStates());
-                    STORM_LOG_INFO("No. transitions (Explored): " << model->getNumberOfTransitions());
-                    if (model->getNumberOfStates() <= 15) {
-                        STORM_LOG_TRACE("Transition matrix: " << std::endl << model->getTransitionMatrix());
-                    } else {
-                        STORM_LOG_TRACE("Transition matrix: too big to print");
-                    }
                     explorationTime += std::chrono::high_resolution_clock::now() - explorationStart;
                     // Check lower bound
                     std::unique_ptr<storm::modelchecker::CheckResult> result = checkModel(model, formula);
@@ -188,14 +179,6 @@ namespace storm {
                     STORM_LOG_INFO("Getting model for upper bound...");
                     explorationStart = std::chrono::high_resolution_clock::now();
                     model = builder.getModelApproximation(false);
-                    //model->printModelInformationToStream(std::cout);
-                    STORM_LOG_INFO("No. states (Explored): " << model->getNumberOfStates());
-                    STORM_LOG_INFO("No. transitions (Explored): " << model->getNumberOfTransitions());
-                    if (model->getNumberOfStates() <= 15) {
-                        STORM_LOG_TRACE("Transition matrix: " << std::endl << model->getTransitionMatrix());
-                    } else {
-                        STORM_LOG_TRACE("Transition matrix: too big to print");
-                    }
                     explorationTime += std::chrono::high_resolution_clock::now() - explorationStart;
                     // Check upper bound
                     result = checkModel(model, formula);
@@ -203,7 +186,7 @@ namespace storm {
                     approxResult.second = result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second;
 
                     ++iteration;
-                    STORM_LOG_TRACE("Result after iteration " << iteration << ": (" << approxResult.first << ", " << approxResult.second << ")");
+                    STORM_LOG_INFO("Result after iteration " << iteration << ": (" << std::setprecision(10) << approxResult.first << ", " << approxResult.second << ")");
                 } while (!isApproximationSufficient(approxResult.first, approxResult.second, approximationError));
 
                 STORM_LOG_INFO("Finished approximation after " << iteration << " iteration" << (iteration > 1 ? "s." : "."));
@@ -216,7 +199,7 @@ namespace storm {
                 if (approximationError >= 0.0) {
                     storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
                     typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
-                    builder.buildModel(labeloptions);
+                    builder.buildModel(labeloptions, true);
                     model = builder.getModel();
                 } else {
                     storm::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries, enableDC);
diff --git a/src/storage/dft/DFTState.h b/src/storage/dft/DFTState.h
index 5558e63ae..c87008c9c 100644
--- a/src/storage/dft/DFTState.h
+++ b/src/storage/dft/DFTState.h
@@ -97,8 +97,8 @@ namespace storm {
                 return !mValid;
             }
 
-            void markSkip() {
-                mSkip = true;
+            void setSkip(bool skip) {
+                mSkip = skip;
             }
 
             bool isSkip() const {

From bf491117c7d35d90c56478d05798c339e8dca0d1 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Mon, 10 Oct 2016 17:26:45 +0200
Subject: [PATCH 15/65] Sort row only if replacement took place

Former-commit-id: 84f584d6c4dea92d8b199d34af2074e1e2163ed0
---
 src/storage/SparseMatrix.cpp | 73 ++++++++++++------------------------
 src/storage/SparseMatrix.h   |  8 +---
 2 files changed, 24 insertions(+), 57 deletions(-)

diff --git a/src/storage/SparseMatrix.cpp b/src/storage/SparseMatrix.cpp
index c43dc77d9..d38b0a838 100644
--- a/src/storage/SparseMatrix.cpp
+++ b/src/storage/SparseMatrix.cpp
@@ -22,6 +22,8 @@
 
 #include "src/utility/macros.h"
 
+#include <iterator>
+
 namespace storm {
     namespace storage {
         
@@ -267,66 +269,37 @@ namespace storm {
         }
         
         template<typename ValueType>
-        bool SparseMatrixBuilder<ValueType>::replaceColumns(std::vector<index_type> const& replacements, index_type offset) {
-            bool changed = false;
+        void SparseMatrixBuilder<ValueType>::replaceColumns(std::vector<index_type> const& replacements, index_type offset) {
             index_type maxColumn = 0;
-            for (auto& elem : columnsAndValues) {
-                if (elem.getColumn() >= offset) {
-                    elem.setColumn(replacements[elem.getColumn() - offset]);
-                    changed = true;
-                }
-                maxColumn = std::max(maxColumn, elem.getColumn());
-            }
-            STORM_LOG_ASSERT(changed || highestColumn == maxColumn, "Incorrect maximal column.");
-            highestColumn = maxColumn;
-            STORM_LOG_ASSERT(changed || lastColumn == columnsAndValues[columnsAndValues.size() - 1].getColumn(), "Incorrect last column.");
-            lastColumn = columnsAndValues[columnsAndValues.size() - 1].getColumn();
-            
-            if (changed) {
-                fixColumns();
-            }
-            return changed;
-        }
 
-        template<typename ValueType>
-        void SparseMatrixBuilder<ValueType>::fixColumns() {
-            // Sort columns per row
-            typename SparseMatrix<ValueType>::index_type endGroups;
-            typename SparseMatrix<ValueType>::index_type endRows;
-            
-            if (hasCustomRowGrouping) {
-                for (index_type group = 0; group < rowGroupIndices.get().size(); ++group) {
-                    endGroups = group < rowGroupIndices.get().size()-1 ? rowGroupIndices.get()[group+1] : rowIndications.size();
-                    for (index_type i = rowGroupIndices.get()[group]; i < endGroups; ++i) {
-                        endRows = i < rowIndications.size()-1 ? rowIndications[i+1] : columnsAndValues.size();
-                        // Sort the row
-                        std::sort(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows,
-                                  [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) {
-                                      return a.getColumn() < b.getColumn();
-                                  });
-                        // Assert no equal elements
-                        STORM_LOG_ASSERT(std::is_sorted(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows,
-                                              [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) {
-                                                  return a.getColumn() <= b.getColumn();
-                                              }), "Columns not sorted.");
+            for (index_type row = 0; row < rowIndications.size(); ++row) {
+                bool changed = false;
+                auto startRow = std::next(columnsAndValues.begin(), rowIndications[row]);
+                auto endRow = row < rowIndications.size()-1 ? std::next(columnsAndValues.begin(), rowIndications[row+1]) : columnsAndValues.end();
+                for (auto entry = startRow; entry != endRow; ++entry) {
+                    if (entry->getColumn() >= offset) {
+                        // Change column
+                        entry->setColumn(replacements[entry->getColumn() - offset]);
+                        changed = true;
                     }
+                    maxColumn = std::max(maxColumn, entry->getColumn());
                 }
-            } else {
-                for (index_type i = 0; i < rowIndications.size(); ++i) {
-                    endRows = i < rowIndications.size()-1 ? rowIndications[i+1] : columnsAndValues.size();
-                    // Sort the row
-                    std::sort(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows,
+                if (changed) {
+                    // Sort columns in row
+                    std::sort(startRow, endRow,
                               [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) {
                                   return a.getColumn() < b.getColumn();
                               });
                     // Assert no equal elements
-                    STORM_LOG_ASSERT(std::is_sorted(columnsAndValues.begin() + rowIndications[i], columnsAndValues.begin() + endRows,
-                                          [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) {
-                                              return a.getColumn() <= b.getColumn();
-                                          }), "Columns not sorted.");
+                    STORM_LOG_ASSERT(std::is_sorted(startRow, endRow,
+                                                    [](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) {
+                                                        return a.getColumn() < b.getColumn();
+                                                    }), "Columns not sorted.");
                 }
-
             }
+
+            highestColumn = maxColumn;
+            lastColumn = columnsAndValues[columnsAndValues.size() - 1].getColumn();
         }
 
         template<typename ValueType>
diff --git a/src/storage/SparseMatrix.h b/src/storage/SparseMatrix.h
index c170d43a9..5d9f48fe9 100644
--- a/src/storage/SparseMatrix.h
+++ b/src/storage/SparseMatrix.h
@@ -230,9 +230,8 @@ namespace storm {
              *
              * @param replacements Mapping indicating the replacements from offset+i -> value of i.
              * @param offset Offset to add to each id in vector index.
-             * @return True if replacement took place, False if nothing changed.
              */
-            bool replaceColumns(std::vector<index_type> const& replacements, index_type offset);
+            void replaceColumns(std::vector<index_type> const& replacements, index_type offset);
                         
         private:
             // A flag indicating whether a row count was set upon construction.
@@ -295,11 +294,6 @@ namespace storm {
             // Stores the currently active row group. This is used for correctly constructing the row grouping of the
             // matrix.
             index_type currentRowGroup;
-            
-            /*!
-             * Fixes the matrix by sorting the columns to gain increasing order again.
-             */
-            void fixColumns();
         };
         
         /*!

From 41a71f86889bcab17236ce170a65f4321acfb634 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Mon, 10 Oct 2016 17:44:45 +0200
Subject: [PATCH 16/65] Fixed bug with not setting nondetermism correctly

Former-commit-id: cd1e029c296df1d00c965be044f122dd04bf90e0
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 2 +-
 src/builder/ExplicitDFTModelBuilderApprox.h   | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index b9eda6308..0729fec59 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -17,7 +17,7 @@ namespace storm {
         }
 
         template<typename ValueType, typename StateType>
-        ExplicitDFTModelBuilderApprox<ValueType, StateType>::MatrixBuilder::MatrixBuilder(bool canHaveNondeterminism) : mappingOffset(0), stateRemapping(), currentRowGroup(0), currentRow(0) {
+        ExplicitDFTModelBuilderApprox<ValueType, StateType>::MatrixBuilder::MatrixBuilder(bool canHaveNondeterminism) : mappingOffset(0), stateRemapping(), currentRowGroup(0), currentRow(0), canHaveNondeterminism((canHaveNondeterminism)) {
             // Create matrix builder
             builder = storm::storage::SparseMatrixBuilder<ValueType>(0, 0, 0, false, canHaveNondeterminism, 0);
         }
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index 3f8af519f..b8658c6ce 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -114,9 +114,6 @@ namespace storm {
                     return currentRowGroup;
                 }
 
-                // Flag indicating if row groups are needed.
-                bool canHaveNondeterminism;
-
                 // Matrix builder.
                 storm::storage::SparseMatrixBuilder<ValueType> builder;
 
@@ -134,6 +131,9 @@ namespace storm {
 
                 // Index of the current row.
                 StateType currentRow;
+
+                // Flag indicating if row groups are needed.
+                bool canHaveNondeterminism;
             };
 
         public:

From 6b7bf3bba7abe115540cd3d20ec56fc5255cfd13 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Tue, 11 Oct 2016 22:50:16 +0200
Subject: [PATCH 17/65] Introduced heuristic depth with distance from initial
 state

Former-commit-id: 1b94ebc4f960f126b5338cdb0cee75aea0a42f1a
---
 src/builder/DftExplorationHeuristic.cpp       | 76 +++++++++++++++++++
 src/builder/DftExplorationHeuristic.h         | 44 +++++++++++
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 33 ++++----
 src/builder/ExplicitDFTModelBuilderApprox.h   | 31 ++++----
 src/generator/DftNextStateGenerator.cpp       | 49 +++---------
 src/generator/DftNextStateGenerator.h         | 21 -----
 src/modelchecker/dft/DFTModelChecker.cpp      |  2 +-
 src/storage/dft/DFTState.cpp                  |  9 ++-
 src/storage/dft/DFTState.h                    | 27 +++++--
 9 files changed, 192 insertions(+), 100 deletions(-)
 create mode 100644 src/builder/DftExplorationHeuristic.cpp
 create mode 100644 src/builder/DftExplorationHeuristic.h

diff --git a/src/builder/DftExplorationHeuristic.cpp b/src/builder/DftExplorationHeuristic.cpp
new file mode 100644
index 000000000..1364026a1
--- /dev/null
+++ b/src/builder/DftExplorationHeuristic.cpp
@@ -0,0 +1,76 @@
+#include "src/builder/DftExplorationHeuristic.h"
+#include "src/adapters/CarlAdapter.h"
+#include "src/utility/macros.h"
+#include "src/utility/constants.h"
+#include "src/exceptions/NotImplementedException.h"
+#include "src/storage/dft/DFTState.h"
+
+#include <limits>
+
+namespace storm {
+    namespace builder {
+
+        template<typename ValueType>
+        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic() : skip(true), depth(std::numeric_limits<std::size_t>::max()), rate(storm::utility::zero<ValueType>()), exitRate(storm::utility::zero<ValueType>()) {
+            // Intentionally left empty
+        }
+
+        template<typename ValueType>
+        bool DFTExplorationHeuristic<ValueType>::isSkip() const {
+            return skip;
+        }
+
+        template<typename ValueType>
+        size_t DFTExplorationHeuristic<ValueType>::getDepth() const {
+            return depth;
+        }
+
+        template<typename ValueType>
+        void DFTExplorationHeuristic<ValueType>::setHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) {
+            std::cout << "Set priority: " << depth << ", old: " << this->depth << std::endl;
+            this->depth = depth;
+            // TODO Matthias: update rates and exitRates as well
+            this->rate = rate;
+            this->exitRate = exitRate;
+        }
+
+        template<typename ValueType>
+        double DFTExplorationHeuristic<ValueType>::getPriority() const {
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Approximation works only for double.");
+        }
+
+        template<>
+        double DFTExplorationHeuristic<double>::getPriority() const {
+            // TODO Matthias: change according to heuristic
+            if (!skip) {
+                // TODO Matthias: change to non-magic number
+                return 0;
+            }
+            //return rate/exitRate;
+            return depth;
+        }
+
+        template<>
+        double DFTExplorationHeuristic<storm::RationalFunction>::getPriority() const {
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Approximation works only for double.");
+            /*std::cout << (rate / exitRate) << " < " << threshold << ": " << (number < threshold) << std::endl;
+             std::map<storm::Variable, storm::RationalNumber> mapping;
+             storm::RationalFunction eval(number.evaluate(mapping));
+             std::cout << "Evaluated: " << eval << std::endl;
+             return eval < threshold;*/
+        }
+
+        template<typename ValueType>
+        bool compareDepth(std::shared_ptr<storm::storage::DFTState<ValueType>> stateA, std::shared_ptr<storm::storage::DFTState<ValueType>> stateB) {
+            return stateA->getPriority() > stateB->getPriority();
+        }
+
+        template class DFTExplorationHeuristic<double>;
+        template bool compareDepth(std::shared_ptr<storm::storage::DFTState<double>>, std::shared_ptr<storm::storage::DFTState<double>>);
+
+#ifdef STORM_HAVE_CARL
+        template class DFTExplorationHeuristic<storm::RationalFunction>;
+        template bool compareDepth(std::shared_ptr<storm::storage::DFTState<storm::RationalFunction>>, std::shared_ptr<storm::storage::DFTState<storm::RationalFunction>>);
+#endif
+    }
+}
diff --git a/src/builder/DftExplorationHeuristic.h b/src/builder/DftExplorationHeuristic.h
new file mode 100644
index 000000000..59c35f812
--- /dev/null
+++ b/src/builder/DftExplorationHeuristic.h
@@ -0,0 +1,44 @@
+#ifndef STORM_BUILDER_DFTEXPLORATIONHEURISTIC_H_
+#define STORM_BUILDER_DFTEXPLORATIONHEURISTIC_H_
+
+#include <memory>
+#include <algorithm>
+
+namespace storm {
+
+    // Forward declaration
+    namespace storage {
+        template<typename ValueType>
+        class DFTState;
+    }
+
+    namespace builder {
+
+        template<typename ValueType>
+        class DFTExplorationHeuristic {
+
+        public:
+            DFTExplorationHeuristic();
+
+            void setHeuristicValues(size_t depth, ValueType rate, ValueType exitRate);
+
+            bool isSkip() const;
+
+            size_t getDepth() const;
+
+            double getPriority() const;
+            
+        private:
+            bool skip;
+            size_t depth;
+            ValueType rate;
+            ValueType exitRate;
+
+        };
+
+        template<typename ValueType>
+        bool compareDepth(std::shared_ptr<storm::storage::DFTState<ValueType>> stateA, std::shared_ptr<storm::storage::DFTState<ValueType>> stateB);
+    }
+}
+
+#endif /* STORM_BUILDER_DFTEXPLORATIONHEURISTIC_H_ */
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 0729fec59..3dedfd01d 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -25,15 +25,16 @@ namespace storm {
         template<typename ValueType, typename StateType>
         ExplicitDFTModelBuilderApprox<ValueType, StateType>::ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC) : dft(dft), stateGenerationInfo(std::make_shared<storm::storage::DFTStateGenerationInfo>(dft.buildStateGenerationInfo(symmetries))), enableDC(enableDC), generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates), matrixBuilder(!generator.isDeterministicModel()), stateStorage(((dft.stateVectorSize() / 64) + 1) * 64) {
             // stateVectorSize is bound for size of bitvector
+
+            // Compare states by their distance from the initial state
+            // TODO Matthias: customize
+            statesToExplore = std::priority_queue<DFTStatePointer, std::deque<DFTStatePointer>, std::function<bool(DFTStatePointer, DFTStatePointer)>>(&storm::builder::compareDepth<ValueType>);
         }
 
         template<typename ValueType, typename StateType>
-        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::buildModel(LabelOptions const& labelOpts, bool firstTime, double approximationError) {
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::buildModel(LabelOptions const& labelOpts, bool firstTime, double approximationThreshold) {
             STORM_LOG_TRACE("Generating DFT state space");
 
-            // Initialize
-            generator.setApproximationError(approximationError);
-
             if (firstTime) {
                 // Initialize
                 modelComponents.markovianStates = storm::storage::BitVector(INITIAL_BITVECTOR_SIZE);
@@ -72,7 +73,7 @@ namespace storm {
                 initializeNextIteration();
             }
 
-            exploreStateSpace();
+            exploreStateSpace(approximationThreshold);
 
             size_t stateSize = stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0);
             modelComponents.markovianStates.resize(stateSize);
@@ -169,7 +170,7 @@ namespace storm {
             size_t index = modelComponents.markovianStates.getNextSetIndex(0);
             while (index < modelComponents.markovianStates.size()) {
                 markovianStatesNew.set(indexRemapping[index], false);
-                index = modelComponents.markovianStates.getNextSetIndex(index);
+                index = modelComponents.markovianStates.getNextSetIndex(index+1);
             }
             STORM_LOG_ASSERT(modelComponents.markovianStates.size() - modelComponents.markovianStates.getNumberOfSetBits() == markovianStatesNew.getNumberOfSetBits(), "Remapping of markovian states is wrong.");
             STORM_LOG_ASSERT(markovianStatesNew.size() == nrStates, "No. of states does not coincide with markovian size.");
@@ -201,23 +202,24 @@ namespace storm {
 
             STORM_LOG_ASSERT(matrixBuilder.getCurrentRowGroup() == nrExpandedStates, "Row group size does not match.");
 
-            // Explore all skipped states now
+            // Push skipped states to explore queue
+            // TODO Matthias: remove
             for (auto const& skippedState : skippedStates) {
-                skippedState.second->setSkip(false);
-                statesToExplore.push_front(skippedState.second);
+                statesToExplore.push(skippedState.second);
             }
             skippedStates.clear();
         }
 
         template<typename ValueType, typename StateType>
-        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::exploreStateSpace() {
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::exploreStateSpace(double approximationThreshold) {
             bool explorationFinished = false;
             size_t pseudoStatesToCheck = 0;
             while (!explorationFinished) {
                 // Get the first state in the queue
-                DFTStatePointer currentState = statesToExplore.front();
+                DFTStatePointer currentState = statesToExplore.top();
+                STORM_LOG_ASSERT(stateStorage.stateToId.contains(currentState->status()), "State is not contained in state storage.");
                 STORM_LOG_ASSERT(stateStorage.stateToId.getValue(currentState->status()) == currentState->getId(), "Ids of states do not coincide.");
-                statesToExplore.pop_front();
+                statesToExplore.pop();
 
                 // Remember that the current row group was actually filled with the transitions of a different state
                 matrixBuilder.setRemapping(currentState->getId());
@@ -227,7 +229,8 @@ namespace storm {
                 // Try to explore the next state
                 generator.load(currentState);
 
-                if (currentState->isSkip()) {
+                STORM_LOG_TRACE("Priority of state " <<currentState->getId() << ": " << currentState->getPriority());
+                if (currentState->getPriority() > approximationThreshold) {
                     // Skip the current state
                     STORM_LOG_TRACE("Skip expansion of state: " << dft.getStateString(currentState));
                     setMarkovian(true);
@@ -464,7 +467,7 @@ namespace storm {
                     stateId = state->getId();
                     stateStorage.stateToId.setOrAdd(state->status(), stateId);
                     STORM_LOG_TRACE("Now create state " << dft.getStateString(state) << " with id " << stateId);
-                    statesToExplore.push_front(state);
+                    statesToExplore.push(state);
                 }
             } else {
                 // State does not exist yet
@@ -483,7 +486,7 @@ namespace storm {
                     stateId = stateStorage.stateToId.findOrAdd(state->status(), state->getId());
                     STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not match.");
                     STORM_LOG_TRACE("New state: " << dft.getStateString(state));
-                    statesToExplore.push_front(state);
+                    statesToExplore.push(state);
 
                     // Reserve one slot for the new state in the remapping
                     matrixBuilder.stateRemapping.push_back(0);
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index b8658c6ce..65575735f 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -1,14 +1,15 @@
 #ifndef EXPLICITDFTMODELBUILDERAPPROX_H
 #define	EXPLICITDFTMODELBUILDERAPPROX_H
 
-#include <src/models/sparse/StateLabeling.h>
-#include <src/models/sparse/StandardRewardModel.h>
-#include <src/models/sparse/Model.h>
+#include "src/builder/DftExplorationHeuristic.h"
+#include "src/models/sparse/StateLabeling.h"
+#include "src/models/sparse/StandardRewardModel.h"
+#include "src/models/sparse/Model.h"
 #include "src/generator/DftNextStateGenerator.h"
-#include <src/storage/SparseMatrix.h>
+#include "src/storage/SparseMatrix.h"
 #include "src/storage/sparse/StateStorage.h"
-#include <src/storage/dft/DFT.h>
-#include <src/storage/dft/SymmetricUnits.h>
+#include "src/storage/dft/DFT.h"
+#include "src/storage/dft/SymmetricUnits.h"
 #include <boost/container/flat_set.hpp>
 #include <boost/optional/optional.hpp>
 #include <stack>
@@ -156,11 +157,11 @@ namespace storm {
             /*!
              * Build model from DFT.
              *
-             * @param labelOpts          Options for labeling.
-             * @param firstTime          Flag indicating if the model is built for the first time or rebuilt.
-             * @param approximationError Error allowed for approximation.
+             * @param labelOpts              Options for labeling.
+             * @param firstTime              Flag indicating if the model is built for the first time or rebuilt.
+             * @param approximationThreshold Threshold determining when to skip exploring states.
              */
-            void buildModel(LabelOptions const& labelOpts, bool firstTime, double approximationError = 0.0);
+            void buildModel(LabelOptions const& labelOpts, bool firstTime, double approximationThreshold = 0.0);
 
             /*!
              * Get the built model.
@@ -182,8 +183,10 @@ namespace storm {
 
             /*!
              * Explore state space of DFT.
+             *
+             * @param approximationThreshold Threshold to determine when to skip states.
              */
-            void exploreStateSpace();
+            void exploreStateSpace(double approximationThreshold);
 
             /*!
              * Initialize the matrix for a refinement iteration.
@@ -237,7 +240,6 @@ namespace storm {
              */
             std::shared_ptr<storm::models::sparse::Model<ValueType>> createModel(bool copy);
 
-
             // Initial size of the bitvector.
             const size_t INITIAL_BITVECTOR_SIZE = 20000;
             // Offset used for pseudo states.
@@ -280,14 +282,15 @@ namespace storm {
             // Internal information about the states that were explored.
             storm::storage::sparse::StateStorage<StateType> stateStorage;
 
-            // A set of states that still need to be explored.
-            std::deque<DFTStatePointer> statesToExplore;
+            // A pniority queue of states that still need to be explored.
+            std::priority_queue<DFTStatePointer, std::deque<DFTStatePointer>, std::function<bool(DFTStatePointer, DFTStatePointer)>> statesToExplore;
 
             // Holds all skipped states which were not yet expanded. More concretely it is a mapping from matrix indices
             // to the corresponding skipped states.
             // Notice that we need an ordered map here to easily iterate in increasing order over state ids.
             std::map<StateType, DFTStatePointer> skippedStates;
         };
+
     }
 }
 
diff --git a/src/generator/DftNextStateGenerator.cpp b/src/generator/DftNextStateGenerator.cpp
index 119ff9342..31d17fbe0 100644
--- a/src/generator/DftNextStateGenerator.cpp
+++ b/src/generator/DftNextStateGenerator.cpp
@@ -20,6 +20,7 @@ namespace storm {
         template<typename ValueType, typename StateType>
         std::vector<StateType> DftNextStateGenerator<ValueType, StateType>::getInitialStates(StateToIdCallback const& stateToIdCallback) {
             DFTStatePointer initialState = std::make_shared<storm::storage::DFTState<ValueType>>(mDft, mStateGenerationInfo, 0);
+            initialState->setHeuristicValues(0, storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>());
 
             // Register initial state
             StateType id = stateToIdCallback(initialState);
@@ -75,7 +76,7 @@ namespace storm {
                 STORM_LOG_ASSERT(!mDft.hasFailed(state), "Dft has failed.");
 
                 // Construct new state as copy from original one
-                DFTStatePointer newState = std::make_shared<storm::storage::DFTState<ValueType>>(*state);
+                DFTStatePointer newState = state->copy();
                 std::pair<std::shared_ptr<storm::storage::DFTBE<ValueType> const>, bool> nextBEPair = newState->letNextBEFail(currentFailable);
                 std::shared_ptr<storm::storage::DFTBE<ValueType> const>& nextBE = nextBEPair.first;
                 STORM_LOG_ASSERT(nextBE, "NextBE is null.");
@@ -150,15 +151,17 @@ namespace storm {
 
                     if (!storm::utility::isOne(probability)) {
                         // Add transition to state where dependency was unsuccessful
-                        DFTStatePointer unsuccessfulState = std::make_shared<storm::storage::DFTState<ValueType>>(*state);
+                        DFTStatePointer unsuccessfulState = state->copy();
                         unsuccessfulState->letDependencyBeUnsuccessful(currentFailable);
                         // Add state
                         StateType unsuccessfulStateId = stateToIdCallback(unsuccessfulState);
                         ValueType remainingProbability = storm::utility::one<ValueType>() - probability;
                         choice.addProbability(unsuccessfulStateId, remainingProbability);
                         STORM_LOG_TRACE("Added transition to " << unsuccessfulStateId << " with remaining probability " << remainingProbability);
+                        unsuccessfulState->setHeuristicValues(state, remainingProbability, storm::utility::one<ValueType>());
                     }
                     result.addChoice(std::move(choice));
+                    newState->setHeuristicValues(state, probability, storm::utility::one<ValueType>());
                 } else {
                     // Failure is due to "normal" BE failure
                     // Set failure rate according to activation
@@ -171,14 +174,7 @@ namespace storm {
                     STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Rate is 0.");
                     choice.addProbability(newStateId, rate);
                     STORM_LOG_TRACE("Added transition to " << newStateId << " with " << (isActive ? "active" : "passive") << " failure rate " << rate);
-
-                    // Check if new state needs expansion for approximation
-                    if (approximationError > 0.0) {
-                        if (checkSkipState(newState, rate, choice.getTotalMass(), approximationError)) {
-                            STORM_LOG_TRACE("Will skip state " << newStateId);
-                            newState->setSkip(true);
-                        }
-                    }
+                    newState->setHeuristicValues(state, rate, choice.getTotalMass());
                 }
 
                 ++currentFailable;
@@ -213,37 +209,10 @@ namespace storm {
             return result;
         }
 
-        template<typename ValueType, typename StateType>
-        void DftNextStateGenerator<ValueType, StateType>::setApproximationError(double approximationError) {
-            this->approximationError = approximationError;
-        }
-
-        template<typename ValueType, typename StateType>
-        bool DftNextStateGenerator<ValueType, StateType>::checkSkipState(DFTStatePointer const& state, ValueType rate, ValueType exitRate, double approximationError) {
-            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Approximation works only for double.");
-        }
-
-        template<>
-        bool DftNextStateGenerator<double>::checkSkipState(DFTStatePointer const& state, double rate, double exitRate, double approximationError) {
-            if (mDft.hasFailed(state) || mDft.isFailsafe(state) ||  (state->nrFailableDependencies() == 0 && state->nrFailableBEs() == 0)) {
-                // Do not skip absorbing state
-                return false;
-            }
-            // Skip if the rate to reach this state is low compared to all other outgoing rates from the predecessor
-            return rate/exitRate < approximationError;
-        }
-
-        template<>
-        bool DftNextStateGenerator<storm::RationalFunction>::checkSkipState(DFTStatePointer const& state, storm::RationalFunction rate, storm::RationalFunction exitRate, double approximationError) {
-            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Approximation works only for double.");
-            /*std::cout << (rate / exitRate) << " < " << threshold << ": " << (number < threshold) << std::endl;
-            std::map<storm::Variable, storm::RationalNumber> mapping;
-            storm::RationalFunction eval(number.evaluate(mapping));
-            std::cout << "Evaluated: " << eval << std::endl;
-            return eval < threshold;*/
-        }
-        
         template class DftNextStateGenerator<double>;
+
+#ifdef STORM_HAVE_CARL
         template class DftNextStateGenerator<storm::RationalFunction>;
+#endif
     }
 }
diff --git a/src/generator/DftNextStateGenerator.h b/src/generator/DftNextStateGenerator.h
index 6fa815e44..8fdfbf471 100644
--- a/src/generator/DftNextStateGenerator.h
+++ b/src/generator/DftNextStateGenerator.h
@@ -42,13 +42,6 @@ namespace storm {
              */
             StateBehavior<ValueType, StateType> createMergeFailedState(StateToIdCallback const& stateToIdCallback);
 
-            /*!
-             * Set a new value for the allowed approximation error.
-             *
-             * @param approximationError Allowed approximation error.
-             */
-            void setApproximationError(double approximationError);
-
         private:
             
             // The dft used for the generation of next states.
@@ -72,20 +65,6 @@ namespace storm {
             // Flag indicating if the model is deterministic.
             bool deterministicModel = false;
 
-            // Allowed approximation error.
-            double approximationError = 0.0;
-
-            /*!
-             * Check if the given state should be skipped for expansion.
-             *
-             * @param state              State to check for expansion
-             * @param rate               Rate of current state
-             * @param exitRate           Exit rates of all outgoing transitions
-             * @param approximationError Allowed approximation error
-             *
-             * @return True, if the given state should be skipped.
-             */
-            bool checkSkipState(DFTStatePointer const& state, ValueType rate, ValueType exitRate, double approximationError);
         };
         
     }
diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index 7ac2f1a8a..205e658f3 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -162,7 +162,7 @@ namespace storm {
                     STORM_LOG_INFO("Building model...");
                     // TODO Matthias refine model using existing model and MC results
                     currentApproximationError = pow(0.1, iteration) * approximationError;
-                    builder.buildModel(labeloptions, iteration < 1, currentApproximationError);
+                    builder.buildModel(labeloptions, iteration < 1, iteration);
 
                     // TODO Matthias: possible to do bisimulation on approximated model and not on concrete one?
 
diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index a38bd21b8..5e84b0c56 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -6,7 +6,7 @@ namespace storm {
     namespace storage {
 
         template<typename ValueType>
-        DFTState<ValueType>::DFTState(DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(dft.stateVectorSize()), mId(id), mDft(dft), mStateGenerationInfo(stateGenerationInfo)  {
+        DFTState<ValueType>::DFTState(DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(dft.stateVectorSize()), mId(id), mDft(dft), mStateGenerationInfo(stateGenerationInfo), exploreHeuristic()  {
             
             // Initialize uses
             for(size_t spareId  : mDft.getSpareIndices()) {
@@ -55,6 +55,13 @@ namespace storm {
             }
         }
 
+        template<typename ValueType>
+        std::shared_ptr<DFTState<ValueType>> DFTState<ValueType>::copy() const {
+            std::shared_ptr<DFTState<ValueType>> stateCopy = std::make_shared<storm::storage::DFTState<ValueType>>(*this);
+            stateCopy->exploreHeuristic = storm::builder::DFTExplorationHeuristic<ValueType>();
+            return stateCopy;
+        }
+
         template<typename ValueType>
         DFTElementState DFTState<ValueType>::getElementState(size_t id) const {
             return static_cast<DFTElementState>(getElementStateInt(id));
diff --git a/src/storage/dft/DFTState.h b/src/storage/dft/DFTState.h
index c87008c9c..cd2b9eb0f 100644
--- a/src/storage/dft/DFTState.h
+++ b/src/storage/dft/DFTState.h
@@ -1,8 +1,9 @@
 #ifndef DFTSTATE_H
 #define	DFTSTATE_H
 
-#include "../BitVector.h"
-#include "DFTElementState.h"
+#include "src/storage/dft/DFTElementState.h"
+#include "src/storage/BitVector.h"
+#include "src/builder/DftExplorationHeuristic.h"
 
 #include <sstream>
 #include <memory>
@@ -31,7 +32,7 @@ namespace storm {
             bool mValid = true;
             const DFT<ValueType>& mDft;
             const DFTStateGenerationInfo& mStateGenerationInfo;
-            bool mSkip = false;
+            storm::builder::DFTExplorationHeuristic<ValueType> exploreHeuristic;
             
         public:
             DFTState(DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id);
@@ -40,7 +41,9 @@ namespace storm {
              * Construct state from underlying bitvector.
              */
             DFTState(storm::storage::BitVector const& status, DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id);
-            
+
+            std::shared_ptr<DFTState<ValueType>> copy() const;
+
             DFTElementState getElementState(size_t id) const;
             
             DFTDependencyState getDependencyState(size_t id) const;
@@ -97,12 +100,20 @@ namespace storm {
                 return !mValid;
             }
 
-            void setSkip(bool skip) {
-                mSkip = skip;
+            void setHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) {
+                exploreHeuristic.setHeuristicValues(depth, rate, exitRate);
+            }
+
+            void setHeuristicValues(std::shared_ptr<storm::storage::DFTState<ValueType>> oldState, ValueType rate, ValueType exitRate) {
+                if (hasFailed(mDft.getTopLevelIndex()) || isFailsafe(mDft.getTopLevelIndex()) || (nrFailableDependencies() == 0 && nrFailableBEs() == 0)) {
+                    // Do not skip absorbing state
+                    exploreHeuristic.setNotSkip();
+                }
+                exploreHeuristic.setHeuristicValues(oldState->exploreHeuristic.getDepth() + 1, rate, exitRate);
             }
 
-            bool isSkip() const {
-                return mSkip;
+            double getPriority() const {
+                return exploreHeuristic.getPriority();
             }
             
             storm::storage::BitVector const& status() const {

From 53821d3d84a50419f1ed8566fa8bfec64c6bc6ff Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Tue, 11 Oct 2016 22:58:00 +0200
Subject: [PATCH 18/65] Added settings for approximation heuristic

Former-commit-id: 40267add31426b65c1232ad11a82b12d0e1a0e0d
---
 src/builder/DftExplorationHeuristic.cpp       | 25 ++++++++++++++-----
 src/builder/DftExplorationHeuristic.h         | 10 +++++++-
 src/builder/ExplicitDFTModelBuilderApprox.cpp |  5 ++--
 src/builder/ExplicitDFTModelBuilderApprox.h   |  3 +++
 src/settings/modules/DFTSettings.cpp          | 18 +++++++++++--
 src/settings/modules/DFTSettings.h            |  9 +++++++
 src/storage/dft/DFTState.h                    |  4 +++
 7 files changed, 63 insertions(+), 11 deletions(-)

diff --git a/src/builder/DftExplorationHeuristic.cpp b/src/builder/DftExplorationHeuristic.cpp
index 1364026a1..74937d4b1 100644
--- a/src/builder/DftExplorationHeuristic.cpp
+++ b/src/builder/DftExplorationHeuristic.cpp
@@ -16,10 +16,27 @@ namespace storm {
         }
 
         template<typename ValueType>
-        bool DFTExplorationHeuristic<ValueType>::isSkip() const {
-            return skip;
+        bool DFTExplorationHeuristic<ValueType>::isSkip(double approximationThreshold, ApproximationHeuristic heuristic) const {
+            if (!skip) {
+                return false;
+            }
+            switch (heuristic) {
+                case ApproximationHeuristic::NONE:
+                    return false;
+                case ApproximationHeuristic::DEPTH:
+                    return depth > approximationThreshold;
+                case ApproximationHeuristic::RATERATIO:
+                    // TODO Matthias: implement
+                    STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work.");
+            }
         }
 
+        template<typename ValueType>
+        void DFTExplorationHeuristic<ValueType>::setNotSkip() {
+            skip = false;
+        }
+
+
         template<typename ValueType>
         size_t DFTExplorationHeuristic<ValueType>::getDepth() const {
             return depth;
@@ -42,10 +59,6 @@ namespace storm {
         template<>
         double DFTExplorationHeuristic<double>::getPriority() const {
             // TODO Matthias: change according to heuristic
-            if (!skip) {
-                // TODO Matthias: change to non-magic number
-                return 0;
-            }
             //return rate/exitRate;
             return depth;
         }
diff --git a/src/builder/DftExplorationHeuristic.h b/src/builder/DftExplorationHeuristic.h
index 59c35f812..a9958443a 100644
--- a/src/builder/DftExplorationHeuristic.h
+++ b/src/builder/DftExplorationHeuristic.h
@@ -14,6 +14,11 @@ namespace storm {
 
     namespace builder {
 
+        /*!
+         * Enum representing the heuristic used for deciding which states to expand.
+         */
+        enum class ApproximationHeuristic { NONE, DEPTH, RATERATIO };
+
         template<typename ValueType>
         class DFTExplorationHeuristic {
 
@@ -22,13 +27,16 @@ namespace storm {
 
             void setHeuristicValues(size_t depth, ValueType rate, ValueType exitRate);
 
-            bool isSkip() const;
+            bool isSkip(double approximationThreshold, ApproximationHeuristic heuristic) const;
+
+            void setNotSkip();
 
             size_t getDepth() const;
 
             double getPriority() const;
             
         private:
+
             bool skip;
             size_t depth;
             ValueType rate;
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 3dedfd01d..9ed09eccb 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -26,6 +26,8 @@ namespace storm {
         ExplicitDFTModelBuilderApprox<ValueType, StateType>::ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC) : dft(dft), stateGenerationInfo(std::make_shared<storm::storage::DFTStateGenerationInfo>(dft.buildStateGenerationInfo(symmetries))), enableDC(enableDC), generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates), matrixBuilder(!generator.isDeterministicModel()), stateStorage(((dft.stateVectorSize() / 64) + 1) * 64) {
             // stateVectorSize is bound for size of bitvector
 
+            heuristic = storm::settings::getModule<storm::settings::modules::DFTSettings>().getApproximationHeuristic();
+
             // Compare states by their distance from the initial state
             // TODO Matthias: customize
             statesToExplore = std::priority_queue<DFTStatePointer, std::deque<DFTStatePointer>, std::function<bool(DFTStatePointer, DFTStatePointer)>>(&storm::builder::compareDepth<ValueType>);
@@ -229,8 +231,7 @@ namespace storm {
                 // Try to explore the next state
                 generator.load(currentState);
 
-                STORM_LOG_TRACE("Priority of state " <<currentState->getId() << ": " << currentState->getPriority());
-                if (currentState->getPriority() > approximationThreshold) {
+                if (currentState->isSkip(approximationThreshold, heuristic)) {
                     // Skip the current state
                     STORM_LOG_TRACE("Skip expansion of state: " << dft.getStateString(currentState));
                     setMarkovian(true);
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index 65575735f..cb9a444af 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -258,6 +258,9 @@ namespace storm {
             //TODO Matthias: make changeable
             const bool mergeFailedStates = true;
 
+            // Heuristic used for approximation
+            storm::builder::ApproximationHeuristic heuristic;
+
             // Current id for new state
             size_t newIndex = 0;
 
diff --git a/src/settings/modules/DFTSettings.cpp b/src/settings/modules/DFTSettings.cpp
index c27009a85..1b3f0bae2 100644
--- a/src/settings/modules/DFTSettings.cpp
+++ b/src/settings/modules/DFTSettings.cpp
@@ -9,7 +9,6 @@
 
 #include "src/exceptions/InvalidSettingsException.h"
 
-
 namespace storm {
     namespace settings {
         namespace modules {
@@ -23,6 +22,7 @@ namespace storm {
             const std::string DFTSettings::disableDCOptionName = "disabledc";
             const std::string DFTSettings::approximationErrorOptionName = "approximation";
             const std::string DFTSettings::approximationErrorOptionShortName = "approx";
+            const std::string DFTSettings::approximationHeuristicOptionName = "approximationheuristic";
             const std::string DFTSettings::propExpectedTimeOptionName = "expectedtime";
             const std::string DFTSettings::propExpectedTimeOptionShortName = "mttf";
             const std::string DFTSettings::propProbabilityOptionName = "probability";
@@ -40,6 +40,7 @@ namespace storm {
                 this->addOption(storm::settings::OptionBuilder(moduleName, modularisationOptionName, false, "Use modularisation (not applicable for expected time).").build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, disableDCOptionName, false, "Disable Dont Care propagation.").build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, approximationErrorOptionName, false, "Approximation error allowed.").setShortName(approximationErrorOptionShortName).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("error", "The approximation error to use.").addValidationFunctionDouble(storm::settings::ArgumentValidators::doubleGreaterValidatorIncluding(0.0)).build()).build());
+                this->addOption(storm::settings::OptionBuilder(moduleName, approximationHeuristicOptionName, false, "Set the heuristic used for approximation.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("heuristic", "Sets which heuristic is used for approximation. Must be in {depth, rateratio}. Default is").setDefaultValueString("depth").addValidationFunctionString(storm::settings::ArgumentValidators::stringInListValidator({"depth", "rateratio"})).build()).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, propExpectedTimeOptionName, false, "Compute expected time of system failure.").setShortName(propExpectedTimeOptionShortName).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, propProbabilityOptionName, false, "Compute probability of system failure.").build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, propTimeBoundOptionName, false, "Compute probability of system failure up to given timebound.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("time", "The timebound to use.").addValidationFunctionDouble(storm::settings::ArgumentValidators::doubleGreaterValidatorExcluding(0.0)).build()).build());
@@ -78,6 +79,20 @@ namespace storm {
                 return this->getOption(approximationErrorOptionName).getArgumentByName("error").getValueAsDouble();
             }
 
+            storm::builder::ApproximationHeuristic DFTSettings::getApproximationHeuristic() const {
+                if (!isApproximationErrorSet() || getApproximationError() == 0.0) {
+                    // No approximation is done
+                    return storm::builder::ApproximationHeuristic::NONE;
+                }
+                std::string heuristicAsString = this->getOption(approximationHeuristicOptionName).getArgumentByName("heuristic").getValueAsString();
+                if (heuristicAsString == "depth") {
+                    return storm::builder::ApproximationHeuristic::DEPTH;
+                } else if (heuristicAsString == "rateratio") {
+                    return storm::builder::ApproximationHeuristic::RATERATIO;
+                }
+                STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Illegal value '" << heuristicAsString << "' set as heuristic for approximation.");
+            }
+
             bool DFTSettings::usePropExpectedTime() const {
                 return this->getOption(propExpectedTimeOptionName).getHasOptionBeenSet();
             }
@@ -109,7 +124,6 @@ namespace storm {
 #endif
             
             void DFTSettings::finalize() {
-                
             }
 
             bool DFTSettings::check() const {
diff --git a/src/settings/modules/DFTSettings.h b/src/settings/modules/DFTSettings.h
index bb83a7475..2aa418538 100644
--- a/src/settings/modules/DFTSettings.h
+++ b/src/settings/modules/DFTSettings.h
@@ -3,6 +3,7 @@
 
 #include "storm-config.h"
 #include "src/settings/modules/ModuleSettings.h"
+#include "src/builder/DftExplorationHeuristic.h"
 
 namespace storm {
     namespace settings {
@@ -68,6 +69,13 @@ namespace storm {
                  */
                 double getApproximationError() const;
 
+                /*!
+                 * Retrieves the heuristic used for approximation.
+                 *
+                 * @return The heuristic to use.
+                 */
+                storm::builder::ApproximationHeuristic getApproximationHeuristic() const;
+
                 /*!
                  * Retrieves whether the property expected time should be used.
                  *
@@ -135,6 +143,7 @@ namespace storm {
                 static const std::string disableDCOptionName;
                 static const std::string approximationErrorOptionName;
                 static const std::string approximationErrorOptionShortName;
+                static const std::string approximationHeuristicOptionName;
                 static const std::string propExpectedTimeOptionName;
                 static const std::string propExpectedTimeOptionShortName;
                 static const std::string propProbabilityOptionName;
diff --git a/src/storage/dft/DFTState.h b/src/storage/dft/DFTState.h
index cd2b9eb0f..b49727313 100644
--- a/src/storage/dft/DFTState.h
+++ b/src/storage/dft/DFTState.h
@@ -112,6 +112,10 @@ namespace storm {
                 exploreHeuristic.setHeuristicValues(oldState->exploreHeuristic.getDepth() + 1, rate, exitRate);
             }
 
+            bool isSkip(double approximationThreshold, storm::builder::ApproximationHeuristic heuristic) {
+                return exploreHeuristic.isSkip(approximationThreshold, heuristic);
+            }
+
             double getPriority() const {
                 return exploreHeuristic.getPriority();
             }

From 2f765a9a955927dac47a71442113cd58982d1d1c Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Wed, 12 Oct 2016 08:49:33 +0200
Subject: [PATCH 19/65] Expand states reached be dependencies

Former-commit-id: ab22162ed579ccdb4678afeee6075a650c0bdd96
---
 src/storage/dft/DFTState.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/storage/dft/DFTState.h b/src/storage/dft/DFTState.h
index b49727313..617d40a7d 100644
--- a/src/storage/dft/DFTState.h
+++ b/src/storage/dft/DFTState.h
@@ -105,8 +105,8 @@ namespace storm {
             }
 
             void setHeuristicValues(std::shared_ptr<storm::storage::DFTState<ValueType>> oldState, ValueType rate, ValueType exitRate) {
-                if (hasFailed(mDft.getTopLevelIndex()) || isFailsafe(mDft.getTopLevelIndex()) || (nrFailableDependencies() == 0 && nrFailableBEs() == 0)) {
-                    // Do not skip absorbing state
+                if (hasFailed(mDft.getTopLevelIndex()) || isFailsafe(mDft.getTopLevelIndex()) || nrFailableDependencies() > 0 || (nrFailableDependencies() == 0 && nrFailableBEs() == 0)) {
+                    // Do not skip absorbing state or if reached by dependencies
                     exploreHeuristic.setNotSkip();
                 }
                 exploreHeuristic.setHeuristicValues(oldState->exploreHeuristic.getDepth() + 1, rate, exitRate);

From 3d083a171946013598fd757c94ecd07cab8fc699 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Wed, 12 Oct 2016 13:06:59 +0200
Subject: [PATCH 20/65] Fixed bug with wrong row in case of nondeterminism

Former-commit-id: 24d7bd672c3df018ab35ebc2b70190b226bbb8b9
---
 src/builder/DftExplorationHeuristic.cpp       | 2 --
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 4 ++--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/builder/DftExplorationHeuristic.cpp b/src/builder/DftExplorationHeuristic.cpp
index 74937d4b1..727c29c37 100644
--- a/src/builder/DftExplorationHeuristic.cpp
+++ b/src/builder/DftExplorationHeuristic.cpp
@@ -44,9 +44,7 @@ namespace storm {
 
         template<typename ValueType>
         void DFTExplorationHeuristic<ValueType>::setHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) {
-            std::cout << "Set priority: " << depth << ", old: " << this->depth << std::endl;
             this->depth = depth;
-            // TODO Matthias: update rates and exitRates as well
             this->rate = rate;
             this->exitRate = exitRate;
         }
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 9ed09eccb..0bf848838 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -412,7 +412,7 @@ namespace storm {
         void ExplicitDFTModelBuilderApprox<ValueType, StateType>::changeMatrixLowerBound(storm::storage::SparseMatrix<ValueType> & matrix) const {
             // Set lower bound for skipped states
             for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
-                auto matrixEntry = matrix.getRow(it->first).begin();
+                auto matrixEntry = matrix.getRow(it->first, 0).begin();
                 STORM_LOG_ASSERT(matrixEntry->getColumn() == failedStateId, "Transition has wrong target state.");
                 // Get the lower bound by considering the failure of the BE with the highest rate
                 // The list is sorted by rate, therefore we consider the first BE for the highest failure rate
@@ -424,7 +424,7 @@ namespace storm {
         void ExplicitDFTModelBuilderApprox<ValueType, StateType>::changeMatrixUpperBound(storm::storage::SparseMatrix<ValueType> & matrix) const {
             // Set uppper bound for skipped states
             for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
-                auto matrixEntry = matrix.getRow(it->first).begin();
+                auto matrixEntry = matrix.getRow(it->first, 0).begin();
                 STORM_LOG_ASSERT(matrixEntry->getColumn() == failedStateId, "Transition has wrong target state.");
                 // Get the upper bound by considering the failure of all BEs
                 // The used formula for the rate is 1/( 1/a + 1/b + ...)

From 6faa7f0429eb1f29230f93da661bbbb5b93acfe5 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Wed, 12 Oct 2016 14:23:07 +0200
Subject: [PATCH 21/65] Abort when getting infinity in approximation

Former-commit-id: 8bfda3656ac9b4ca07d2c10e56753e1b8159bcc0
---
 src/modelchecker/dft/DFTModelChecker.cpp |  1 +
 src/utility/constants.cpp                | 37 +++++++++++++++++-------
 src/utility/constants.h                  |  7 +++--
 3 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index 205e658f3..692f61735 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -187,6 +187,7 @@ namespace storm {
 
                     ++iteration;
                     STORM_LOG_INFO("Result after iteration " << iteration << ": (" << std::setprecision(10) << approxResult.first << ", " << approxResult.second << ")");
+                    STORM_LOG_THROW(!storm::utility::isInfinity<ValueType>(approxResult.first) && !storm::utility::isInfinity<ValueType>(approxResult.second), storm::exceptions::NotSupportedException, "Approximation does not work if result might be infinity.");
                 } while (!isApproximationSufficient(approxResult.first, approxResult.second, approximationError));
 
                 STORM_LOG_INFO("Finished approximation after " << iteration << " iteration" << (iteration > 1 ? "s." : "."));
diff --git a/src/utility/constants.cpp b/src/utility/constants.cpp
index c3184c194..c787b7d91 100644
--- a/src/utility/constants.cpp
+++ b/src/utility/constants.cpp
@@ -40,7 +40,11 @@ namespace storm {
             return true;
         }
 
-        
+        template<typename ValueType>
+        bool isInfinity(ValueType const& a) {
+            return a == infinity<ValueType>();
+        }
+
 #ifdef STORM_HAVE_CARL
         template<>
         bool isOne(storm::RationalFunction const& a) {
@@ -56,7 +60,7 @@ namespace storm {
         bool isConstant(storm::RationalFunction const& a) {
             return a.isConstant();
         }
-        
+
         template<>
         bool isOne(storm::Polynomial const& a) {
             return a.isOne();
@@ -71,13 +75,19 @@ namespace storm {
         bool isConstant(storm::Polynomial const& a) {
             return a.isConstant();
         }
-        
+
         template<>
         storm::RationalFunction infinity() {
             // FIXME: this should be treated more properly.
             return storm::RationalFunction(-1.0);
         }
-        
+
+        template<>
+        bool isInfinity(storm::RationalFunction const& a) {
+            // FIXME: this should be treated more properly.
+            return a == infinity<storm::RationalFunction>();
+        }
+
         template<>
         bool isOne(storm::RationalNumber const& a) {
             return carl::isOne(a);
@@ -166,7 +176,8 @@ namespace storm {
         template bool isOne(double const& value);
         template bool isZero(double const& value);
         template bool isConstant(double const& value);
-        
+        template bool isInfinity(double const& value);
+
 		template double one();
 		template double zero();
 		template double infinity();
@@ -182,7 +193,8 @@ namespace storm {
         template bool isOne(float const& value);
         template bool isZero(float const& value);
         template bool isConstant(float const& value);
-        
+        template bool isInfinity(float const& value);
+
 		template float one();
 		template float zero();
 		template float infinity();
@@ -198,7 +210,8 @@ namespace storm {
         template bool isOne(int const& value);
         template bool isZero(int const& value);
         template bool isConstant(int const& value);
-        
+        template bool isInfinity(int const& value);
+
         template int one();
         template int zero();
         template int infinity();
@@ -214,6 +227,7 @@ namespace storm {
         template bool isOne(storm::storage::sparse::state_type const& value);
         template bool isZero(storm::storage::sparse::state_type const& value);
         template bool isConstant(storm::storage::sparse::state_type const& value);
+        template bool isInfinity(storm::storage::sparse::state_type const& value);
 
         template uint32_t one();
         template uint32_t zero();
@@ -235,7 +249,8 @@ namespace storm {
         template bool isOne(RationalFunction const& value);
         template bool isZero(RationalFunction const& value);
         template bool isConstant(RationalFunction const& value);
-        
+        template bool isInfinity(RationalFunction const& value);
+
         template RationalFunction one();
         template RationalFunction zero();
         template storm::RationalFunction infinity();
@@ -251,7 +266,8 @@ namespace storm {
         template bool isOne(RationalNumber const& value);
         template bool isZero(RationalNumber const& value);
         template bool isConstant(RationalNumber const& value);
-        
+        template bool isInfinity(RationalNumber const& value);
+
         template RationalNumber one();
         template RationalNumber zero();
        
@@ -261,7 +277,8 @@ namespace storm {
         template bool isOne(Interval const& value);
         template bool isZero(Interval const& value);
         template bool isConstant(Interval const& value);
-        
+        template bool isInfinity(Interval const& value);
+
         template Interval one();
         template Interval zero();
         
diff --git a/src/utility/constants.h b/src/utility/constants.h
index 80222b74f..b80b61777 100644
--- a/src/utility/constants.h
+++ b/src/utility/constants.h
@@ -38,7 +38,10 @@ namespace storm {
         
         template<typename ValueType>
         bool isConstant(ValueType const& a);
-                
+
+        template<typename ValueType>
+        bool isInfinity(ValueType const& a);
+
         template<typename ValueType>
         ValueType pow(ValueType const& value, uint_fast64_t exponent);
         
@@ -56,4 +59,4 @@ namespace storm {
     }
 }
 
-#endif /* STORM_UTILITY_CONSTANTS_H_ */
\ No newline at end of file
+#endif /* STORM_UTILITY_CONSTANTS_H_ */

From a419cb0d8096ab8d4d0e985ecca570ea3290c06f Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Wed, 12 Oct 2016 18:18:30 +0200
Subject: [PATCH 22/65] Fixed computing rates for lower and upper bound

Former-commit-id: 89846a97885f5119d3082dce17982576755c0f4c
---
 src/builder/ExplicitDFTModelBuilder.cpp       |  2 +-
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 15 +++-
 src/generator/DftNextStateGenerator.cpp       |  2 +-
 src/modelchecker/dft/DFTModelChecker.cpp      | 10 ++-
 src/storage/dft/DFT.h                         |  4 +-
 src/storage/dft/DFTState.cpp                  | 72 ++++++++++++++-----
 src/storage/dft/DFTState.h                    | 71 ++++++++++++++----
 7 files changed, 136 insertions(+), 40 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilder.cpp b/src/builder/ExplicitDFTModelBuilder.cpp
index 46797aa23..9481e3392 100644
--- a/src/builder/ExplicitDFTModelBuilder.cpp
+++ b/src/builder/ExplicitDFTModelBuilder.cpp
@@ -290,7 +290,7 @@ namespace storm {
                     if (mDft.hasRepresentant(nextBE->id())) {
                         // Active must be checked for the state we are coming from as this state is responsible for the
                         // rate and not the new state we are going to
-                        isActive = state->isActive(mDft.getRepresentant(nextBE->id())->id());
+                        isActive = state->isActive(mDft.getRepresentant(nextBE->id()));
                     }
                     ValueType rate = isActive ? nextBE->activeFailureRate() : nextBE->passiveFailureRate();
                     STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Rate is 0.");
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 0bf848838..1f702d270 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -414,9 +414,15 @@ namespace storm {
             for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
                 auto matrixEntry = matrix.getRow(it->first, 0).begin();
                 STORM_LOG_ASSERT(matrixEntry->getColumn() == failedStateId, "Transition has wrong target state.");
-                // Get the lower bound by considering the failure of the BE with the highest rate
-                // The list is sorted by rate, therefore we consider the first BE for the highest failure rate
-                matrixEntry->setValue(it->second->getFailableBERate(0));
+                // Get the lower bound by considering the failure of all possible BEs
+                ValueType newRate = storm::utility::zero<ValueType>();
+                for (size_t index = 0; index < it->second->nrFailableBEs(); ++index) {
+                    newRate += it->second->getFailableBERate(index);
+                }
+                for (size_t index = 0; index < it->second->nrNotFailableBEs(); ++index) {
+                    newRate += it->second->getNotFailableBERate(index);
+                }
+                matrixEntry->setValue(newRate);
             }
         }
 
@@ -433,6 +439,9 @@ namespace storm {
                 for (size_t index = 0; index < it->second->nrFailableBEs(); ++index) {
                     newRate += storm::utility::one<ValueType>() / it->second->getFailableBERate(index);
                 }
+                for (size_t index = 0; index < it->second->nrNotFailableBEs(); ++index) {
+                    newRate += storm::utility::one<ValueType>() / it->second->getNotFailableBERate(index);
+                }
                 newRate = storm::utility::one<ValueType>() / newRate;
                 matrixEntry->setValue(newRate);
             }
diff --git a/src/generator/DftNextStateGenerator.cpp b/src/generator/DftNextStateGenerator.cpp
index 31d17fbe0..e61e8e331 100644
--- a/src/generator/DftNextStateGenerator.cpp
+++ b/src/generator/DftNextStateGenerator.cpp
@@ -168,7 +168,7 @@ namespace storm {
                     bool isActive = true;
                     if (mDft.hasRepresentant(nextBE->id())) {
                         // Active must be checked for the state we are coming from as this state is responsible for the rate
-                        isActive = state->isActive(mDft.getRepresentant(nextBE->id())->id());
+                        isActive = state->isActive(mDft.getRepresentant(nextBE->id()));
                     }
                     ValueType rate = isActive ? nextBE->activeFailureRate() : nextBE->passiveFailureRate();
                     STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Rate is 0.");
diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index 692f61735..26f2033d6 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -147,6 +147,8 @@ namespace storm {
             buildingTime += buildingEnd - buildingStart;
 
             if (approximationError > 0.0) {
+                // Comparator for checking the error of the approximation
+                storm::utility::ConstantsComparator<ValueType> comparator;
                 // Build approximate Markov Automata for lower and upper bound
                 double currentApproximationError = approximationError;
                 approximation_result approxResult = std::make_pair(storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>());
@@ -173,7 +175,9 @@ namespace storm {
                     // Check lower bound
                     std::unique_ptr<storm::modelchecker::CheckResult> result = checkModel(model, formula);
                     result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
-                    approxResult.first = result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second;
+                    ValueType newResult = result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second;
+                    STORM_LOG_ASSERT(iteration == 0 || !comparator.isLess(newResult, approxResult.first), "New under-approximation " << newResult << " is smaller than old result " << approxResult.first);
+                    approxResult.first = newResult;
 
                     // Build model for upper bound
                     STORM_LOG_INFO("Getting model for upper bound...");
@@ -183,7 +187,9 @@ namespace storm {
                     // Check upper bound
                     result = checkModel(model, formula);
                     result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
-                    approxResult.second = result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second;
+                    newResult = result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second;
+                    STORM_LOG_ASSERT(iteration == 0 || !comparator.isLess(approxResult.second, newResult), "New over-approximation " << newResult << " is greater than old result " << approxResult.second);
+                    approxResult.second = newResult;
 
                     ++iteration;
                     STORM_LOG_INFO("Result after iteration " << iteration << ": (" << std::setprecision(10) << approxResult.first << ", " << approxResult.second << ")");
diff --git a/src/storage/dft/DFT.h b/src/storage/dft/DFT.h
index c12204e06..7620a059a 100644
--- a/src/storage/dft/DFT.h
+++ b/src/storage/dft/DFT.h
@@ -216,9 +216,9 @@ namespace storm {
                 return mRepresentants.find(id) != mRepresentants.end();
             }
 
-            DFTElementCPointer getRepresentant(size_t id) const {
+            size_t getRepresentant(size_t id) const {
                 STORM_LOG_ASSERT(hasRepresentant(id), "Element has no representant.");
-                return getElement(mRepresentants.find(id)->second);
+                return mRepresentants.find(id)->second;
             }
 
             bool hasFailed(DFTStatePointer const& state) const {
diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index 5e84b0c56..b292e322d 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -9,18 +9,29 @@ namespace storm {
         DFTState<ValueType>::DFTState(DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(dft.stateVectorSize()), mId(id), mDft(dft), mStateGenerationInfo(stateGenerationInfo), exploreHeuristic()  {
             
             // Initialize uses
-            for(size_t spareId  : mDft.getSpareIndices()) {
+            for(size_t spareId : mDft.getSpareIndices()) {
                 std::shared_ptr<DFTGate<ValueType> const> elem = mDft.getGate(spareId);
                 STORM_LOG_ASSERT(elem->isSpareGate(), "Element is no spare gate.");
                 STORM_LOG_ASSERT(elem->nrChildren() > 0, "Element has no child.");
                 this->setUses(spareId, elem->children()[0]->id());
             }
-            
+
+            for (auto elem : mDft.getBasicElements()) {
+                mCurrentlyNotFailableBE.push_back(elem->id());
+            }
+
             // Initialize activation
             propagateActivation(mDft.getTopLevelIndex());
 
-            std::vector<size_t> alwaysActiveBEs = dft.nonColdBEs();
-            mIsCurrentlyFailableBE.insert(mIsCurrentlyFailableBE.end(), alwaysActiveBEs.begin(), alwaysActiveBEs.end());
+            std::vector<size_t> alwaysActiveBEs = mDft.nonColdBEs();
+            mCurrentlyFailableBE.insert(mCurrentlyFailableBE.end(), alwaysActiveBEs.begin(), alwaysActiveBEs.end());
+            // Remove always active BEs from currently not failable BEs
+            for (size_t id : alwaysActiveBEs) {
+                auto it = std::find(mCurrentlyNotFailableBE.begin(), mCurrentlyNotFailableBE.end(), id);
+                STORM_LOG_ASSERT(it != mCurrentlyNotFailableBE.end(), "Id not found.");
+                mCurrentlyNotFailableBE.erase(it);
+            }
+
             sortFailableBEs();
         }
         
@@ -31,9 +42,13 @@ namespace storm {
                 // Initialize currently failable BE
                 if (mDft.isBasicElement(index) && isOperational(index)) {
                     std::shared_ptr<const DFTBE<ValueType>> be = mDft.getBasicElement(index);
-                    if ((!be->isColdBasicElement() && be->canFail()) || !mDft.hasRepresentant(index) || isActive(mDft.getRepresentant(index)->id())) {
-                        mIsCurrentlyFailableBE.push_back(index);
+                    if ((!be->isColdBasicElement() && be->canFail()) || !mDft.hasRepresentant(index) || isActive(mDft.getRepresentant(index))) {
+                        mCurrentlyFailableBE.push_back(index);
                         STORM_LOG_TRACE("Currently failable: " << mDft.getBasicElement(index)->toString());
+                    } else {
+                        // BE currently is not failable
+                        mCurrentlyNotFailableBE.push_back(index);
+                        STORM_LOG_TRACE("Currently not failable: " << mDft.getBasicElement(index)->toString());
                     }
                 } else if (mDft.getElement(index)->isSpareGate()) {
                     // Initialize used representants
@@ -176,9 +191,9 @@ namespace storm {
 
         template<typename ValueType>
         void DFTState<ValueType>::beNoLongerFailable(size_t id) {
-            auto it = std::find(mIsCurrentlyFailableBE.begin(), mIsCurrentlyFailableBE.end(), id);
-            if(it != mIsCurrentlyFailableBE.end()) {
-                mIsCurrentlyFailableBE.erase(it);
+            auto it = std::find(mCurrentlyFailableBE.begin(), mCurrentlyFailableBE.end(), id);
+            if(it != mCurrentlyFailableBE.end()) {
+                mCurrentlyFailableBE.erase(it);
             }
         }
 
@@ -210,11 +225,29 @@ namespace storm {
             }
         }
 
+        template<typename ValueType>
+        ValueType DFTState<ValueType>::getBERate(size_t id, bool considerPassive) const {
+            STORM_LOG_ASSERT(mDft.isBasicElement(id), "Element is no BE.");
+            if (considerPassive && mDft.hasRepresentant(id) && !isActive(mDft.getRepresentant(id))) {
+                return mDft.getBasicElement(id)->passiveFailureRate();
+            } else {
+                return mDft.getBasicElement(id)->activeFailureRate();
+            }
+        }
+
         template<typename ValueType>
         ValueType DFTState<ValueType>::getFailableBERate(size_t index) const {
             STORM_LOG_ASSERT(index < nrFailableBEs(), "Index invalid.");
-            // TODO Matthias: get passive failure rate when applicable
-            return mDft.getBasicElement(mIsCurrentlyFailableBE[index])->activeFailureRate();
+            return getBERate(mCurrentlyFailableBE[index], true);
+        }
+
+        template<typename ValueType>
+        ValueType DFTState<ValueType>::getNotFailableBERate(size_t index) const {
+            STORM_LOG_ASSERT(index < nrNotFailableBEs(), "Index invalid.");
+            STORM_LOG_ASSERT(storm::utility::isZero<ValueType>(mDft.getBasicElement(mCurrentlyNotFailableBE[index])->activeFailureRate()) ||
+                             (mDft.hasRepresentant(mCurrentlyNotFailableBE[index]) && !isActive(mDft.getRepresentant(mCurrentlyNotFailableBE[index]))), "BE " << mCurrentlyNotFailableBE[index] << " can fail");
+            // Use active failure rate as passive failure rate is 0.
+            return getBERate(mCurrentlyNotFailableBE[index], false);
         }
 
         template<typename ValueType>
@@ -232,9 +265,9 @@ namespace storm {
             } else {
                 // Consider "normal" failure
                 STORM_LOG_ASSERT(index < nrFailableBEs(), "Index invalid.");
-                std::pair<std::shared_ptr<DFTBE<ValueType> const>,bool> res(mDft.getBasicElement(mIsCurrentlyFailableBE[index]), false);
+                std::pair<std::shared_ptr<DFTBE<ValueType> const>,bool> res(mDft.getBasicElement(mCurrentlyFailableBE[index]), false);
                 STORM_LOG_ASSERT(res.first->canFail(), "Element cannot fail.");
-                mIsCurrentlyFailableBE.erase(mIsCurrentlyFailableBE.begin() + index);
+                mCurrentlyFailableBE.erase(mCurrentlyFailableBE.begin() + index);
                 setFailed(res.first->id());
                 return res;
             }
@@ -269,7 +302,12 @@ namespace storm {
                 if(mDft.isBasicElement(elem) && isOperational(elem)) {
                     std::shared_ptr<const DFTBE<ValueType>> be = mDft.getBasicElement(elem);
                     if (be->isColdBasicElement() && be->canFail()) {
-                        mIsCurrentlyFailableBE.push_back(elem);
+                        // Add to failable BEs
+                        mCurrentlyFailableBE.push_back(elem);
+                        // Remove from not failable BEs
+                        auto it = std::find(mCurrentlyNotFailableBE.begin(), mCurrentlyNotFailableBE.end(), elem);
+                        STORM_LOG_ASSERT(it != mCurrentlyNotFailableBE.end(), "Element not found.");
+                        mCurrentlyNotFailableBE.erase(it);
                     }
                 } else if (mDft.getElement(elem)->isSpareGate() && !isActive(uses(elem))) {
                     propagateActivation(uses(elem));
@@ -373,11 +411,9 @@ namespace storm {
         
         template<typename ValueType>
         void DFTState<ValueType>::sortFailableBEs() {
-            std::sort( mIsCurrentlyFailableBE.begin( ), mIsCurrentlyFailableBE.end( ), [&](size_t const& lhs, size_t const& rhs) {
-                ValueType leftRate = mDft.getBasicElement(lhs)->activeFailureRate();
-                ValueType rightRate = mDft.getBasicElement(rhs)->activeFailureRate();
+            std::sort(mCurrentlyFailableBE.begin( ), mCurrentlyFailableBE.end( ), [&](size_t const& lhs, size_t const& rhs) {
                 // Sort decreasing
-                return rightRate < leftRate;
+                return getBERate(rhs, true) < getBERate(lhs, true);
             });
         }
 
diff --git a/src/storage/dft/DFTState.h b/src/storage/dft/DFTState.h
index 617d40a7d..a6644f349 100644
--- a/src/storage/dft/DFTState.h
+++ b/src/storage/dft/DFTState.h
@@ -26,7 +26,8 @@ namespace storm {
             // Status is bitvector where each element has two bits with the meaning according to DFTElementState
             storm::storage::BitVector mStatus;
             size_t mId;
-            std::vector<size_t> mIsCurrentlyFailableBE;
+            std::vector<size_t> mCurrentlyFailableBE;
+            std::vector<size_t> mCurrentlyNotFailableBE;
             std::vector<size_t> mFailableDependencies;
             std::vector<size_t> mUsedRepresentants;
             bool mValid = true;
@@ -158,25 +159,58 @@ namespace storm {
              * @param spareId Id of the spare
              */
             void finalizeUses(size_t spareId);
-            
+
+            /**
+             * Claim a new spare child for the given spare gate.
+             *
+             * @param spareId       Id of the spare gate.
+             * @param currentlyUses Id of the currently used spare child.
+             * @param children      List of children of this spare.
+             *
+             * @return True, if claiming was successful.
+             */
             bool claimNew(size_t spareId, size_t currentlyUses, std::vector<std::shared_ptr<DFTElement<ValueType>>> const& children);
             
-            bool hasOutgoingEdges() const {
-                return !mIsCurrentlyFailableBE.empty();
-            }
-            
+            /**
+             * Get number of currently failable BEs.
+             *
+             * @return Number of failable BEs.
+             */
             size_t nrFailableBEs() const {
-                return mIsCurrentlyFailableBE.size();
+                return mCurrentlyFailableBE.size();
+            }
+
+            /**
+             * Get number of currently not failable BEs. These are cold BE which can fail in the future.
+             *
+             * @return Number of not failable BEs.
+             */
+            size_t nrNotFailableBEs() const {
+                return mCurrentlyNotFailableBE.size();
             }
 
-            /** Get the failure rate of the currently failable BE on the given index.
+            /**
+             * Get the failure rate of the currently failable BE on the given index.
              *
-             * @param index Index of BE in list of currently failable BEs.
+             * @param index           Index of BE in list of currently failable BEs.
              *
              * @return Failure rate of the BE.
              */
             ValueType getFailableBERate(size_t index) const;
 
+            /**
+             * Get the failure rate of the currently not failable BE on the given index.
+             *
+             * @param index Index of BE in list of currently not failable BEs.
+             *
+             * @return Failure rate of the BE.
+             */
+            ValueType getNotFailableBERate(size_t index) const;
+
+            /** Get number of currently failable dependencies.
+             *
+             * @return Number of failable dependencies.
+             */
             size_t nrFailableDependencies() const {
                 return mFailableDependencies.size();
             }
@@ -245,13 +279,13 @@ namespace storm {
                     }
                     stream << "} ";
                 } else {
-                    auto it = mIsCurrentlyFailableBE.begin();
+                    auto it = mCurrentlyFailableBE.begin();
                     stream << "{";
-                    if(it != mIsCurrentlyFailableBE.end()) {
+                    if(it != mCurrentlyFailableBE.end()) {
                         stream << *it;
                     }
                     ++it;
-                    while(it != mIsCurrentlyFailableBE.end()) {
+                    while(it != mCurrentlyFailableBE.end()) {
                         stream << ", " << *it;
                         ++it;
                     }
@@ -266,7 +300,18 @@ namespace storm {
             
         private:
             void propagateActivation(size_t representativeId);
-            
+
+            /**
+             * Get the failure rate of the given BE.
+             *
+             * @param id              Id of BE.
+             * @param considerPassive Flag indicating if the passive failure rate should be returned if
+             *                        the BE currently is passive.
+             *
+             * @return Failure rate of the BE.
+             */
+            ValueType getBERate(size_t id, bool considerPassive) const;
+
             /*!
              * Sort failable BEs in decreasing order of their active failure rate.
              */

From ea00abc35eba8f83b5bc41e6d0ed07592fdf2528 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Thu, 13 Oct 2016 13:12:16 +0200
Subject: [PATCH 23/65] Fixed problems with approximation while using symred

Former-commit-id: df12c037e731f08e7072e2d74abf64a5ce5c11f7
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 30 ++++++++++++-------
 src/storage/dft/DFTState.cpp                  |  2 +-
 src/utility/vector.cpp                        | 14 +++++----
 3 files changed, 29 insertions(+), 17 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 1f702d270..ac26129df 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -82,18 +82,23 @@ namespace storm {
             modelComponents.deterministicModel = generator.isDeterministicModel();
 
             // Replace pseudo states in matrix
-            // TODO Matthias: avoid hack with fixed int type
-            std::vector<uint_fast64_t> pseudoStatesVector;
-            for (auto const& pseudoStatePair : mPseudoStatesMapping) {
-                pseudoStatesVector.push_back(pseudoStatePair.first);
+            if (!mPseudoStatesMapping.empty()) {
+                // TODO Matthias: avoid hack with fixed int type
+                std::vector<uint_fast64_t> pseudoStatesVector;
+                for (auto const& pseudoStatePair : mPseudoStatesMapping) {
+                    pseudoStatesVector.push_back(matrixBuilder.mappingOffset + pseudoStatePair.first);
+                }
+                STORM_LOG_ASSERT(std::find(pseudoStatesVector.begin(), pseudoStatesVector.end(), 0) == pseudoStatesVector.end(), "Unexplored pseudo state still contained.");
+                STORM_LOG_TRACE("Replace pseudo states: " << pseudoStatesVector << ", offset: " << OFFSET_PSEUDO_STATE);
+                // TODO Matthias: combine replacement with later one
+                matrixBuilder.builder.replaceColumns(pseudoStatesVector, OFFSET_PSEUDO_STATE);
+                mPseudoStatesMapping.clear();
             }
-            STORM_LOG_ASSERT(std::find(pseudoStatesVector.begin(), pseudoStatesVector.end(), 0) == pseudoStatesVector.end(), "Unexplored pseudo state still contained.");
-            matrixBuilder.builder.replaceColumns(pseudoStatesVector, OFFSET_PSEUDO_STATE);
-            mPseudoStatesMapping.clear();
 
             // Fix the entries in the transition matrix according to the mapping of ids to row group indices
             STORM_LOG_ASSERT(matrixBuilder.stateRemapping[initialStateIndex] == initialStateIndex, "Initial state should not be remapped.");
             // TODO Matthias: do not consider all rows?
+            STORM_LOG_TRACE("Remap matrix: " << matrixBuilder.stateRemapping << ", offset: " << matrixBuilder.mappingOffset);
             matrixBuilder.remap();
 
             STORM_LOG_TRACE("State remapping: " << matrixBuilder.stateRemapping);
@@ -251,10 +256,9 @@ namespace storm {
                     for (auto const& choice : behavior) {
                         // Add the probabilistic behavior to the matrix.
                         for (auto const& stateProbabilityPair : choice) {
-
-                            // Check that pseudo state and its instantiation do not appear together
-                            // TODO Matthias: prove that this is not possible and remove
                             if (stateProbabilityPair.first >= OFFSET_PSEUDO_STATE) {
+                                // Check that pseudo state and its instantiation do not appear together
+                                // TODO Matthias: prove that this is not possible and remove
                                 StateType newId = stateProbabilityPair.first - OFFSET_PSEUDO_STATE;
                                 STORM_LOG_ASSERT(newId < mPseudoStatesMapping.size(), "Id is not valid.");
                                 if (mPseudoStatesMapping[newId].first > 0) {
@@ -264,8 +268,12 @@ namespace storm {
                                         STORM_LOG_ASSERT(itFind->first != newId, "Pseudo state and instantiation occur together in a distribution.");
                                     }
                                 }
+                                // Set transtion to pseudo state
+                                matrixBuilder.addTransition(stateProbabilityPair.first, stateProbabilityPair.second);
+                            } else {
+                                // Set transition to state id + offset. This helps in only remapping all previously skipped states.
+                                matrixBuilder.addTransition(matrixBuilder.mappingOffset + stateProbabilityPair.first, stateProbabilityPair.second);
                             }
-                            matrixBuilder.addTransition(matrixBuilder.mappingOffset + stateProbabilityPair.first, stateProbabilityPair.second);
                         }
                         matrixBuilder.finishRow();
                     }
diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index b292e322d..208dd6bf0 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -36,7 +36,7 @@ namespace storm {
         }
         
         template<typename ValueType>
-        DFTState<ValueType>::DFTState(storm::storage::BitVector const& status, DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(status), mId(id), mDft(dft), mStateGenerationInfo(stateGenerationInfo) {
+        DFTState<ValueType>::DFTState(storm::storage::BitVector const& status, DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(status), mId(id), mDft(dft), mStateGenerationInfo(stateGenerationInfo), exploreHeuristic() {
             
             for(size_t index = 0; index < mDft.nrElements(); ++index) {
                 // Initialize currently failable BE
diff --git a/src/utility/vector.cpp b/src/utility/vector.cpp
index 44e480029..595af193e 100644
--- a/src/utility/vector.cpp
+++ b/src/utility/vector.cpp
@@ -20,20 +20,24 @@ template std::ostream& operator<<(std::ostream& out, std::vector<uint_fast64_t>
 
 std::ostream& operator<<(std::ostream& out, std::vector<double> const& vector) {
     out << "vector (" << vector.size() << ") [ ";
-    for (uint_fast64_t i = 0; i < vector.size() - 1; ++i) {
+    for (size_t i = 0; i + 1 < vector.size(); ++i) {
         out << vector[i] << ", ";
     }
-    out << vector.back();
+    if (!vector.empty()) {
+        out << vector.back();
+    }
     out << " ]";
     return out;
 }
 
 std::ostream& operator<<(std::ostream& out, std::vector<uint_fast64_t> const& vector) {
     out << "vector (" << vector.size() << ") [ ";
-    for (uint_fast64_t i = 0; i < vector.size() - 1; ++i) {
+    for (size_t i = 0; i + 1 < vector.size(); ++i) {
         out << vector[i] << ", ";
     }
-    out << vector.back();
+    if (!vector.empty()) {
+        out << vector.back();
+    }
     out << " ]";
     return out;
-}
\ No newline at end of file
+}

From faadf19228bbedc42569b731421d83788cd4b78a Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Thu, 13 Oct 2016 15:09:09 +0200
Subject: [PATCH 24/65] Approximation error is relative to mean of lower and
 upper bound

Former-commit-id: f01c027a3a2d083dd45dcae15aab256e6d44c97f
---
 src/modelchecker/dft/DFTModelChecker.cpp | 2 +-
 src/modelchecker/dft/DFTModelChecker.h   | 3 ++-
 src/settings/modules/DFTSettings.cpp     | 2 +-
 src/settings/modules/DFTSettings.h       | 2 +-
 4 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index 26f2033d6..717ace4c3 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -254,7 +254,7 @@ namespace storm {
 
         template<>
         bool DFTModelChecker<double>::isApproximationSufficient(double lowerBound, double upperBound, double approximationError) {
-            return upperBound - lowerBound <= approximationError;
+            return upperBound - lowerBound <= approximationError * (lowerBound + upperBound) / 2;
         }
 
         template<typename ValueType>
diff --git a/src/modelchecker/dft/DFTModelChecker.h b/src/modelchecker/dft/DFTModelChecker.h
index 62bb5afe4..83df59bfa 100644
--- a/src/modelchecker/dft/DFTModelChecker.h
+++ b/src/modelchecker/dft/DFTModelChecker.h
@@ -106,7 +106,8 @@ namespace storm {
             std::unique_ptr<storm::modelchecker::CheckResult> checkModel(std::shared_ptr<storm::models::sparse::Model<ValueType>>& model, std::shared_ptr<const storm::logic::Formula> const& formula);
 
             /*!
-             * Checks if the computed approximation is sufficient, i.e. upperBound - lowerBound <= approximationError.
+             * Checks if the computed approximation is sufficient, i.e.
+             * upperBound - lowerBound <= approximationError * mean(upperBound, lowerBound).
              *
              * @param lowerBound         The lower bound on the result.
              * @param upperBound         The upper bound on the result.
diff --git a/src/settings/modules/DFTSettings.cpp b/src/settings/modules/DFTSettings.cpp
index 1b3f0bae2..0dcb49f1d 100644
--- a/src/settings/modules/DFTSettings.cpp
+++ b/src/settings/modules/DFTSettings.cpp
@@ -39,7 +39,7 @@ namespace storm {
                 this->addOption(storm::settings::OptionBuilder(moduleName, symmetryReductionOptionName, false, "Exploit symmetric structure of model.").setShortName(symmetryReductionOptionShortName).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, modularisationOptionName, false, "Use modularisation (not applicable for expected time).").build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, disableDCOptionName, false, "Disable Dont Care propagation.").build());
-                this->addOption(storm::settings::OptionBuilder(moduleName, approximationErrorOptionName, false, "Approximation error allowed.").setShortName(approximationErrorOptionShortName).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("error", "The approximation error to use.").addValidationFunctionDouble(storm::settings::ArgumentValidators::doubleGreaterValidatorIncluding(0.0)).build()).build());
+                this->addOption(storm::settings::OptionBuilder(moduleName, approximationErrorOptionName, false, "Approximation error allowed.").setShortName(approximationErrorOptionShortName).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("error", "The relative approximation error to use.").addValidationFunctionDouble(storm::settings::ArgumentValidators::doubleGreaterValidatorIncluding(0.0)).build()).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, approximationHeuristicOptionName, false, "Set the heuristic used for approximation.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("heuristic", "Sets which heuristic is used for approximation. Must be in {depth, rateratio}. Default is").setDefaultValueString("depth").addValidationFunctionString(storm::settings::ArgumentValidators::stringInListValidator({"depth", "rateratio"})).build()).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, propExpectedTimeOptionName, false, "Compute expected time of system failure.").setShortName(propExpectedTimeOptionShortName).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, propProbabilityOptionName, false, "Compute probability of system failure.").build());
diff --git a/src/settings/modules/DFTSettings.h b/src/settings/modules/DFTSettings.h
index 2aa418538..e580a5d05 100644
--- a/src/settings/modules/DFTSettings.h
+++ b/src/settings/modules/DFTSettings.h
@@ -63,7 +63,7 @@ namespace storm {
                 bool isApproximationErrorSet() const;
 
                 /*!
-                 * Retrieves the error allowed for approximation the model checking result.
+                 * Retrieves the relative error allowed for approximating the model checking result.
                  *
                  * @return The allowed errorbound.
                  */

From e05c4dab0dfdb2d6a7f923867052f74e5ff39c75 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Thu, 13 Oct 2016 16:00:32 +0200
Subject: [PATCH 25/65] Use custom DynamicPriorityQueue

Former-commit-id: b4b552a84d9f43880bc0c37b19b4edd90f3b6ddf
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 18 +++--
 src/builder/ExplicitDFTModelBuilderApprox.h   |  3 +-
 src/storage/DynamicPriorityQueue.h            | 67 +++++++++++++++++++
 3 files changed, 81 insertions(+), 7 deletions(-)
 create mode 100644 src/storage/DynamicPriorityQueue.h

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index ac26129df..88af5276d 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -23,14 +23,17 @@ namespace storm {
         }
 
         template<typename ValueType, typename StateType>
-        ExplicitDFTModelBuilderApprox<ValueType, StateType>::ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC) : dft(dft), stateGenerationInfo(std::make_shared<storm::storage::DFTStateGenerationInfo>(dft.buildStateGenerationInfo(symmetries))), enableDC(enableDC), generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates), matrixBuilder(!generator.isDeterministicModel()), stateStorage(((dft.stateVectorSize() / 64) + 1) * 64) {
+        ExplicitDFTModelBuilderApprox<ValueType, StateType>::ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC) :
+                dft(dft),
+                stateGenerationInfo(std::make_shared<storm::storage::DFTStateGenerationInfo>(dft.buildStateGenerationInfo(symmetries))),
+                enableDC(enableDC),
+                generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates),
+                matrixBuilder(!generator.isDeterministicModel()),
+                stateStorage(((dft.stateVectorSize() / 64) + 1) * 64),
+                statesToExplore(storm::storage::DynamicPriorityQueue<DFTStatePointer, std::vector<DFTStatePointer>, std::function<bool(DFTStatePointer, DFTStatePointer)>>(&storm::builder::compareDepth<ValueType>))
+        {
             // stateVectorSize is bound for size of bitvector
-
             heuristic = storm::settings::getModule<storm::settings::modules::DFTSettings>().getApproximationHeuristic();
-
-            // Compare states by their distance from the initial state
-            // TODO Matthias: customize
-            statesToExplore = std::priority_queue<DFTStatePointer, std::deque<DFTStatePointer>, std::function<bool(DFTStatePointer, DFTStatePointer)>>(&storm::builder::compareDepth<ValueType>);
         }
 
         template<typename ValueType, typename StateType>
@@ -279,6 +282,9 @@ namespace storm {
                     }
                 }
 
+                // Update priority queue
+                statesToExplore.fix();
+
                 if (statesToExplore.empty()) {
                     explorationFinished = true;
                     // Before ending the exploration check for pseudo states which are not initialized yet
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index cb9a444af..9dfb3f63d 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -10,6 +10,7 @@
 #include "src/storage/sparse/StateStorage.h"
 #include "src/storage/dft/DFT.h"
 #include "src/storage/dft/SymmetricUnits.h"
+#include "src/storage/DynamicPriorityQueue.h"
 #include <boost/container/flat_set.hpp>
 #include <boost/optional/optional.hpp>
 #include <stack>
@@ -286,7 +287,7 @@ namespace storm {
             storm::storage::sparse::StateStorage<StateType> stateStorage;
 
             // A pniority queue of states that still need to be explored.
-            std::priority_queue<DFTStatePointer, std::deque<DFTStatePointer>, std::function<bool(DFTStatePointer, DFTStatePointer)>> statesToExplore;
+            storm::storage::DynamicPriorityQueue<DFTStatePointer, std::vector<DFTStatePointer>, std::function<bool(DFTStatePointer, DFTStatePointer)>> statesToExplore;
 
             // Holds all skipped states which were not yet expanded. More concretely it is a mapping from matrix indices
             // to the corresponding skipped states.
diff --git a/src/storage/DynamicPriorityQueue.h b/src/storage/DynamicPriorityQueue.h
new file mode 100644
index 000000000..a416a89b6
--- /dev/null
+++ b/src/storage/DynamicPriorityQueue.h
@@ -0,0 +1,67 @@
+#ifndef STORM_STORAGE_DYNAMICPRIORITYQUEUE_H_
+#define STORM_STORAGE_DYNAMICPRIORITYQUEUE_H_
+
+#include <algorithm>
+#include <vector>
+
+namespace storm {
+    namespace storage {
+
+        template<typename T, typename Container = std::vector<T>, typename Compare = std::less<T>>
+        class DynamicPriorityQueue {
+
+        private:
+            Container container;
+            Compare compare;
+
+        public:
+            explicit DynamicPriorityQueue(const Compare& compare) : container(), compare(compare) {
+                // Intentionally left empty
+            }
+
+            explicit DynamicPriorityQueue(Container&& container, const Compare& compare) : container(std::move(container)), compare(compare) {
+                std::make_heap(container.begin(), container.end(), compare);
+            }
+
+            void fix() {
+                std::make_heap(container.begin(), container.end(), compare);
+            }
+
+            bool empty() const {
+                return container.empty();
+            }
+
+            std::size_t size() const {
+                return container.size();
+            }
+
+            const T& top() const {
+                return container.front();
+            }
+
+            void push(const T& item) {
+                container.push_back(item);
+                std::push_heap(container.begin(), container.end(), compare);
+            }
+
+            void push(T&& item) {
+                container.push_back(std::move(item));
+                std::push_heap(container.begin(), container.end(), compare);
+            }
+
+            void pop() {
+                std::pop_heap(container.begin(), container.end(), compare);
+                container.pop_back();
+            }
+
+            T popTop() {
+                T item = top();
+                pop();
+                return item;
+            }
+
+        };
+    }
+}
+
+#endif // STORM_STORAGE_DYNAMICPRIORITYQUEUE_H_

From 8e1e61c4f249b92fcb33f158fd805de34b58d552 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Fri, 14 Oct 2016 18:59:45 +0200
Subject: [PATCH 26/65] Changed datastructures and made handling of pseudo
 states easier

Former-commit-id: a0e0324fe6d25f63312edac06fb4d8871bb26f7d
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 169 +++++++-----------
 src/builder/ExplicitDFTModelBuilderApprox.h   |  21 ++-
 src/storage/DynamicPriorityQueue.h            |   4 +-
 src/storage/dft/DFTState.cpp                  |  17 +-
 src/storage/dft/DFTState.h                    |  26 ++-
 5 files changed, 119 insertions(+), 118 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 88af5276d..76ace8dda 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -27,13 +27,15 @@ namespace storm {
                 dft(dft),
                 stateGenerationInfo(std::make_shared<storm::storage::DFTStateGenerationInfo>(dft.buildStateGenerationInfo(symmetries))),
                 enableDC(enableDC),
+                heuristic(storm::settings::getModule<storm::settings::modules::DFTSettings>().getApproximationHeuristic()),
                 generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates),
                 matrixBuilder(!generator.isDeterministicModel()),
                 stateStorage(((dft.stateVectorSize() / 64) + 1) * 64),
-                statesToExplore(storm::storage::DynamicPriorityQueue<DFTStatePointer, std::vector<DFTStatePointer>, std::function<bool(DFTStatePointer, DFTStatePointer)>>(&storm::builder::compareDepth<ValueType>))
+                explorationQueue([this](StateType idA, StateType idB) {
+                        return isPriorityGreater(idA, idB);
+                    })
         {
-            // stateVectorSize is bound for size of bitvector
-            heuristic = storm::settings::getModule<storm::settings::modules::DFTSettings>().getApproximationHeuristic();
+            // Intentionally left empty.
         }
 
         template<typename ValueType, typename StateType>
@@ -84,20 +86,6 @@ namespace storm {
             modelComponents.markovianStates.resize(stateSize);
             modelComponents.deterministicModel = generator.isDeterministicModel();
 
-            // Replace pseudo states in matrix
-            if (!mPseudoStatesMapping.empty()) {
-                // TODO Matthias: avoid hack with fixed int type
-                std::vector<uint_fast64_t> pseudoStatesVector;
-                for (auto const& pseudoStatePair : mPseudoStatesMapping) {
-                    pseudoStatesVector.push_back(matrixBuilder.mappingOffset + pseudoStatePair.first);
-                }
-                STORM_LOG_ASSERT(std::find(pseudoStatesVector.begin(), pseudoStatesVector.end(), 0) == pseudoStatesVector.end(), "Unexplored pseudo state still contained.");
-                STORM_LOG_TRACE("Replace pseudo states: " << pseudoStatesVector << ", offset: " << OFFSET_PSEUDO_STATE);
-                // TODO Matthias: combine replacement with later one
-                matrixBuilder.builder.replaceColumns(pseudoStatesVector, OFFSET_PSEUDO_STATE);
-                mPseudoStatesMapping.clear();
-            }
-
             // Fix the entries in the transition matrix according to the mapping of ids to row group indices
             STORM_LOG_ASSERT(matrixBuilder.stateRemapping[initialStateIndex] == initialStateIndex, "Initial state should not be remapped.");
             // TODO Matthias: do not consider all rows?
@@ -125,6 +113,14 @@ namespace storm {
         void ExplicitDFTModelBuilderApprox<ValueType, StateType>::initializeNextIteration() {
             STORM_LOG_TRACE("Refining DFT state space");
 
+            // TODO Matthias: should be easier now as skipped states all are at the end of the matrix
+            // Push skipped states to explore queue
+            // TODO Matthias: remove
+            for (auto const& skippedState : skippedStates) {
+                statesNotExplored[skippedState.second->getId()] = skippedState.second;
+                explorationQueue.push(skippedState.second->getId());
+            }
+
             // Initialize matrix builder again
             // TODO Matthias: avoid copy
             std::vector<uint_fast64_t> copyRemapping = matrixBuilder.stateRemapping;
@@ -211,28 +207,33 @@ namespace storm {
             skippedStates = skippedStatesNew;
 
             STORM_LOG_ASSERT(matrixBuilder.getCurrentRowGroup() == nrExpandedStates, "Row group size does not match.");
-
-            // Push skipped states to explore queue
-            // TODO Matthias: remove
-            for (auto const& skippedState : skippedStates) {
-                statesToExplore.push(skippedState.second);
-            }
             skippedStates.clear();
         }
 
         template<typename ValueType, typename StateType>
         void ExplicitDFTModelBuilderApprox<ValueType, StateType>::exploreStateSpace(double approximationThreshold) {
-            bool explorationFinished = false;
-            size_t pseudoStatesToCheck = 0;
-            while (!explorationFinished) {
+            // TODO Matthias: do not empty queue every time but break before
+            while (!explorationQueue.empty()) {
                 // Get the first state in the queue
-                DFTStatePointer currentState = statesToExplore.top();
+                StateType currentId = explorationQueue.popTop();
+                auto itFind = statesNotExplored.find(currentId);
+                STORM_LOG_ASSERT(itFind != statesNotExplored.end(), "Id " << currentId << " not found");
+                DFTStatePointer currentState = itFind->second;
+                STORM_LOG_ASSERT(currentState->getId() == currentId, "Ids do not match");
+                // Remove it from the list of not explored states
+                statesNotExplored.erase(itFind);
                 STORM_LOG_ASSERT(stateStorage.stateToId.contains(currentState->status()), "State is not contained in state storage.");
-                STORM_LOG_ASSERT(stateStorage.stateToId.getValue(currentState->status()) == currentState->getId(), "Ids of states do not coincide.");
-                statesToExplore.pop();
+                STORM_LOG_ASSERT(stateStorage.stateToId.getValue(currentState->status()) == currentId, "Ids of states do not coincide.");
+
+                // Get concrete state if necessary
+                if (currentState->isPseudoState()) {
+                    // Create concrete state from pseudo state
+                    currentState->construct();
+                }
+                STORM_LOG_ASSERT(!currentState->isPseudoState(), "State is pseudo state.");
 
                 // Remember that the current row group was actually filled with the transitions of a different state
-                matrixBuilder.setRemapping(currentState->getId());
+                matrixBuilder.setRemapping(currentId);
 
                 matrixBuilder.newRowGroup();
 
@@ -259,53 +260,17 @@ namespace storm {
                     for (auto const& choice : behavior) {
                         // Add the probabilistic behavior to the matrix.
                         for (auto const& stateProbabilityPair : choice) {
-                            if (stateProbabilityPair.first >= OFFSET_PSEUDO_STATE) {
-                                // Check that pseudo state and its instantiation do not appear together
-                                // TODO Matthias: prove that this is not possible and remove
-                                StateType newId = stateProbabilityPair.first - OFFSET_PSEUDO_STATE;
-                                STORM_LOG_ASSERT(newId < mPseudoStatesMapping.size(), "Id is not valid.");
-                                if (mPseudoStatesMapping[newId].first > 0) {
-                                    // State exists already
-                                    newId = mPseudoStatesMapping[newId].first;
-                                    for (auto itFind = choice.begin(); itFind != choice.end(); ++itFind) {
-                                        STORM_LOG_ASSERT(itFind->first != newId, "Pseudo state and instantiation occur together in a distribution.");
-                                    }
-                                }
-                                // Set transtion to pseudo state
-                                matrixBuilder.addTransition(stateProbabilityPair.first, stateProbabilityPair.second);
-                            } else {
-                                // Set transition to state id + offset. This helps in only remapping all previously skipped states.
-                                matrixBuilder.addTransition(matrixBuilder.mappingOffset + stateProbabilityPair.first, stateProbabilityPair.second);
-                            }
+                            // Set transition to state id + offset. This helps in only remapping all previously skipped states.
+                            matrixBuilder.addTransition(matrixBuilder.mappingOffset + stateProbabilityPair.first, stateProbabilityPair.second);
+                            // TODO Matthias: set heuristic values here
                         }
                         matrixBuilder.finishRow();
                     }
                 }
 
                 // Update priority queue
-                statesToExplore.fix();
-
-                if (statesToExplore.empty()) {
-                    explorationFinished = true;
-                    // Before ending the exploration check for pseudo states which are not initialized yet
-                    for ( ; pseudoStatesToCheck < mPseudoStatesMapping.size(); ++pseudoStatesToCheck) {
-                        std::pair<StateType, storm::storage::BitVector> pseudoStatePair = mPseudoStatesMapping[pseudoStatesToCheck];
-                        if (pseudoStatePair.first == 0) {
-                            // Create state from pseudo state and explore
-                            STORM_LOG_ASSERT(stateStorage.stateToId.contains(pseudoStatePair.second), "Pseudo state not contained.");
-                            STORM_LOG_ASSERT(stateStorage.stateToId.getValue(pseudoStatePair.second) >= OFFSET_PSEUDO_STATE, "State is no pseudo state.");
-                            STORM_LOG_TRACE("Create pseudo state from bit vector " << pseudoStatePair.second);
-                            DFTStatePointer pseudoState = std::make_shared<storm::storage::DFTState<ValueType>>(pseudoStatePair.second, dft, *stateGenerationInfo, newIndex);
-                            STORM_LOG_ASSERT(pseudoStatePair.second == pseudoState->status(), "Pseudo states do not coincide.");
-                            STORM_LOG_TRACE("Explore pseudo state " << dft.getStateString(pseudoState) << " with id " << pseudoState->getId());
-
-                            getOrAddStateIndex(pseudoState);
-                            explorationFinished = false;
-                            break;
-                        }
-                    }
-                }
-
+                // TODO Matthias: only when necessary
+                explorationQueue.fix();
             } // end exploration
         }
 
@@ -476,45 +441,31 @@ namespace storm {
             if (stateStorage.stateToId.contains(state->status())) {
                 // State already exists
                 stateId = stateStorage.stateToId.getValue(state->status());
-                STORM_LOG_TRACE("State " << dft.getStateString(state) << " with id " << stateId << " already exists");
-
-                if (!changed && stateId >= OFFSET_PSEUDO_STATE) {
-                    // Pseudo state can be created now
-                    STORM_LOG_ASSERT(stateId >= OFFSET_PSEUDO_STATE, "State is no pseudo state.");
-                    stateId -= OFFSET_PSEUDO_STATE;
-                    STORM_LOG_ASSERT(stateId < mPseudoStatesMapping.size(), "Pseudo state not known.");
-                    STORM_LOG_ASSERT(mPseudoStatesMapping[stateId].first == 0, "Pseudo state already created.");
+                STORM_LOG_TRACE("State " << dft.getStateString(state) << " already exists");
+
+                if (!changed && statesNotExplored.at(stateId)->isPseudoState()) {
                     // Create pseudo state now
-                    STORM_LOG_ASSERT(mPseudoStatesMapping[stateId].second == state->status(), "Pseudo states do not coincide.");
-                    state->setId(newIndex++);
-                    mPseudoStatesMapping[stateId].first = state->getId();
-                    stateId = state->getId();
-                    stateStorage.stateToId.setOrAdd(state->status(), stateId);
-                    STORM_LOG_TRACE("Now create state " << dft.getStateString(state) << " with id " << stateId);
-                    statesToExplore.push(state);
+                    STORM_LOG_ASSERT(statesNotExplored.at(stateId)->getId() == stateId, "Ids do not match.");
+                    STORM_LOG_ASSERT(statesNotExplored.at(stateId)->status() == state->status(), "Pseudo states do not coincide.");
+                    state->setId(stateId);
+                    // Update mapping to map to concrete state now
+                    statesNotExplored[stateId] = state;
+                    // We do not push the new state on the exploration queue as the pseudo state was already pushed
+                    STORM_LOG_TRACE("Created pseudo state " << dft.getStateString(state));
                 }
             } else {
                 // State does not exist yet
-                if (changed) {
-                    // Remember state for later creation
-                    state->setId(mPseudoStatesMapping.size() + OFFSET_PSEUDO_STATE);
-                    mPseudoStatesMapping.push_back(std::make_pair(0, state->status()));
-                    stateId = stateStorage.stateToId.findOrAdd(state->status(), state->getId());
-                    STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not match.");
-                    STORM_LOG_TRACE("Remember state for later creation: " << dft.getStateString(state));
-                    // Reserve one slot for the coming state in the remapping
-                    matrixBuilder.stateRemapping.push_back(0);
-                } else {
-                    // Create new state
-                    state->setId(newIndex++);
-                    stateId = stateStorage.stateToId.findOrAdd(state->status(), state->getId());
-                    STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not match.");
-                    STORM_LOG_TRACE("New state: " << dft.getStateString(state));
-                    statesToExplore.push(state);
-
-                    // Reserve one slot for the new state in the remapping
-                    matrixBuilder.stateRemapping.push_back(0);
-                }
+                STORM_LOG_ASSERT(state->isPseudoState() == changed, "State type (pseudo/concrete) wrong.");
+                // Create new state
+                state->setId(newIndex++);
+                stateId = stateStorage.stateToId.findOrAdd(state->status(), state->getId());
+                STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not match.");
+                // Insert state as not yet explored
+                statesNotExplored[stateId] = state;
+                explorationQueue.push(stateId);
+                // Reserve one slot for the new state in the remapping
+                matrixBuilder.stateRemapping.push_back(0);
+                STORM_LOG_TRACE("New " << (state->isPseudoState() ? "pseudo" : "concrete") << " state: " << dft.getStateString(state));
             }
             return stateId;
         }
@@ -528,6 +479,12 @@ namespace storm {
             modelComponents.markovianStates.set(matrixBuilder.getCurrentRowGroup() - 1, markovian);
         }
 
+        template<typename ValueType, typename StateType>
+        bool ExplicitDFTModelBuilderApprox<ValueType, StateType>::isPriorityGreater(StateType idA, StateType idB) const {
+            // TODO Matthias: compare directly and according to heuristic
+            return storm::builder::compareDepth(statesNotExplored.at(idA), statesNotExplored.at(idB));
+        }
+
 
         // Explicitly instantiate the class.
         template class ExplicitDFTModelBuilderApprox<double>;
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index 9dfb3f63d..5e841fddc 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -231,6 +231,16 @@ namespace storm {
              */
             void changeMatrixUpperBound(storm::storage::SparseMatrix<ValueType> & matrix) const;
 
+            /*!
+             * Compares the priority of two states.
+             *
+             * @param idA Id of first state
+             * @param idB Id of second state
+             *
+             * @return True if the priority of the first state is greater then the priority of the second one.
+             */
+            bool isPriorityGreater(StateType idA, StateType idB) const;
+
             /*!
              * Create the model model from the model components.
              *
@@ -271,9 +281,6 @@ namespace storm {
             // Id of initial state
             size_t initialStateIndex = 0;
 
-            // Mapping from pseudo states to (id of concrete state, bitvector representation)
-            std::vector<std::pair<StateType, storm::storage::BitVector>> mPseudoStatesMapping;
-
             // Next state generator for exploring the state space
             storm::generator::DftNextStateGenerator<ValueType, StateType> generator;
 
@@ -286,12 +293,16 @@ namespace storm {
             // Internal information about the states that were explored.
             storm::storage::sparse::StateStorage<StateType> stateStorage;
 
-            // A pniority queue of states that still need to be explored.
-            storm::storage::DynamicPriorityQueue<DFTStatePointer, std::vector<DFTStatePointer>, std::function<bool(DFTStatePointer, DFTStatePointer)>> statesToExplore;
+            // A priority queue of states that still need to be explored.
+            storm::storage::DynamicPriorityQueue<StateType, std::vector<StateType>, std::function<bool(StateType, StateType)>> explorationQueue;
+
+            // A mapping of not yet explored states from the id to the state object.
+            std::map<StateType, DFTStatePointer> statesNotExplored;
 
             // Holds all skipped states which were not yet expanded. More concretely it is a mapping from matrix indices
             // to the corresponding skipped states.
             // Notice that we need an ordered map here to easily iterate in increasing order over state ids.
+            // TODO remove again
             std::map<StateType, DFTStatePointer> skippedStates;
         };
 
diff --git a/src/storage/DynamicPriorityQueue.h b/src/storage/DynamicPriorityQueue.h
index a416a89b6..dc7949b4a 100644
--- a/src/storage/DynamicPriorityQueue.h
+++ b/src/storage/DynamicPriorityQueue.h
@@ -15,11 +15,11 @@ namespace storm {
             Compare compare;
 
         public:
-            explicit DynamicPriorityQueue(const Compare& compare) : container(), compare(compare) {
+            explicit DynamicPriorityQueue(Compare const& compare) : container(), compare(compare) {
                 // Intentionally left empty
             }
 
-            explicit DynamicPriorityQueue(Container&& container, const Compare& compare) : container(std::move(container)), compare(compare) {
+            explicit DynamicPriorityQueue(Container&& container, Compare const& compare) : container(std::move(container)), compare(compare) {
                 std::make_heap(container.begin(), container.end(), compare);
             }
 
diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index 208dd6bf0..4482a97a0 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -6,7 +6,8 @@ namespace storm {
     namespace storage {
 
         template<typename ValueType>
-        DFTState<ValueType>::DFTState(DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(dft.stateVectorSize()), mId(id), mDft(dft), mStateGenerationInfo(stateGenerationInfo), exploreHeuristic()  {
+        DFTState<ValueType>::DFTState(DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(dft.stateVectorSize()), mId(id), mPseudoState(false), mDft(dft), mStateGenerationInfo(stateGenerationInfo), exploreHeuristic()  {
+            // TODO Matthias: use construct()
             
             // Initialize uses
             for(size_t spareId : mDft.getSpareIndices()) {
@@ -34,10 +35,16 @@ namespace storm {
 
             sortFailableBEs();
         }
+
+        template<typename ValueType>
+        DFTState<ValueType>::DFTState(storm::storage::BitVector const& status, DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(status), mId(id), mPseudoState(true), mDft(dft), mStateGenerationInfo(stateGenerationInfo), exploreHeuristic() {
+            // Intentionally left empty
+        }
         
         template<typename ValueType>
-        DFTState<ValueType>::DFTState(storm::storage::BitVector const& status, DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(status), mId(id), mDft(dft), mStateGenerationInfo(stateGenerationInfo), exploreHeuristic() {
-            
+        void DFTState<ValueType>::construct() {
+            STORM_LOG_TRACE("Construct concrete state from pseudo state " << mDft.getStateString(mStatus, mStateGenerationInfo, mId));
+            STORM_LOG_ASSERT(mPseudoState, "Only pseudo states can be constructed.");
             for(size_t index = 0; index < mDft.nrElements(); ++index) {
                 // Initialize currently failable BE
                 if (mDft.isBasicElement(index) && isOperational(index)) {
@@ -68,6 +75,7 @@ namespace storm {
                     STORM_LOG_TRACE("New dependency failure: " << dependency->toString());
                 }
             }
+            mPseudoState = false;
         }
 
         template<typename ValueType>
@@ -406,6 +414,9 @@ namespace storm {
                     n = tmp;
                 } while (n > 0);
             }
+            if (changed) {
+                mPseudoState = true;
+            }
             return changed;
         }
         
diff --git a/src/storage/dft/DFTState.h b/src/storage/dft/DFTState.h
index a6644f349..b2fb803da 100644
--- a/src/storage/dft/DFTState.h
+++ b/src/storage/dft/DFTState.h
@@ -30,19 +30,37 @@ namespace storm {
             std::vector<size_t> mCurrentlyNotFailableBE;
             std::vector<size_t> mFailableDependencies;
             std::vector<size_t> mUsedRepresentants;
+            bool mPseudoState;
             bool mValid = true;
             const DFT<ValueType>& mDft;
             const DFTStateGenerationInfo& mStateGenerationInfo;
             storm::builder::DFTExplorationHeuristic<ValueType> exploreHeuristic;
             
         public:
+            /**
+             * Construct the initial state.
+             *
+             * @param dft                 DFT
+             * @param stateGenerationInfo General information for state generation
+             * @param id                  State id
+             */
             DFTState(DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id);
-            
+
             /**
-             * Construct state from underlying bitvector.
+             * Construct temporary pseudo state. The actual state is constructed later.
+             *
+             * @param status              BitVector representing the status of the state.
+             * @param dft                 DFT
+             * @param stateGenerationInfo General information for state generation
+             * @param id                  Pseudo state id
              */
             DFTState(storm::storage::BitVector const& status, DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id);
 
+            /**
+             * Construct concerete state from pseudo state by using the underlying bitvector.
+             */
+            void construct();
+
             std::shared_ptr<DFTState<ValueType>> copy() const;
 
             DFTElementState getElementState(size_t id) const;
@@ -101,6 +119,10 @@ namespace storm {
                 return !mValid;
             }
 
+            bool isPseudoState() const {
+                return mPseudoState;
+            }
+
             void setHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) {
                 exploreHeuristic.setHeuristicValues(depth, rate, exitRate);
             }

From 26d0a3a7a4442f823c78d4edd9d53c54b67ea584 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Mon, 17 Oct 2016 13:20:31 +0200
Subject: [PATCH 27/65] Fixed smaller bugs

Former-commit-id: 4c9c22bca138e4cc2de148480964484e253ee2cf
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 27 +++++++++++--------
 src/storage/DynamicPriorityQueue.h            |  4 +++
 src/storage/dft/DFT.cpp                       |  3 +--
 src/storage/dft/DFTState.cpp                  |  5 ++++
 4 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 76ace8dda..cb04f3135 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -441,17 +441,22 @@ namespace storm {
             if (stateStorage.stateToId.contains(state->status())) {
                 // State already exists
                 stateId = stateStorage.stateToId.getValue(state->status());
-                STORM_LOG_TRACE("State " << dft.getStateString(state) << " already exists");
-
-                if (!changed && statesNotExplored.at(stateId)->isPseudoState()) {
-                    // Create pseudo state now
-                    STORM_LOG_ASSERT(statesNotExplored.at(stateId)->getId() == stateId, "Ids do not match.");
-                    STORM_LOG_ASSERT(statesNotExplored.at(stateId)->status() == state->status(), "Pseudo states do not coincide.");
-                    state->setId(stateId);
-                    // Update mapping to map to concrete state now
-                    statesNotExplored[stateId] = state;
-                    // We do not push the new state on the exploration queue as the pseudo state was already pushed
-                    STORM_LOG_TRACE("Created pseudo state " << dft.getStateString(state));
+                STORM_LOG_TRACE("State " << dft.getStateString(state) << " with id " << stateId << " already exists");
+                if (!changed) {
+                    // Check if state is pseudo state
+                    // If state is explored already the possible pseudo state was already constructed
+                    auto iter = statesNotExplored.find(stateId);
+                    if (iter != statesNotExplored.end() && iter->second->isPseudoState()) {
+                        // Create pseudo state now
+                        STORM_LOG_ASSERT(iter->second->getId() == stateId, "Ids do not match.");
+                        STORM_LOG_ASSERT(iter->second->status() == state->status(), "Pseudo states do not coincide.");
+                        state->setId(stateId);
+                        // Update mapping to map to concrete state now
+                        statesNotExplored[stateId] = state;
+                        // TODO Matthias: copy explorationHeuristic
+                        // We do not push the new state on the exploration queue as the pseudo state was already pushed
+                        STORM_LOG_TRACE("Created pseudo state " << dft.getStateString(state));
+                    }
                 }
             } else {
                 // State does not exist yet
diff --git a/src/storage/DynamicPriorityQueue.h b/src/storage/DynamicPriorityQueue.h
index dc7949b4a..9df114fbf 100644
--- a/src/storage/DynamicPriorityQueue.h
+++ b/src/storage/DynamicPriorityQueue.h
@@ -60,6 +60,10 @@ namespace storm {
                 return item;
             }
 
+            Container getContainer() const {
+                return container;
+            }
+
         };
     }
 }
diff --git a/src/storage/dft/DFT.cpp b/src/storage/dft/DFT.cpp
index 87ee74cdd..b8024ef56 100644
--- a/src/storage/dft/DFT.cpp
+++ b/src/storage/dft/DFT.cpp
@@ -481,8 +481,7 @@ namespace storm {
                         } else {
                             useId = getChild(elem->id(), nrUsedChild);
                         }
-                        bool isActive = status[stateGenerationInfo.getSpareActivationIndex(useId)];
-                        if(useId == elem->id() || isActive) {
+                        if(useId == elem->id() || status[stateGenerationInfo.getSpareActivationIndex(useId)]) {
                             stream << "actively ";
                         }
                         stream << "using " << useId << "]";
diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index 4482a97a0..f6bb692a7 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -44,6 +44,11 @@ namespace storm {
         template<typename ValueType>
         void DFTState<ValueType>::construct() {
             STORM_LOG_TRACE("Construct concrete state from pseudo state " << mDft.getStateString(mStatus, mStateGenerationInfo, mId));
+            // Clear information from pseudo state
+            mCurrentlyFailableBE.clear();
+            mCurrentlyNotFailableBE.clear();
+            mFailableDependencies.clear();
+            mUsedRepresentants.clear();
             STORM_LOG_ASSERT(mPseudoState, "Only pseudo states can be constructed.");
             for(size_t index = 0; index < mDft.nrElements(); ++index) {
                 // Initialize currently failable BE

From 4a6f53031e01069f68789c205ff70b77f56c504d Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Tue, 18 Oct 2016 14:42:52 +0200
Subject: [PATCH 28/65] Choose different approximation heuristics

Former-commit-id: e9ddae066b005a67e839a1f31405dd72d7790d0e
---
 src/builder/DftExplorationHeuristic.cpp       | 57 +++++++++----------
 src/builder/DftExplorationHeuristic.h         |  9 ++-
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 15 +++--
 src/builder/ExplicitDFTModelBuilderApprox.h   |  4 +-
 src/modelchecker/dft/DFTModelChecker.cpp      |  4 +-
 src/storage/dft/DFTState.h                    |  6 +-
 6 files changed, 48 insertions(+), 47 deletions(-)

diff --git a/src/builder/DftExplorationHeuristic.cpp b/src/builder/DftExplorationHeuristic.cpp
index 727c29c37..e14c34dee 100644
--- a/src/builder/DftExplorationHeuristic.cpp
+++ b/src/builder/DftExplorationHeuristic.cpp
@@ -15,6 +15,13 @@ namespace storm {
             // Intentionally left empty
         }
 
+        template<typename ValueType>
+        void DFTExplorationHeuristic<ValueType>::setHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) {
+            this->depth = std::min(this->depth, depth);
+            this->rate = std::max(this->rate, rate);
+            this->exitRate = std::max(this->exitRate, exitRate);
+        }
+
         template<typename ValueType>
         bool DFTExplorationHeuristic<ValueType>::isSkip(double approximationThreshold, ApproximationHeuristic heuristic) const {
             if (!skip) {
@@ -26,8 +33,9 @@ namespace storm {
                 case ApproximationHeuristic::DEPTH:
                     return depth > approximationThreshold;
                 case ApproximationHeuristic::RATERATIO:
-                    // TODO Matthias: implement
-                    STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work.");
+                    return getRateRatio() < approximationThreshold;
+                default:
+                    STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic not known.");
             }
         }
 
@@ -36,52 +44,41 @@ namespace storm {
             skip = false;
         }
 
-
         template<typename ValueType>
         size_t DFTExplorationHeuristic<ValueType>::getDepth() const {
             return depth;
         }
 
         template<typename ValueType>
-        void DFTExplorationHeuristic<ValueType>::setHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) {
-            this->depth = depth;
-            this->rate = rate;
-            this->exitRate = exitRate;
-        }
-
-        template<typename ValueType>
-        double DFTExplorationHeuristic<ValueType>::getPriority() const {
-            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Approximation works only for double.");
+        bool DFTExplorationHeuristic<ValueType>::compare(DFTExplorationHeuristic<ValueType> other, ApproximationHeuristic heuristic) {
+            switch (heuristic) {
+                case ApproximationHeuristic::NONE:
+                    // Just use memory address for comparing
+                    // TODO Matthias: better idea?
+                    return this > &other;
+                case ApproximationHeuristic::DEPTH:
+                    return this->depth > other.depth;
+                case ApproximationHeuristic::RATERATIO:
+                    return this->getRateRatio() < other.getRateRatio();
+                default:
+                    STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic not known.");
+            }
         }
 
         template<>
-        double DFTExplorationHeuristic<double>::getPriority() const {
-            // TODO Matthias: change according to heuristic
-            //return rate/exitRate;
-            return depth;
+        double DFTExplorationHeuristic<double>::getRateRatio() const {
+            return rate/exitRate;
         }
 
         template<>
-        double DFTExplorationHeuristic<storm::RationalFunction>::getPriority() const {
-            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Approximation works only for double.");
-            /*std::cout << (rate / exitRate) << " < " << threshold << ": " << (number < threshold) << std::endl;
-             std::map<storm::Variable, storm::RationalNumber> mapping;
-             storm::RationalFunction eval(number.evaluate(mapping));
-             std::cout << "Evaluated: " << eval << std::endl;
-             return eval < threshold;*/
-        }
-
-        template<typename ValueType>
-        bool compareDepth(std::shared_ptr<storm::storage::DFTState<ValueType>> stateA, std::shared_ptr<storm::storage::DFTState<ValueType>> stateB) {
-            return stateA->getPriority() > stateB->getPriority();
+        double DFTExplorationHeuristic<storm::RationalFunction>::getRateRatio() const {
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work.");
         }
 
         template class DFTExplorationHeuristic<double>;
-        template bool compareDepth(std::shared_ptr<storm::storage::DFTState<double>>, std::shared_ptr<storm::storage::DFTState<double>>);
 
 #ifdef STORM_HAVE_CARL
         template class DFTExplorationHeuristic<storm::RationalFunction>;
-        template bool compareDepth(std::shared_ptr<storm::storage::DFTState<storm::RationalFunction>>, std::shared_ptr<storm::storage::DFTState<storm::RationalFunction>>);
 #endif
     }
 }
diff --git a/src/builder/DftExplorationHeuristic.h b/src/builder/DftExplorationHeuristic.h
index a9958443a..3fd3d72a8 100644
--- a/src/builder/DftExplorationHeuristic.h
+++ b/src/builder/DftExplorationHeuristic.h
@@ -33,19 +33,18 @@ namespace storm {
 
             size_t getDepth() const;
 
-            double getPriority() const;
-            
+            bool compare(DFTExplorationHeuristic<ValueType> other, ApproximationHeuristic heuristic);
+
         private:
 
+            double getRateRatio() const;
+
             bool skip;
             size_t depth;
             ValueType rate;
             ValueType exitRate;
 
         };
-
-        template<typename ValueType>
-        bool compareDepth(std::shared_ptr<storm::storage::DFTState<ValueType>> stateA, std::shared_ptr<storm::storage::DFTState<ValueType>> stateB);
     }
 }
 
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index cb04f3135..5acf60980 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -39,10 +39,10 @@ namespace storm {
         }
 
         template<typename ValueType, typename StateType>
-        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::buildModel(LabelOptions const& labelOpts, bool firstTime, double approximationThreshold) {
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::buildModel(LabelOptions const& labelOpts, size_t iteration, double approximationThreshold) {
             STORM_LOG_TRACE("Generating DFT state space");
 
-            if (firstTime) {
+            if (iteration < 1) {
                 // Initialize
                 modelComponents.markovianStates = storm::storage::BitVector(INITIAL_BITVECTOR_SIZE);
 
@@ -80,6 +80,14 @@ namespace storm {
                 initializeNextIteration();
             }
 
+            switch (heuristic) {
+                case storm::builder::ApproximationHeuristic::DEPTH:
+                    approximationThreshold = iteration;
+                    break;
+                case storm::builder::ApproximationHeuristic::RATERATIO:
+                    approximationThreshold = std::pow(0.1, iteration) * approximationThreshold;
+                    break;
+            }
             exploreStateSpace(approximationThreshold);
 
             size_t stateSize = stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0);
@@ -486,8 +494,7 @@ namespace storm {
 
         template<typename ValueType, typename StateType>
         bool ExplicitDFTModelBuilderApprox<ValueType, StateType>::isPriorityGreater(StateType idA, StateType idB) const {
-            // TODO Matthias: compare directly and according to heuristic
-            return storm::builder::compareDepth(statesNotExplored.at(idA), statesNotExplored.at(idB));
+            return statesNotExplored.at(idA)->comparePriority(statesNotExplored.at(idB), heuristic);
         }
 
 
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index 5e841fddc..74798e889 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -159,10 +159,10 @@ namespace storm {
              * Build model from DFT.
              *
              * @param labelOpts              Options for labeling.
-             * @param firstTime              Flag indicating if the model is built for the first time or rebuilt.
+             * @param iteration              Current number of iteration.
              * @param approximationThreshold Threshold determining when to skip exploring states.
              */
-            void buildModel(LabelOptions const& labelOpts, bool firstTime, double approximationThreshold = 0.0);
+            void buildModel(LabelOptions const& labelOpts, size_t iteration, double approximationThreshold = 0.0);
 
             /*!
              * Get the built model.
diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index 717ace4c3..1fa1ca245 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -150,7 +150,6 @@ namespace storm {
                 // Comparator for checking the error of the approximation
                 storm::utility::ConstantsComparator<ValueType> comparator;
                 // Build approximate Markov Automata for lower and upper bound
-                double currentApproximationError = approximationError;
                 approximation_result approxResult = std::make_pair(storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>());
                 std::chrono::high_resolution_clock::time_point explorationStart;
                 std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
@@ -163,8 +162,7 @@ namespace storm {
                     explorationStart = std::chrono::high_resolution_clock::now();
                     STORM_LOG_INFO("Building model...");
                     // TODO Matthias refine model using existing model and MC results
-                    currentApproximationError = pow(0.1, iteration) * approximationError;
-                    builder.buildModel(labeloptions, iteration < 1, iteration);
+                    builder.buildModel(labeloptions, iteration, approximationError);
 
                     // TODO Matthias: possible to do bisimulation on approximated model and not on concrete one?
 
diff --git a/src/storage/dft/DFTState.h b/src/storage/dft/DFTState.h
index b2fb803da..eb3164516 100644
--- a/src/storage/dft/DFTState.h
+++ b/src/storage/dft/DFTState.h
@@ -139,10 +139,10 @@ namespace storm {
                 return exploreHeuristic.isSkip(approximationThreshold, heuristic);
             }
 
-            double getPriority() const {
-                return exploreHeuristic.getPriority();
+            bool comparePriority(std::shared_ptr<DFTState> const& other, storm::builder::ApproximationHeuristic heuristic) {
+                return this->exploreHeuristic.compare(other->exploreHeuristic, heuristic);
             }
-            
+
             storm::storage::BitVector const& status() const {
                 return mStatus;
             }

From 1bfd9747957838406ddb033ac093ad99d0793902 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Tue, 18 Oct 2016 15:58:43 +0200
Subject: [PATCH 29/65] Minor fixes

Former-commit-id: 9344ebe5aac6a410ae5e84b4230037401c2946f3
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 19 +++++++++++++++----
 src/generator/DftNextStateGenerator.cpp       |  4 ----
 src/modelchecker/dft/DFTModelChecker.cpp      |  2 +-
 3 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 5acf60980..fda689be7 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -75,12 +75,16 @@ namespace storm {
                 STORM_LOG_ASSERT(stateStorage.initialStateIndices.size() == 1, "Only one initial state assumed.");
                 initialStateIndex = stateStorage.initialStateIndices[0];
                 STORM_LOG_TRACE("Initial state: " << initialStateIndex);
-
+                // Initialize heuristic values for inital state
+                statesNotExplored.at(initialStateIndex)->setHeuristicValues(0, storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>());
             } else {
                 initializeNextIteration();
             }
 
             switch (heuristic) {
+                case storm::builder::ApproximationHeuristic::NONE:
+                    // Do not change anything
+                    break;
                 case storm::builder::ApproximationHeuristic::DEPTH:
                     approximationThreshold = iteration;
                     break;
@@ -246,6 +250,7 @@ namespace storm {
                 matrixBuilder.newRowGroup();
 
                 // Try to explore the next state
+                bool fixQueue = false;
                 generator.load(currentState);
 
                 if (currentState->isSkip(approximationThreshold, heuristic)) {
@@ -270,15 +275,21 @@ namespace storm {
                         for (auto const& stateProbabilityPair : choice) {
                             // Set transition to state id + offset. This helps in only remapping all previously skipped states.
                             matrixBuilder.addTransition(matrixBuilder.mappingOffset + stateProbabilityPair.first, stateProbabilityPair.second);
-                            // TODO Matthias: set heuristic values here
+                            // Set heuristic values for reached states
+                            auto iter = statesNotExplored.find(stateProbabilityPair.first);
+                            if (iter != statesNotExplored.end()) {
+                                iter->second->setHeuristicValues(currentState, stateProbabilityPair.second, choice.getTotalMass());
+                                fixQueue = true;
+                            }
                         }
                         matrixBuilder.finishRow();
                     }
                 }
 
                 // Update priority queue
-                // TODO Matthias: only when necessary
-                explorationQueue.fix();
+                if (fixQueue) {
+                    explorationQueue.fix();
+                }
             } // end exploration
         }
 
diff --git a/src/generator/DftNextStateGenerator.cpp b/src/generator/DftNextStateGenerator.cpp
index e61e8e331..69fca22b4 100644
--- a/src/generator/DftNextStateGenerator.cpp
+++ b/src/generator/DftNextStateGenerator.cpp
@@ -20,7 +20,6 @@ namespace storm {
         template<typename ValueType, typename StateType>
         std::vector<StateType> DftNextStateGenerator<ValueType, StateType>::getInitialStates(StateToIdCallback const& stateToIdCallback) {
             DFTStatePointer initialState = std::make_shared<storm::storage::DFTState<ValueType>>(mDft, mStateGenerationInfo, 0);
-            initialState->setHeuristicValues(0, storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>());
 
             // Register initial state
             StateType id = stateToIdCallback(initialState);
@@ -158,10 +157,8 @@ namespace storm {
                         ValueType remainingProbability = storm::utility::one<ValueType>() - probability;
                         choice.addProbability(unsuccessfulStateId, remainingProbability);
                         STORM_LOG_TRACE("Added transition to " << unsuccessfulStateId << " with remaining probability " << remainingProbability);
-                        unsuccessfulState->setHeuristicValues(state, remainingProbability, storm::utility::one<ValueType>());
                     }
                     result.addChoice(std::move(choice));
-                    newState->setHeuristicValues(state, probability, storm::utility::one<ValueType>());
                 } else {
                     // Failure is due to "normal" BE failure
                     // Set failure rate according to activation
@@ -174,7 +171,6 @@ namespace storm {
                     STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Rate is 0.");
                     choice.addProbability(newStateId, rate);
                     STORM_LOG_TRACE("Added transition to " << newStateId << " with " << (isActive ? "active" : "passive") << " failure rate " << rate);
-                    newState->setHeuristicValues(state, rate, choice.getTotalMass());
                 }
 
                 ++currentFailable;
diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index 1fa1ca245..cadc37ac7 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -204,7 +204,7 @@ namespace storm {
                 if (approximationError >= 0.0) {
                     storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
                     typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
-                    builder.buildModel(labeloptions, true);
+                    builder.buildModel(labeloptions, 0);
                     model = builder.getModel();
                 } else {
                     storm::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries, enableDC);

From ec8b5a23f2e8b7176762a0fa328f8e0db9ddfe39 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Thu, 20 Oct 2016 16:57:28 +0200
Subject: [PATCH 30/65] Fixed compile issues with under Linux

Former-commit-id: 17f4d895ec52241f653fc9a175d4609c88d71a94
---
 src/builder/DftSmtBuilder.cpp | 2 +-
 src/storm-dyftee.cpp          | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/builder/DftSmtBuilder.cpp b/src/builder/DftSmtBuilder.cpp
index 1d60b2c74..c1226531c 100644
--- a/src/builder/DftSmtBuilder.cpp
+++ b/src/builder/DftSmtBuilder.cpp
@@ -1,4 +1,4 @@
-#include "src/builder/DFTSMTBuilder.h"
+#include "src/builder/DftSmtBuilder.h"
 #include "src/exceptions/NotImplementedException.h"
 
 namespace storm {
diff --git a/src/storm-dyftee.cpp b/src/storm-dyftee.cpp
index 51061050e..fb0c0b1e6 100644
--- a/src/storm-dyftee.cpp
+++ b/src/storm-dyftee.cpp
@@ -117,6 +117,7 @@ int main(const int argc, const char** argv) {
         parametric = generalSettings.isParametricSet();
 #endif
         
+#ifdef STORM_HAVE_Z3
         if (dftSettings.solveWithSMT()) {
             // Solve with SMT
             if (parametric) {
@@ -127,6 +128,7 @@ int main(const int argc, const char** argv) {
             storm::utility::cleanUp();
             return 0;
         }
+#endif
         
         // Set min or max
         bool minimal = true;

From a624292ecea60e9983ef677b97c76accabc3a0a9 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Fri, 21 Oct 2016 18:28:01 +0200
Subject: [PATCH 31/65] Output no states

Former-commit-id: d1548bb3fba7fe2ecbf4f20dc79eb61f4f9369f5
---
 src/builder/ExplicitDFTModelBuilder.cpp       |  1 +
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 12 ++++++++++--
 src/modelchecker/dft/DFTModelChecker.cpp      |  5 ++++-
 3 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilder.cpp b/src/builder/ExplicitDFTModelBuilder.cpp
index 9481e3392..4a2f56b5f 100644
--- a/src/builder/ExplicitDFTModelBuilder.cpp
+++ b/src/builder/ExplicitDFTModelBuilder.cpp
@@ -58,6 +58,7 @@ namespace storm {
                     STORM_LOG_ASSERT(mStates.getValue(pseudoStatePair.second) >= OFFSET_PSEUDO_STATE, "State is no pseudo state.");
                     STORM_LOG_TRACE("Create pseudo state from bit vector " << pseudoStatePair.second);
                     DFTStatePointer pseudoState = std::make_shared<storm::storage::DFTState<ValueType>>(pseudoStatePair.second, mDft, *mStateGenerationInfo, newIndex);
+                    pseudoState->construct();
                     STORM_LOG_ASSERT(pseudoStatePair.second == pseudoState->status(), "Pseudo states do not coincide.");
                     STORM_LOG_TRACE("Explore pseudo state " << mDft.getStateString(pseudoState) << " with id " << pseudoState->getId());
                     auto exploreResult = exploreStates(pseudoState, rowOffset, transitionMatrixBuilder, tmpMarkovianStates, modelComponents.exitRates);
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index fda689be7..268ec03dc 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -106,8 +106,7 @@ namespace storm {
 
             STORM_LOG_TRACE("State remapping: " << matrixBuilder.stateRemapping);
             STORM_LOG_TRACE("Markovian states: " << modelComponents.markovianStates);
-            STORM_LOG_DEBUG("Generated " << stateSize << " states");
-            STORM_LOG_DEBUG("Skipped " << skippedStates.size() << " states");
+            STORM_LOG_DEBUG("Model has " << stateSize << " states");
             STORM_LOG_DEBUG("Model is " << (generator.isDeterministicModel() ? "deterministic" : "non-deterministic"));
 
             // Build transition matrix
@@ -224,6 +223,8 @@ namespace storm {
 
         template<typename ValueType, typename StateType>
         void ExplicitDFTModelBuilderApprox<ValueType, StateType>::exploreStateSpace(double approximationThreshold) {
+            size_t nrExpandedStates = 0;
+            size_t nrSkippedStates = 0;
             // TODO Matthias: do not empty queue every time but break before
             while (!explorationQueue.empty()) {
                 // Get the first state in the queue
@@ -255,6 +256,7 @@ namespace storm {
 
                 if (currentState->isSkip(approximationThreshold, heuristic)) {
                     // Skip the current state
+                    ++nrSkippedStates;
                     STORM_LOG_TRACE("Skip expansion of state: " << dft.getStateString(currentState));
                     setMarkovian(true);
                     // Add transition to target state with temporary value 0
@@ -265,6 +267,7 @@ namespace storm {
                     matrixBuilder.finishRow();
                 } else {
                     // Explore the current state
+                    ++nrExpandedStates;
                     storm::generator::StateBehavior<ValueType, StateType> behavior = generator.expand(std::bind(&ExplicitDFTModelBuilderApprox::getOrAddStateIndex, this, std::placeholders::_1));
                     STORM_LOG_ASSERT(!behavior.empty(), "Behavior is empty.");
                     setMarkovian(behavior.begin()->isMarkovian());
@@ -273,6 +276,7 @@ namespace storm {
                     for (auto const& choice : behavior) {
                         // Add the probabilistic behavior to the matrix.
                         for (auto const& stateProbabilityPair : choice) {
+                            STORM_LOG_ASSERT(!storm::utility::isZero(stateProbabilityPair.second), "Probability zero.");
                             // Set transition to state id + offset. This helps in only remapping all previously skipped states.
                             matrixBuilder.addTransition(matrixBuilder.mappingOffset + stateProbabilityPair.first, stateProbabilityPair.second);
                             // Set heuristic values for reached states
@@ -291,6 +295,10 @@ namespace storm {
                     explorationQueue.fix();
                 }
             } // end exploration
+
+            STORM_LOG_INFO("Expanded " << nrExpandedStates << " states");
+            STORM_LOG_INFO("Skipped " << nrSkippedStates << " states");
+            STORM_LOG_ASSERT(nrSkippedStates == skippedStates.size(), "Nr skipped states is wrong");
         }
 
         template<typename ValueType, typename StateType>
diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index cadc37ac7..f19943f2f 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -169,6 +169,9 @@ namespace storm {
                     // Build model for lower bound
                     STORM_LOG_INFO("Getting model for lower bound...");
                     model = builder.getModelApproximation(true);
+                    // We only output the info from the lower bound as the info for the upper bound is the same
+                    STORM_LOG_INFO("No. states: " << model->getNumberOfStates());
+                    STORM_LOG_INFO("No. transitions: " << model->getNumberOfTransitions());
                     explorationTime += std::chrono::high_resolution_clock::now() - explorationStart;
                     // Check lower bound
                     std::unique_ptr<storm::modelchecker::CheckResult> result = checkModel(model, formula);
@@ -201,7 +204,7 @@ namespace storm {
                 STORM_LOG_INFO("Building Model...");
                 std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
                 // TODO Matthias: use only one builder if everything works again
-                if (approximationError >= 0.0) {
+                if (storm::settings::getModule<storm::settings::modules::DFTSettings>().isApproximationErrorSet()) {
                     storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
                     typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
                     builder.buildModel(labeloptions, 0);

From a333d29d1663a877fd0980d5ecc562213463a9b9 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Sat, 22 Oct 2016 17:31:02 +0200
Subject: [PATCH 32/65] Hard coded heuristic to gain performance

Former-commit-id: d0d869bb3e08535bdfa5c56ec2e1e4eb42395e81
---
 src/builder/DftExplorationHeuristic.cpp       | 84 +++++++++++--------
 src/builder/DftExplorationHeuristic.h         | 71 ++++++++++++----
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 71 ++++++++--------
 src/builder/ExplicitDFTModelBuilderApprox.h   | 15 ++--
 src/storage/dft/DFTState.cpp                  |  8 +-
 src/storage/dft/DFTState.h                    | 23 +----
 6 files changed, 150 insertions(+), 122 deletions(-)

diff --git a/src/builder/DftExplorationHeuristic.cpp b/src/builder/DftExplorationHeuristic.cpp
index e14c34dee..4bc72ccc1 100644
--- a/src/builder/DftExplorationHeuristic.cpp
+++ b/src/builder/DftExplorationHeuristic.cpp
@@ -3,7 +3,6 @@
 #include "src/utility/macros.h"
 #include "src/utility/constants.h"
 #include "src/exceptions/NotImplementedException.h"
-#include "src/storage/dft/DFTState.h"
 
 #include <limits>
 
@@ -11,74 +10,87 @@ namespace storm {
     namespace builder {
 
         template<typename ValueType>
-        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic() : skip(true), depth(std::numeric_limits<std::size_t>::max()), rate(storm::utility::zero<ValueType>()), exitRate(storm::utility::zero<ValueType>()) {
+        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic(size_t id) : id(id), expand(false), depth(std::numeric_limits<std::size_t>::max()), rate(storm::utility::zero<ValueType>()), exitRate(storm::utility::zero<ValueType>()) {
             // Intentionally left empty
         }
 
         template<typename ValueType>
-        void DFTExplorationHeuristic<ValueType>::setHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) {
+        void DFTExplorationHeuristic<ValueType>::updateHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) {
             this->depth = std::min(this->depth, depth);
             this->rate = std::max(this->rate, rate);
             this->exitRate = std::max(this->exitRate, exitRate);
         }
 
         template<typename ValueType>
-        bool DFTExplorationHeuristic<ValueType>::isSkip(double approximationThreshold, ApproximationHeuristic heuristic) const {
-            if (!skip) {
-                return false;
-            }
-            switch (heuristic) {
-                case ApproximationHeuristic::NONE:
-                    return false;
-                case ApproximationHeuristic::DEPTH:
-                    return depth > approximationThreshold;
-                case ApproximationHeuristic::RATERATIO:
-                    return getRateRatio() < approximationThreshold;
-                default:
-                    STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic not known.");
-            }
+        DFTExplorationHeuristicNone<ValueType>::DFTExplorationHeuristicNone(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
+            // Intentionally left empty
+        }
+
+        template<typename ValueType>
+        bool DFTExplorationHeuristicNone<ValueType>::isSkip(double approximationThreshold) const {
+            return false;
+        }
+
+        template<typename ValueType>
+        bool DFTExplorationHeuristicNone<ValueType>::operator<(DFTExplorationHeuristicNone<ValueType> const& other) const {
+            // Just use memory address for comparing
+            // TODO Matthias: better idea?
+            return this > &other;
+        }
+
+        template<typename ValueType>
+        DFTExplorationHeuristicDepth<ValueType>::DFTExplorationHeuristicDepth(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
+            // Intentionally left empty
+        }
+
+        template<typename ValueType>
+        bool DFTExplorationHeuristicDepth<ValueType>::isSkip(double approximationThreshold) const {
+            return !this->expand && this->depth > approximationThreshold;
+        }
+
+        template<typename ValueType>
+        bool DFTExplorationHeuristicDepth<ValueType>::operator<(DFTExplorationHeuristicDepth<ValueType> const& other) const {
+            return this->depth > other.depth;
         }
 
         template<typename ValueType>
-        void DFTExplorationHeuristic<ValueType>::setNotSkip() {
-            skip = false;
+        DFTExplorationHeuristicRateRatio<ValueType>::DFTExplorationHeuristicRateRatio(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
+            // Intentionally left empty
         }
 
         template<typename ValueType>
-        size_t DFTExplorationHeuristic<ValueType>::getDepth() const {
-            return depth;
+        bool DFTExplorationHeuristicRateRatio<ValueType>::isSkip(double approximationThreshold) const {
+            return !this->expand && this->getRateRatio() < approximationThreshold;
         }
 
         template<typename ValueType>
-        bool DFTExplorationHeuristic<ValueType>::compare(DFTExplorationHeuristic<ValueType> other, ApproximationHeuristic heuristic) {
-            switch (heuristic) {
-                case ApproximationHeuristic::NONE:
-                    // Just use memory address for comparing
-                    // TODO Matthias: better idea?
-                    return this > &other;
-                case ApproximationHeuristic::DEPTH:
-                    return this->depth > other.depth;
-                case ApproximationHeuristic::RATERATIO:
-                    return this->getRateRatio() < other.getRateRatio();
-                default:
-                    STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic not known.");
-            }
+        bool DFTExplorationHeuristicRateRatio<ValueType>::operator<(DFTExplorationHeuristicRateRatio<ValueType> const& other) const {
+            return this->getRateRatio() < other.getRateRatio();
         }
 
+
         template<>
-        double DFTExplorationHeuristic<double>::getRateRatio() const {
+        double DFTExplorationHeuristicRateRatio<double>::getRateRatio() const {
             return rate/exitRate;
         }
 
         template<>
-        double DFTExplorationHeuristic<storm::RationalFunction>::getRateRatio() const {
+        double DFTExplorationHeuristicRateRatio<storm::RationalFunction>::getRateRatio() const {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work.");
         }
 
+
+        // Instantiate templates.
         template class DFTExplorationHeuristic<double>;
+        template class DFTExplorationHeuristicNone<double>;
+        template class DFTExplorationHeuristicDepth<double>;
+        template class DFTExplorationHeuristicRateRatio<double>;
 
 #ifdef STORM_HAVE_CARL
         template class DFTExplorationHeuristic<storm::RationalFunction>;
+        template class DFTExplorationHeuristicNone<storm::RationalFunction>;
+        template class DFTExplorationHeuristicDepth<storm::RationalFunction>;
+        template class DFTExplorationHeuristicRateRatio<storm::RationalFunction>;
 #endif
     }
 }
diff --git a/src/builder/DftExplorationHeuristic.h b/src/builder/DftExplorationHeuristic.h
index 3fd3d72a8..8f12d2ec1 100644
--- a/src/builder/DftExplorationHeuristic.h
+++ b/src/builder/DftExplorationHeuristic.h
@@ -2,16 +2,9 @@
 #define STORM_BUILDER_DFTEXPLORATIONHEURISTIC_H_
 
 #include <memory>
-#include <algorithm>
 
 namespace storm {
 
-    // Forward declaration
-    namespace storage {
-        template<typename ValueType>
-        class DFTState;
-    }
-
     namespace builder {
 
         /*!
@@ -19,32 +12,74 @@ namespace storm {
          */
         enum class ApproximationHeuristic { NONE, DEPTH, RATERATIO };
 
+
+        /*!
+         * General super class for appoximation heuristics.
+         */
         template<typename ValueType>
         class DFTExplorationHeuristic {
 
         public:
-            DFTExplorationHeuristic();
-
-            void setHeuristicValues(size_t depth, ValueType rate, ValueType exitRate);
-
-            bool isSkip(double approximationThreshold, ApproximationHeuristic heuristic) const;
+            DFTExplorationHeuristic(size_t id);
 
-            void setNotSkip();
+            void updateHeuristicValues(size_t depth, ValueType rate, ValueType exitRate);
 
-            size_t getDepth() const;
+            virtual bool isSkip(double approximationThreshold) const = 0;
 
-            bool compare(DFTExplorationHeuristic<ValueType> other, ApproximationHeuristic heuristic);
+            void markExpand() {
+                expand = true;
+            }
 
-        private:
+            size_t getId() const {
+                return id;
+            }
 
-            double getRateRatio() const;
+            size_t getDepth() const {
+                return depth;
+            }
 
-            bool skip;
+        protected:
+            size_t id;
+            bool expand;
             size_t depth;
             ValueType rate;
             ValueType exitRate;
 
         };
+
+        template<typename ValueType>
+        class DFTExplorationHeuristicNone : public DFTExplorationHeuristic<ValueType> {
+        public:
+            DFTExplorationHeuristicNone(size_t id);
+
+            bool isSkip(double approximationThreshold) const override;
+
+            bool operator<(DFTExplorationHeuristicNone<ValueType> const& other) const;
+        };
+
+        template<typename ValueType>
+        class DFTExplorationHeuristicDepth : public DFTExplorationHeuristic<ValueType> {
+        public:
+            DFTExplorationHeuristicDepth(size_t id);
+
+            bool isSkip(double approximationThreshold) const override;
+
+            bool operator<(DFTExplorationHeuristicDepth<ValueType> const& other) const;
+        };
+
+        template<typename ValueType>
+        class DFTExplorationHeuristicRateRatio : public DFTExplorationHeuristic<ValueType> {
+        public:
+            DFTExplorationHeuristicRateRatio(size_t id);
+
+            bool isSkip(double approximationThreshold) const override;
+
+            bool operator<(DFTExplorationHeuristicRateRatio<ValueType> const& other) const;
+
+        private:
+            double getRateRatio() const;
+        };
+
     }
 }
 
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 268ec03dc..5595a5f49 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -31,8 +31,8 @@ namespace storm {
                 generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates),
                 matrixBuilder(!generator.isDeterministicModel()),
                 stateStorage(((dft.stateVectorSize() / 64) + 1) * 64),
-                explorationQueue([this](StateType idA, StateType idB) {
-                        return isPriorityGreater(idA, idB);
+                explorationQueue([this](ExplorationHeuristicPointer a, ExplorationHeuristicPointer b) {
+                        return *a < *b;
                     })
         {
             // Intentionally left empty.
@@ -76,7 +76,7 @@ namespace storm {
                 initialStateIndex = stateStorage.initialStateIndices[0];
                 STORM_LOG_TRACE("Initial state: " << initialStateIndex);
                 // Initialize heuristic values for inital state
-                statesNotExplored.at(initialStateIndex)->setHeuristicValues(0, storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>());
+                statesNotExplored.at(initialStateIndex).second->updateHeuristicValues(0, storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>());
             } else {
                 initializeNextIteration();
             }
@@ -128,8 +128,8 @@ namespace storm {
             // Push skipped states to explore queue
             // TODO Matthias: remove
             for (auto const& skippedState : skippedStates) {
-                statesNotExplored[skippedState.second->getId()] = skippedState.second;
-                explorationQueue.push(skippedState.second->getId());
+                statesNotExplored[skippedState.second.first->getId()] = skippedState.second;
+                explorationQueue.push(skippedState.second.second);
             }
 
             // Initialize matrix builder again
@@ -157,7 +157,7 @@ namespace storm {
             matrixBuilder.mappingOffset = nrStates;
             STORM_LOG_TRACE("# expanded states: " << nrExpandedStates);
             StateType skippedIndex = nrExpandedStates;
-            std::map<StateType, DFTStatePointer> skippedStatesNew;
+            std::map<StateType, std::pair<DFTStatePointer, ExplorationHeuristicPointer>> skippedStatesNew;
             for (size_t id = 0; id < matrixBuilder.stateRemapping.size(); ++id) {
                 StateType index = matrixBuilder.stateRemapping[id];
                 auto itFind = skippedStates.find(index);
@@ -204,7 +204,7 @@ namespace storm {
                             auto itFind = skippedStates.find(itEntry->getColumn());
                             if (itFind != skippedStates.end()) {
                                 // Set id for skipped states as we remap it later
-                                matrixBuilder.addTransition(matrixBuilder.mappingOffset + itFind->second->getId(), itEntry->getValue());
+                                matrixBuilder.addTransition(matrixBuilder.mappingOffset + itFind->second.first->getId(), itEntry->getValue());
                             } else {
                                 // Set newly remapped index for expanded states
                                 matrixBuilder.addTransition(indexRemapping[itEntry->getColumn()], itEntry->getValue());
@@ -228,10 +228,12 @@ namespace storm {
             // TODO Matthias: do not empty queue every time but break before
             while (!explorationQueue.empty()) {
                 // Get the first state in the queue
-                StateType currentId = explorationQueue.popTop();
+                ExplorationHeuristicPointer currentExplorationHeuristic = explorationQueue.popTop();
+                StateType currentId = currentExplorationHeuristic->getId();
                 auto itFind = statesNotExplored.find(currentId);
                 STORM_LOG_ASSERT(itFind != statesNotExplored.end(), "Id " << currentId << " not found");
-                DFTStatePointer currentState = itFind->second;
+                DFTStatePointer currentState = itFind->second.first;
+                STORM_LOG_ASSERT(currentExplorationHeuristic == itFind->second.second, "Exploration heuristics do not match");
                 STORM_LOG_ASSERT(currentState->getId() == currentId, "Ids do not match");
                 // Remove it from the list of not explored states
                 statesNotExplored.erase(itFind);
@@ -254,7 +256,7 @@ namespace storm {
                 bool fixQueue = false;
                 generator.load(currentState);
 
-                if (currentState->isSkip(approximationThreshold, heuristic)) {
+                if (currentExplorationHeuristic->isSkip(approximationThreshold)) {
                     // Skip the current state
                     ++nrSkippedStates;
                     STORM_LOG_TRACE("Skip expansion of state: " << dft.getStateString(currentState));
@@ -263,7 +265,7 @@ namespace storm {
                     // TODO Matthias: what to do when there is no unique target state?
                     matrixBuilder.addTransition(failedStateId, storm::utility::zero<ValueType>());
                     // Remember skipped state
-                    skippedStates[matrixBuilder.getCurrentRowGroup() - 1] = currentState;
+                    skippedStates[matrixBuilder.getCurrentRowGroup() - 1] = std::make_pair(currentState, currentExplorationHeuristic);
                     matrixBuilder.finishRow();
                 } else {
                     // Explore the current state
@@ -282,7 +284,13 @@ namespace storm {
                             // Set heuristic values for reached states
                             auto iter = statesNotExplored.find(stateProbabilityPair.first);
                             if (iter != statesNotExplored.end()) {
-                                iter->second->setHeuristicValues(currentState, stateProbabilityPair.second, choice.getTotalMass());
+                                // Update heuristic values
+                                DFTStatePointer state = iter->second.first;
+                                if (state->hasFailed(dft.getTopLevelIndex()) || state->isFailsafe(dft.getTopLevelIndex()) || state->nrFailableDependencies() > 0 || (state->nrFailableDependencies() == 0 && state->nrFailableBEs() == 0)) {
+                                    // Do not skip absorbing state or if reached by dependencies
+                                    iter->second.second->markExpand();
+                                }
+                                iter->second.second->updateHeuristicValues(currentExplorationHeuristic->getDepth() + 1, stateProbabilityPair.second, choice.getTotalMass());
                                 fixQueue = true;
                             }
                         }
@@ -421,12 +429,13 @@ namespace storm {
                 auto matrixEntry = matrix.getRow(it->first, 0).begin();
                 STORM_LOG_ASSERT(matrixEntry->getColumn() == failedStateId, "Transition has wrong target state.");
                 // Get the lower bound by considering the failure of all possible BEs
+                DFTStatePointer state = it->second.first;
                 ValueType newRate = storm::utility::zero<ValueType>();
-                for (size_t index = 0; index < it->second->nrFailableBEs(); ++index) {
-                    newRate += it->second->getFailableBERate(index);
+                for (size_t index = 0; index < state->nrFailableBEs(); ++index) {
+                    newRate += state->getFailableBERate(index);
                 }
-                for (size_t index = 0; index < it->second->nrNotFailableBEs(); ++index) {
-                    newRate += it->second->getNotFailableBERate(index);
+                for (size_t index = 0; index < state->nrNotFailableBEs(); ++index) {
+                    newRate += state->getNotFailableBERate(index);
                 }
                 matrixEntry->setValue(newRate);
             }
@@ -441,12 +450,13 @@ namespace storm {
                 // Get the upper bound by considering the failure of all BEs
                 // The used formula for the rate is 1/( 1/a + 1/b + ...)
                 // TODO Matthias: improve by using closed formula for AND of all BEs
+                DFTStatePointer state = it->second.first;
                 ValueType newRate = storm::utility::zero<ValueType>();
-                for (size_t index = 0; index < it->second->nrFailableBEs(); ++index) {
-                    newRate += storm::utility::one<ValueType>() / it->second->getFailableBERate(index);
+                for (size_t index = 0; index < state->nrFailableBEs(); ++index) {
+                    newRate += storm::utility::one<ValueType>() / state->getFailableBERate(index);
                 }
-                for (size_t index = 0; index < it->second->nrNotFailableBEs(); ++index) {
-                    newRate += storm::utility::one<ValueType>() / it->second->getNotFailableBERate(index);
+                for (size_t index = 0; index < state->nrNotFailableBEs(); ++index) {
+                    newRate += storm::utility::one<ValueType>() / state->getNotFailableBERate(index);
                 }
                 newRate = storm::utility::one<ValueType>() / newRate;
                 matrixEntry->setValue(newRate);
@@ -473,14 +483,14 @@ namespace storm {
                     // Check if state is pseudo state
                     // If state is explored already the possible pseudo state was already constructed
                     auto iter = statesNotExplored.find(stateId);
-                    if (iter != statesNotExplored.end() && iter->second->isPseudoState()) {
+                    if (iter != statesNotExplored.end() && iter->second.first->isPseudoState()) {
                         // Create pseudo state now
-                        STORM_LOG_ASSERT(iter->second->getId() == stateId, "Ids do not match.");
-                        STORM_LOG_ASSERT(iter->second->status() == state->status(), "Pseudo states do not coincide.");
+                        STORM_LOG_ASSERT(iter->second.first->getId() == stateId, "Ids do not match.");
+                        STORM_LOG_ASSERT(iter->second.first->status() == state->status(), "Pseudo states do not coincide.");
                         state->setId(stateId);
                         // Update mapping to map to concrete state now
-                        statesNotExplored[stateId] = state;
-                        // TODO Matthias: copy explorationHeuristic
+                        // TODO Matthias: just change pointer?
+                        statesNotExplored[stateId] = std::make_pair(state, iter->second.second);
                         // We do not push the new state on the exploration queue as the pseudo state was already pushed
                         STORM_LOG_TRACE("Created pseudo state " << dft.getStateString(state));
                     }
@@ -493,8 +503,9 @@ namespace storm {
                 stateId = stateStorage.stateToId.findOrAdd(state->status(), state->getId());
                 STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not match.");
                 // Insert state as not yet explored
-                statesNotExplored[stateId] = state;
-                explorationQueue.push(stateId);
+                ExplorationHeuristicPointer heuristic = std::make_shared<ExplorationHeuristic>(stateId);
+                statesNotExplored[stateId] = std::make_pair(state, heuristic);
+                explorationQueue.push(heuristic);
                 // Reserve one slot for the new state in the remapping
                 matrixBuilder.stateRemapping.push_back(0);
                 STORM_LOG_TRACE("New " << (state->isPseudoState() ? "pseudo" : "concrete") << " state: " << dft.getStateString(state));
@@ -511,12 +522,6 @@ namespace storm {
             modelComponents.markovianStates.set(matrixBuilder.getCurrentRowGroup() - 1, markovian);
         }
 
-        template<typename ValueType, typename StateType>
-        bool ExplicitDFTModelBuilderApprox<ValueType, StateType>::isPriorityGreater(StateType idA, StateType idB) const {
-            return statesNotExplored.at(idA)->comparePriority(statesNotExplored.at(idB), heuristic);
-        }
-
-
         // Explicitly instantiate the class.
         template class ExplicitDFTModelBuilderApprox<double>;
 
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index 74798e889..4238194eb 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -26,11 +26,10 @@ namespace storm {
         template<typename ValueType, typename StateType = uint32_t>
         class ExplicitDFTModelBuilderApprox {
 
-            using DFTElementPointer = std::shared_ptr<storm::storage::DFTElement<ValueType>>;
-            using DFTElementCPointer = std::shared_ptr<storm::storage::DFTElement<ValueType> const>;
-            using DFTGatePointer = std::shared_ptr<storm::storage::DFTGate<ValueType>>;
             using DFTStatePointer = std::shared_ptr<storm::storage::DFTState<ValueType>>;
-            using DFTRestrictionPointer = std::shared_ptr<storm::storage::DFTRestriction<ValueType>>;
+            // TODO Matthias: make choosable
+            using ExplorationHeuristic = DFTExplorationHeuristicNone<ValueType>;
+            using ExplorationHeuristicPointer = std::shared_ptr<ExplorationHeuristic>;
 
 
             // A structure holding the individual components of a model.
@@ -294,16 +293,16 @@ namespace storm {
             storm::storage::sparse::StateStorage<StateType> stateStorage;
 
             // A priority queue of states that still need to be explored.
-            storm::storage::DynamicPriorityQueue<StateType, std::vector<StateType>, std::function<bool(StateType, StateType)>> explorationQueue;
+            storm::storage::DynamicPriorityQueue<ExplorationHeuristicPointer, std::vector<ExplorationHeuristicPointer>, std::function<bool(ExplorationHeuristicPointer, ExplorationHeuristicPointer)>> explorationQueue;
 
-            // A mapping of not yet explored states from the id to the state object.
-            std::map<StateType, DFTStatePointer> statesNotExplored;
+            // A mapping of not yet explored states from the id to the tuple (state object, heuristic values).
+            std::map<StateType, std::pair<DFTStatePointer, ExplorationHeuristicPointer>> statesNotExplored;
 
             // Holds all skipped states which were not yet expanded. More concretely it is a mapping from matrix indices
             // to the corresponding skipped states.
             // Notice that we need an ordered map here to easily iterate in increasing order over state ids.
             // TODO remove again
-            std::map<StateType, DFTStatePointer> skippedStates;
+            std::map<StateType, std::pair<DFTStatePointer, ExplorationHeuristicPointer>> skippedStates;
         };
 
     }
diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index f6bb692a7..70ff18122 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -6,7 +6,7 @@ namespace storm {
     namespace storage {
 
         template<typename ValueType>
-        DFTState<ValueType>::DFTState(DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(dft.stateVectorSize()), mId(id), mPseudoState(false), mDft(dft), mStateGenerationInfo(stateGenerationInfo), exploreHeuristic()  {
+        DFTState<ValueType>::DFTState(DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(dft.stateVectorSize()), mId(id), mPseudoState(false), mDft(dft), mStateGenerationInfo(stateGenerationInfo) {
             // TODO Matthias: use construct()
             
             // Initialize uses
@@ -37,7 +37,7 @@ namespace storm {
         }
 
         template<typename ValueType>
-        DFTState<ValueType>::DFTState(storm::storage::BitVector const& status, DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(status), mId(id), mPseudoState(true), mDft(dft), mStateGenerationInfo(stateGenerationInfo), exploreHeuristic() {
+        DFTState<ValueType>::DFTState(storm::storage::BitVector const& status, DFT<ValueType> const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(status), mId(id), mPseudoState(true), mDft(dft), mStateGenerationInfo(stateGenerationInfo) {
             // Intentionally left empty
         }
         
@@ -85,9 +85,7 @@ namespace storm {
 
         template<typename ValueType>
         std::shared_ptr<DFTState<ValueType>> DFTState<ValueType>::copy() const {
-            std::shared_ptr<DFTState<ValueType>> stateCopy = std::make_shared<storm::storage::DFTState<ValueType>>(*this);
-            stateCopy->exploreHeuristic = storm::builder::DFTExplorationHeuristic<ValueType>();
-            return stateCopy;
+            return std::make_shared<storm::storage::DFTState<ValueType>>(*this);
         }
 
         template<typename ValueType>
diff --git a/src/storage/dft/DFTState.h b/src/storage/dft/DFTState.h
index eb3164516..207eecac3 100644
--- a/src/storage/dft/DFTState.h
+++ b/src/storage/dft/DFTState.h
@@ -34,8 +34,7 @@ namespace storm {
             bool mValid = true;
             const DFT<ValueType>& mDft;
             const DFTStateGenerationInfo& mStateGenerationInfo;
-            storm::builder::DFTExplorationHeuristic<ValueType> exploreHeuristic;
-            
+
         public:
             /**
              * Construct the initial state.
@@ -123,26 +122,6 @@ namespace storm {
                 return mPseudoState;
             }
 
-            void setHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) {
-                exploreHeuristic.setHeuristicValues(depth, rate, exitRate);
-            }
-
-            void setHeuristicValues(std::shared_ptr<storm::storage::DFTState<ValueType>> oldState, ValueType rate, ValueType exitRate) {
-                if (hasFailed(mDft.getTopLevelIndex()) || isFailsafe(mDft.getTopLevelIndex()) || nrFailableDependencies() > 0 || (nrFailableDependencies() == 0 && nrFailableBEs() == 0)) {
-                    // Do not skip absorbing state or if reached by dependencies
-                    exploreHeuristic.setNotSkip();
-                }
-                exploreHeuristic.setHeuristicValues(oldState->exploreHeuristic.getDepth() + 1, rate, exitRate);
-            }
-
-            bool isSkip(double approximationThreshold, storm::builder::ApproximationHeuristic heuristic) {
-                return exploreHeuristic.isSkip(approximationThreshold, heuristic);
-            }
-
-            bool comparePriority(std::shared_ptr<DFTState> const& other, storm::builder::ApproximationHeuristic heuristic) {
-                return this->exploreHeuristic.compare(other->exploreHeuristic, heuristic);
-            }
-
             storm::storage::BitVector const& status() const {
                 return mStatus;
             }

From 82a3964e5dab0c6d9d0404a0efa08c576bb0a554 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Sat, 22 Oct 2016 18:30:26 +0200
Subject: [PATCH 33/65] Only fix queue when needed

Former-commit-id: 50231c4554e3bf6cdeeb7b6de37778fa3faedb3a
---
 src/builder/DftExplorationHeuristic.cpp       | 71 +++++--------------
 src/builder/DftExplorationHeuristic.h         | 66 +++++++++++++----
 src/builder/ExplicitDFTModelBuilderApprox.cpp |  3 +-
 3 files changed, 73 insertions(+), 67 deletions(-)

diff --git a/src/builder/DftExplorationHeuristic.cpp b/src/builder/DftExplorationHeuristic.cpp
index 4bc72ccc1..3b9c2e110 100644
--- a/src/builder/DftExplorationHeuristic.cpp
+++ b/src/builder/DftExplorationHeuristic.cpp
@@ -14,69 +14,34 @@ namespace storm {
             // Intentionally left empty
         }
 
-        template<typename ValueType>
-        void DFTExplorationHeuristic<ValueType>::updateHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) {
-            this->depth = std::min(this->depth, depth);
-            this->rate = std::max(this->rate, rate);
-            this->exitRate = std::max(this->exitRate, exitRate);
-        }
-
-        template<typename ValueType>
-        DFTExplorationHeuristicNone<ValueType>::DFTExplorationHeuristicNone(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
-            // Intentionally left empty
+        template<>
+        bool DFTExplorationHeuristicRateRatio<double>::updateHeuristicValues(size_t depth, double rate, double exitRate) {
+            bool update = false;
+            if (this->rate < rate) {
+                this->rate = rate;
+                update = true;
+            }
+            if (this->exitRate < exitRate) {
+                this->exitRate = exitRate;
+                update = true;
+            }
+            return update;
         }
 
-        template<typename ValueType>
-        bool DFTExplorationHeuristicNone<ValueType>::isSkip(double approximationThreshold) const {
+        template<>
+        bool DFTExplorationHeuristicRateRatio<storm::RationalFunction>::updateHeuristicValues(size_t depth, storm::RationalFunction rate, storm::RationalFunction exitRate) {
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work for rational functions.");
             return false;
         }
 
-        template<typename ValueType>
-        bool DFTExplorationHeuristicNone<ValueType>::operator<(DFTExplorationHeuristicNone<ValueType> const& other) const {
-            // Just use memory address for comparing
-            // TODO Matthias: better idea?
-            return this > &other;
-        }
-
-        template<typename ValueType>
-        DFTExplorationHeuristicDepth<ValueType>::DFTExplorationHeuristicDepth(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
-            // Intentionally left empty
-        }
-
-        template<typename ValueType>
-        bool DFTExplorationHeuristicDepth<ValueType>::isSkip(double approximationThreshold) const {
-            return !this->expand && this->depth > approximationThreshold;
-        }
-
-        template<typename ValueType>
-        bool DFTExplorationHeuristicDepth<ValueType>::operator<(DFTExplorationHeuristicDepth<ValueType> const& other) const {
-            return this->depth > other.depth;
-        }
-
-        template<typename ValueType>
-        DFTExplorationHeuristicRateRatio<ValueType>::DFTExplorationHeuristicRateRatio(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
-            // Intentionally left empty
-        }
-
-        template<typename ValueType>
-        bool DFTExplorationHeuristicRateRatio<ValueType>::isSkip(double approximationThreshold) const {
-            return !this->expand && this->getRateRatio() < approximationThreshold;
-        }
-
-        template<typename ValueType>
-        bool DFTExplorationHeuristicRateRatio<ValueType>::operator<(DFTExplorationHeuristicRateRatio<ValueType> const& other) const {
-            return this->getRateRatio() < other.getRateRatio();
-        }
-
-
         template<>
-        double DFTExplorationHeuristicRateRatio<double>::getRateRatio() const {
+        double DFTExplorationHeuristicRateRatio<double>::getPriority() const {
             return rate/exitRate;
         }
 
         template<>
-        double DFTExplorationHeuristicRateRatio<storm::RationalFunction>::getRateRatio() const {
-            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work.");
+        double DFTExplorationHeuristicRateRatio<storm::RationalFunction>::getPriority() const {
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work for rational functions.");
         }
 
 
diff --git a/src/builder/DftExplorationHeuristic.h b/src/builder/DftExplorationHeuristic.h
index 8f12d2ec1..2b4fc5047 100644
--- a/src/builder/DftExplorationHeuristic.h
+++ b/src/builder/DftExplorationHeuristic.h
@@ -22,7 +22,9 @@ namespace storm {
         public:
             DFTExplorationHeuristic(size_t id);
 
-            void updateHeuristicValues(size_t depth, ValueType rate, ValueType exitRate);
+            virtual bool updateHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) = 0;
+
+            virtual double getPriority() const = 0;
 
             virtual bool isSkip(double approximationThreshold) const = 0;
 
@@ -50,34 +52,74 @@ namespace storm {
         template<typename ValueType>
         class DFTExplorationHeuristicNone : public DFTExplorationHeuristic<ValueType> {
         public:
-            DFTExplorationHeuristicNone(size_t id);
+            DFTExplorationHeuristicNone(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
+                // Intentionally left empty
+            }
+
+            bool updateHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) override {
+                return false;
+            }
+
+            double getPriority() const override {
+                return this->id;
+            }
 
-            bool isSkip(double approximationThreshold) const override;
+            bool isSkip(double approximationThreshold) const override {
+                return false;
+            }
 
-            bool operator<(DFTExplorationHeuristicNone<ValueType> const& other) const;
+            bool operator<(DFTExplorationHeuristicNone<ValueType> const& other) const {
+                return this->id > other.id;
+            }
         };
 
         template<typename ValueType>
         class DFTExplorationHeuristicDepth : public DFTExplorationHeuristic<ValueType> {
         public:
-            DFTExplorationHeuristicDepth(size_t id);
+            DFTExplorationHeuristicDepth(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
+                // Intentionally left empty
+            }
+
+            bool updateHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) override {
+                if (depth < this->depth) {
+                    this->depth = depth;
+                    return true;
+                }
+                return false;
+            }
+
 
-            bool isSkip(double approximationThreshold) const override;
+            double getPriority() const override {
+                return this->depth;
+            }
+
+            bool isSkip(double approximationThreshold) const override {
+                return !this->expand && this->depth > approximationThreshold;
+            }
 
-            bool operator<(DFTExplorationHeuristicDepth<ValueType> const& other) const;
+            bool operator<(DFTExplorationHeuristicDepth<ValueType> const& other) const {
+                return this->depth > other.depth;
+            }
         };
 
         template<typename ValueType>
         class DFTExplorationHeuristicRateRatio : public DFTExplorationHeuristic<ValueType> {
         public:
-            DFTExplorationHeuristicRateRatio(size_t id);
+            DFTExplorationHeuristicRateRatio(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
+                // Intentionally left empty
+            }
 
-            bool isSkip(double approximationThreshold) const override;
+            bool updateHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) override;
 
-            bool operator<(DFTExplorationHeuristicRateRatio<ValueType> const& other) const;
+            double getPriority() const override;
 
-        private:
-            double getRateRatio() const;
+            bool isSkip(double approximationThreshold) const override {
+                return !this->expand && this->getPriority() < approximationThreshold;
+            }
+
+            bool operator<(DFTExplorationHeuristicRateRatio<ValueType> const& other) const {
+                return this->getPriority() < other.getPriority();
+            }
         };
 
     }
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 5595a5f49..ed7c1500d 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -290,8 +290,7 @@ namespace storm {
                                     // Do not skip absorbing state or if reached by dependencies
                                     iter->second.second->markExpand();
                                 }
-                                iter->second.second->updateHeuristicValues(currentExplorationHeuristic->getDepth() + 1, stateProbabilityPair.second, choice.getTotalMass());
-                                fixQueue = true;
+                                fixQueue = iter->second.second->updateHeuristicValues(currentExplorationHeuristic->getDepth() + 1, stateProbabilityPair.second, choice.getTotalMass());
                             }
                         }
                         matrixBuilder.finishRow();

From d1d77ff4df3b5d79a3ba956c61f17763012226d3 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Mon, 24 Oct 2016 15:20:03 +0200
Subject: [PATCH 34/65] Changed deque to vector in bisimulation to gain
 performance boost

Former-commit-id: 5db8e917b47000312198ad2e94773bec86912ebd
---
 .../BisimulationDecomposition.cpp             | 16 +++++------
 .../bisimulation/BisimulationDecomposition.h  |  8 +++---
 ...ministicModelBisimulationDecomposition.cpp | 28 +++++++++----------
 ...erministicModelBisimulationDecomposition.h | 10 +++----
 ...ministicModelBisimulationDecomposition.cpp | 14 +++++-----
 ...erministicModelBisimulationDecomposition.h |  8 +++---
 6 files changed, 42 insertions(+), 42 deletions(-)

diff --git a/src/storage/bisimulation/BisimulationDecomposition.cpp b/src/storage/bisimulation/BisimulationDecomposition.cpp
index 4b31551f9..33d4cffcc 100644
--- a/src/storage/bisimulation/BisimulationDecomposition.cpp
+++ b/src/storage/bisimulation/BisimulationDecomposition.cpp
@@ -230,25 +230,25 @@ namespace storm {
         
         template<typename ModelType, typename BlockDataType>
         void BisimulationDecomposition<ModelType, BlockDataType>::performPartitionRefinement() {
-            // Insert all blocks into the splitter queue as a (potential) splitter.
-            std::deque<Block<BlockDataType>*> splitterQueue;
-            std::for_each(partition.getBlocks().begin(), partition.getBlocks().end(), [&] (std::unique_ptr<Block<BlockDataType>> const& block) { block->data().setSplitter(); splitterQueue.push_back(block.get()); } );
+            // Insert all blocks into the splitter vector as a (potential) splitter.
+            std::vector<Block<BlockDataType>*> splitterVector;
+            std::for_each(partition.getBlocks().begin(), partition.getBlocks().end(), [&] (std::unique_ptr<Block<BlockDataType>> const& block) { block->data().setSplitter(); splitterVector.push_back(block.get()); } );
             
             // Then perform the actual splitting until there are no more splitters.
             uint_fast64_t iterations = 0;
-            while (!splitterQueue.empty()) {
+            while (!splitterVector.empty()) {
                 ++iterations;
 
                 // Get and prepare the next splitter.
                 // Sort the splitters according to their sizes to prefer small splitters. That is just a heuristic, but
                 // tends to work well.
-                std::sort(splitterQueue.begin(), splitterQueue.end(), [] (Block<BlockDataType> const* b1, Block<BlockDataType> const* b2) { return b1->getNumberOfStates() < b2->getNumberOfStates(); } );
-                Block<BlockDataType>* splitter = splitterQueue.front();
-                splitterQueue.pop_front();
+                std::sort(splitterVector.begin(), splitterVector.end(), [] (Block<BlockDataType> const* b1, Block<BlockDataType> const* b2) { return b1->getNumberOfStates() > b2->getNumberOfStates(); } );
+                Block<BlockDataType>* splitter = splitterVector.back();
+                splitterVector.pop_back();
                 splitter->data().setSplitter(false);
                 
                 // Now refine the partition using the current splitter.
-                refinePartitionBasedOnSplitter(*splitter, splitterQueue);
+                refinePartitionBasedOnSplitter(*splitter, splitterVector);
             }
         }
         
diff --git a/src/storage/bisimulation/BisimulationDecomposition.h b/src/storage/bisimulation/BisimulationDecomposition.h
index 6d86f2df9..df951bce3 100644
--- a/src/storage/bisimulation/BisimulationDecomposition.h
+++ b/src/storage/bisimulation/BisimulationDecomposition.h
@@ -1,7 +1,7 @@
 #ifndef STORM_STORAGE_BISIMULATIONDECOMPOSITION_H_
 #define STORM_STORAGE_BISIMULATIONDECOMPOSITION_H_
 
-#include <deque>
+#include <vector>
 
 #include "src/settings/SettingsManager.h"
 #include "src/settings/modules/BisimulationSettings.h"
@@ -219,12 +219,12 @@ namespace storm {
             
             /*!
              * Refines the partition by considering the given splitter. All blocks that become potential splitters
-             * because of this refinement, are marked as splitters and inserted into the splitter queue.
+             * because of this refinement, are marked as splitters and inserted into the splitter vector.
              *
              * @param splitter The splitter to use.
-             * @param splitterQueue The queue into which to insert the newly discovered potential splitters.
+             * @param splitterVector The vector into which to insert the newly discovered potential splitters.
              */
-            virtual void refinePartitionBasedOnSplitter(bisimulation::Block<BlockDataType>& splitter, std::deque<bisimulation::Block<BlockDataType>*>& splitterQueue) = 0;
+            virtual void refinePartitionBasedOnSplitter(bisimulation::Block<BlockDataType>& splitter, std::vector<bisimulation::Block<BlockDataType>*>& splitterVector) = 0;
             
             /*!
              * Builds the quotient model based on the previously computed equivalence classes (stored in the blocks
diff --git a/src/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp b/src/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp
index e968c98cd..dcc12fbfb 100644
--- a/src/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp
+++ b/src/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp
@@ -157,7 +157,7 @@ namespace storm {
         }
         
         template<typename ModelType>
-        void DeterministicModelBisimulationDecomposition<ModelType>::refinePredecessorBlocksOfSplitterStrong(std::list<Block<BlockDataType>*> const& predecessorBlocks, std::deque<bisimulation::Block<BlockDataType>*>& splitterQueue) {
+        void DeterministicModelBisimulationDecomposition<ModelType>::refinePredecessorBlocksOfSplitterStrong(std::list<Block<BlockDataType>*> const& predecessorBlocks, std::vector<bisimulation::Block<BlockDataType>*>& splitterVector) {
             for (auto block : predecessorBlocks) {
                 STORM_LOG_TRACE("Refining predecessor " << block->getId() << " of splitter");
 
@@ -176,15 +176,15 @@ namespace storm {
                                                     [this] (storm::storage::sparse::state_type state1, storm::storage::sparse::state_type state2) {
                                                         return this->comparator.isLess(getProbabilityToSplitter(state1), getProbabilityToSplitter(state2));
                                                     },
-                                                    [&splitterQueue] (Block<BlockDataType>& block) {
-                                                        splitterQueue.emplace_back(&block); block.data().setSplitter();
+                                                    [&splitterVector] (Block<BlockDataType>& block) {
+                                                        splitterVector.emplace_back(&block); block.data().setSplitter();
                                                     });
                 
                 
-                // If the predecessor block was split, we need to insert it into the splitter queue if it is not already
+                // If the predecessor block was split, we need to insert it into the splitter vector if it is not already
                 // marked as a splitter.
                 if (split && !blockToRefineProbabilistically->data().splitter()) {
-                    splitterQueue.emplace_back(blockToRefineProbabilistically);
+                    splitterVector.emplace_back(blockToRefineProbabilistically);
                     blockToRefineProbabilistically->data().setSplitter();
                 }
                 
@@ -378,7 +378,7 @@ namespace storm {
         }
         
         template<typename ModelType>
-        void DeterministicModelBisimulationDecomposition<ModelType>::refinePredecessorBlockOfSplitterWeak(bisimulation::Block<BlockDataType>& block, std::deque<bisimulation::Block<BlockDataType>*>& splitterQueue) {
+        void DeterministicModelBisimulationDecomposition<ModelType>::refinePredecessorBlockOfSplitterWeak(bisimulation::Block<BlockDataType>& block, std::vector<bisimulation::Block<BlockDataType>*>& splitterVector) {
             // First, we need to turn the one-step probabilities to go to the splitter to the conditional probabilities
             // for all non-silent states.
             computeConditionalProbabilitiesForNonSilentStates(block);
@@ -395,12 +395,12 @@ namespace storm {
                                                      [&weakStateLabels,&block,originalBlockIndex,this] (storm::storage::sparse::state_type state1, storm::storage::sparse::state_type state2) {
                                                          return weakStateLabels[this->partition.getPosition(state1) - originalBlockIndex] < weakStateLabels[this->partition.getPosition(state2) - originalBlockIndex];
                                                      },
-                                                     [this, &splitterQueue] (bisimulation::Block<BlockDataType>& block) {
+                                                     [this, &splitterVector] (bisimulation::Block<BlockDataType>& block) {
                                                          updateSilentProbabilitiesBasedOnTransitions(block);
                                                          
                                                          // Insert the new block as a splitter.
                                                          block.data().setSplitter();
-                                                         splitterQueue.emplace_back(&block);
+                                                         splitterVector.emplace_back(&block);
                                                      });
             
             // If the block was split, we also update the silent probabilities.
@@ -410,16 +410,16 @@ namespace storm {
                 if (!block.data().splitter()) {
                     // Insert the new block as a splitter.
                     block.data().setSplitter();
-                    splitterQueue.emplace_back(&block);
+                    splitterVector.emplace_back(&block);
                 }
             }
         }
         
         template<typename ModelType>
-        void DeterministicModelBisimulationDecomposition<ModelType>::refinePredecessorBlocksOfSplitterWeak(bisimulation::Block<BlockDataType>& splitter, std::list<bisimulation::Block<BlockDataType>*> const& predecessorBlocks, std::deque<bisimulation::Block<BlockDataType>*>& splitterQueue) {
+        void DeterministicModelBisimulationDecomposition<ModelType>::refinePredecessorBlocksOfSplitterWeak(bisimulation::Block<BlockDataType>& splitter, std::list<bisimulation::Block<BlockDataType>*> const& predecessorBlocks, std::vector<bisimulation::Block<BlockDataType>*>& splitterVector) {
             for (auto block : predecessorBlocks) {
                 if (*block != splitter) {
-                    refinePredecessorBlockOfSplitterWeak(*block, splitterQueue);
+                    refinePredecessorBlockOfSplitterWeak(*block, splitterVector);
                 } else {
                     // If the block to split is the splitter itself, we must not do any splitting here.
                 }
@@ -439,7 +439,7 @@ namespace storm {
         }
         
         template<typename ModelType>
-        void DeterministicModelBisimulationDecomposition<ModelType>::refinePartitionBasedOnSplitter(bisimulation::Block<BlockDataType>& splitter, std::deque<bisimulation::Block<BlockDataType>*>& splitterQueue) {
+        void DeterministicModelBisimulationDecomposition<ModelType>::refinePartitionBasedOnSplitter(bisimulation::Block<BlockDataType>& splitter, std::vector<bisimulation::Block<BlockDataType>*>& splitterVector) {
             STORM_LOG_TRACE("Refining partition based on splitter " << splitter.getId());
 
             // The outline of the refinement is as follows.
@@ -513,7 +513,7 @@ namespace storm {
             if (this->options.getType() == BisimulationType::Strong || this->model.getType() == storm::models::ModelType::Ctmc) {
                 // In the case of CTMCs and weak bisimulation, we still call the "splitStrong" method, but we already have
                 // taken care of not adding the splitter to the predecessor blocks, so this is safe.
-                refinePredecessorBlocksOfSplitterStrong(predecessorBlocks, splitterQueue);
+                refinePredecessorBlocksOfSplitterStrong(predecessorBlocks, splitterVector);
             } else {
                 // If the splitter is a predecessor of we can use the computed probabilities to update the silent
                 // probabilities.
@@ -521,7 +521,7 @@ namespace storm {
                     updateSilentProbabilitiesBasedOnProbabilitiesToSplitter(splitter);
                 }
                 
-                refinePredecessorBlocksOfSplitterWeak(splitter, predecessorBlocks, splitterQueue);
+                refinePredecessorBlocksOfSplitterWeak(splitter, predecessorBlocks, splitterVector);
             }
         }
         
diff --git a/src/storage/bisimulation/DeterministicModelBisimulationDecomposition.h b/src/storage/bisimulation/DeterministicModelBisimulationDecomposition.h
index b9f2a2a5a..b460dfa5d 100644
--- a/src/storage/bisimulation/DeterministicModelBisimulationDecomposition.h
+++ b/src/storage/bisimulation/DeterministicModelBisimulationDecomposition.h
@@ -39,11 +39,11 @@ namespace storm {
             
             virtual void buildQuotient() override;
             
-            virtual void refinePartitionBasedOnSplitter(bisimulation::Block<BlockDataType>& splitter, std::deque<bisimulation::Block<BlockDataType>*>& splitterQueue) override;
+            virtual void refinePartitionBasedOnSplitter(bisimulation::Block<BlockDataType>& splitter, std::vector<bisimulation::Block<BlockDataType>*>& splitterVector) override;
 
         private:
             // Refines the predecessor blocks wrt. strong bisimulation.
-            void refinePredecessorBlocksOfSplitterStrong(std::list<bisimulation::Block<BlockDataType>*> const& predecessorBlocks, std::deque<bisimulation::Block<BlockDataType>*>& splitterQueue);
+            void refinePredecessorBlocksOfSplitterStrong(std::list<bisimulation::Block<BlockDataType>*> const& predecessorBlocks, std::vector<bisimulation::Block<BlockDataType>*>& splitterVector);
 
             /*!
              * Performs the necessary steps to compute a weak bisimulation on a DTMC.
@@ -99,10 +99,10 @@ namespace storm {
             void updateSilentProbabilitiesBasedOnTransitions(bisimulation::Block<BlockDataType>& block);
             
             // Refines the predecessor blocks of the splitter wrt. weak bisimulation in DTMCs.
-            void refinePredecessorBlocksOfSplitterWeak(bisimulation::Block<BlockDataType>& splitter, std::list<bisimulation::Block<BlockDataType>*> const& predecessorBlocks, std::deque<bisimulation::Block<BlockDataType>*>& splitterQueue);
+            void refinePredecessorBlocksOfSplitterWeak(bisimulation::Block<BlockDataType>& splitter, std::list<bisimulation::Block<BlockDataType>*> const& predecessorBlocks, std::vector<bisimulation::Block<BlockDataType>*>& splitterVector);
             
             // Refines the given block wrt to weak bisimulation in DTMCs.
-            void refinePredecessorBlockOfSplitterWeak(bisimulation::Block<BlockDataType>& block, std::deque<bisimulation::Block<BlockDataType>*>& splitterQueue);
+            void refinePredecessorBlockOfSplitterWeak(bisimulation::Block<BlockDataType>& block, std::vector<bisimulation::Block<BlockDataType>*>& splitterVector);
             
             // Converts the one-step probabilities of going into the splitter into the conditional probabilities needed
             // for weak bisimulation (on DTMCs).
@@ -127,4 +127,4 @@ namespace storm {
     }
 }
 
-#endif /* STORM_STORAGE_BISIMULATION_DETERMINISTICMODELBISIMULATIONDECOMPOSITION_H_ */
\ No newline at end of file
+#endif /* STORM_STORAGE_BISIMULATION_DETERMINISTICMODELBISIMULATIONDECOMPOSITION_H_ */
diff --git a/src/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp b/src/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp
index 2e7d54113..fe53c6602 100644
--- a/src/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp
+++ b/src/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp
@@ -198,7 +198,7 @@ namespace storm {
         }
         
         template<typename ModelType>
-        void NondeterministicModelBisimulationDecomposition<ModelType>::updateQuotientDistributionsOfPredecessors(Block<BlockDataType> const& newBlock, Block<BlockDataType> const& oldBlock, std::deque<Block<BlockDataType>*>& splitterQueue) {
+        void NondeterministicModelBisimulationDecomposition<ModelType>::updateQuotientDistributionsOfPredecessors(Block<BlockDataType> const& newBlock, Block<BlockDataType> const& oldBlock, std::vector<Block<BlockDataType>*>& splitterVector) {
             uint_fast64_t lastState = 0;
             bool lastStateInitialized = false;
             
@@ -220,7 +220,7 @@ namespace storm {
                     // If the predecessor block is not marked as to-refined, we do so now.
                     if (!predecessorBlock.data().splitter()) {
                         predecessorBlock.data().setSplitter();
-                        splitterQueue.push_back(&predecessorBlock);
+                        splitterVector.push_back(&predecessorBlock);
                     }
                     
                     if (lastStateInitialized) {
@@ -332,7 +332,7 @@ namespace storm {
         }
         
         template<typename ModelType>
-        bool NondeterministicModelBisimulationDecomposition<ModelType>::splitBlockAccordingToCurrentQuotientDistributions(Block<BlockDataType>& block, std::deque<Block<BlockDataType>*>& splitterQueue) {
+        bool NondeterministicModelBisimulationDecomposition<ModelType>::splitBlockAccordingToCurrentQuotientDistributions(Block<BlockDataType>& block, std::vector<Block<BlockDataType>*>& splitterVector) {
             std::list<Block<BlockDataType>*> newBlocks;
             bool split = this->partition.splitBlock(block,
                                                     [this] (storm::storage::sparse::state_type state1, storm::storage::sparse::state_type state2) {
@@ -340,7 +340,7 @@ namespace storm {
 //                                                        std::cout << state1 << " is " << (!result ? "not" : "") << " smaller than " << state2 << std::endl;
                                                         return result;
                                                     },
-                                                    [this, &block, &splitterQueue, &newBlocks] (Block<BlockDataType>& newBlock) {
+                                                    [this, &block, &splitterVector, &newBlocks] (Block<BlockDataType>& newBlock) {
                                                         newBlocks.push_back(&newBlock);
                                                         
 //                                                        this->checkBlockStable(newBlock);
@@ -357,7 +357,7 @@ namespace storm {
             // defer updating the quotient distributions until *after* all splits, because
             // it otherwise influences the subsequent splits!
             for (auto el : newBlocks) {
-                this->updateQuotientDistributionsOfPredecessors(*el, block, splitterQueue);
+                this->updateQuotientDistributionsOfPredecessors(*el, block, splitterVector);
             }
             
 //            this->checkQuotientDistributions();
@@ -405,14 +405,14 @@ namespace storm {
         }
         
         template<typename ModelType>
-        void NondeterministicModelBisimulationDecomposition<ModelType>::refinePartitionBasedOnSplitter(bisimulation::Block<BlockDataType>& splitter, std::deque<bisimulation::Block<BlockDataType>*>& splitterQueue) {
+        void NondeterministicModelBisimulationDecomposition<ModelType>::refinePartitionBasedOnSplitter(bisimulation::Block<BlockDataType>& splitter, std::vector<bisimulation::Block<BlockDataType>*>& splitterVector) {
             if (!possiblyNeedsRefinement(splitter)) {
                 return;
             }
             
             STORM_LOG_TRACE("Refining block " << splitter.getId());
             
-            splitBlockAccordingToCurrentQuotientDistributions(splitter, splitterQueue);
+            splitBlockAccordingToCurrentQuotientDistributions(splitter, splitterVector);
         }
         
         template class NondeterministicModelBisimulationDecomposition<storm::models::sparse::Mdp<double>>;
diff --git a/src/storage/bisimulation/NondeterministicModelBisimulationDecomposition.h b/src/storage/bisimulation/NondeterministicModelBisimulationDecomposition.h
index 18a6e8e58..38feaf36a 100644
--- a/src/storage/bisimulation/NondeterministicModelBisimulationDecomposition.h
+++ b/src/storage/bisimulation/NondeterministicModelBisimulationDecomposition.h
@@ -37,7 +37,7 @@ namespace storm {
             
             virtual void buildQuotient() override;
             
-            virtual void refinePartitionBasedOnSplitter(bisimulation::Block<BlockDataType>& splitter, std::deque<bisimulation::Block<BlockDataType>*>& splitterQueue) override;
+            virtual void refinePartitionBasedOnSplitter(bisimulation::Block<BlockDataType>& splitter, std::vector<bisimulation::Block<BlockDataType>*>& splitterVector) override;
             
             virtual void initialize() override;
             
@@ -52,7 +52,7 @@ namespace storm {
             bool possiblyNeedsRefinement(bisimulation::Block<BlockDataType> const& block) const;
             
             // Splits the given block according to the current quotient distributions.
-            bool splitBlockAccordingToCurrentQuotientDistributions(bisimulation::Block<BlockDataType>& block, std::deque<bisimulation::Block<BlockDataType>*>& splitterQueue);
+            bool splitBlockAccordingToCurrentQuotientDistributions(bisimulation::Block<BlockDataType>& block, std::vector<bisimulation::Block<BlockDataType>*>& splitterVector);
             
             // Retrieves whether the quotient distributions of state 1 are considered to be less than the ones of state 2.
             bool quotientDistributionsLess(storm::storage::sparse::state_type state1, storm::storage::sparse::state_type state2) const;
@@ -62,7 +62,7 @@ namespace storm {
             
             // Updates the quotient distributions of the predecessors of the new block by taking the probability mass
             // away from the old block.
-            void updateQuotientDistributionsOfPredecessors(bisimulation::Block<BlockDataType> const& newBlock, bisimulation::Block<BlockDataType> const& oldBlock, std::deque<bisimulation::Block<BlockDataType>*>& splitterQueue);
+            void updateQuotientDistributionsOfPredecessors(bisimulation::Block<BlockDataType> const& newBlock, bisimulation::Block<BlockDataType> const& oldBlock, std::vector<bisimulation::Block<BlockDataType>*>& splitterVector);
             
             bool checkQuotientDistributions() const;
             bool checkBlockStable(bisimulation::Block<BlockDataType> const& newBlock) const;
@@ -81,4 +81,4 @@ namespace storm {
     }
 }
 
-#endif /* STORM_STORAGE_BISIMULATION_NONDETERMINISTICMODELBISIMULATIONDECOMPOSITION_H_ */
\ No newline at end of file
+#endif /* STORM_STORAGE_BISIMULATION_NONDETERMINISTICMODELBISIMULATIONDECOMPOSITION_H_ */

From 8d38358c115dda77d55c001c2f8178c2f52aebbb Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Mon, 24 Oct 2016 17:28:56 +0200
Subject: [PATCH 35/65] Use BucketPriorityQueue instead of DynamicPriorityQueue

Former-commit-id: 7a22ef5b1671b4a33319e4cc6c98bff2e473aa77
---
 src/builder/DftExplorationHeuristic.cpp       |  22 +-
 src/builder/DftExplorationHeuristic.h         |  12 +-
 src/builder/ExplicitDFTModelBuilderApprox.cpp |  55 +++--
 src/builder/ExplicitDFTModelBuilderApprox.h   |   9 +-
 src/storage/BucketPriorityQueue.cpp           | 191 ++++++++++++++++++
 src/storage/BucketPriorityQueue.h             |  70 +++++++
 6 files changed, 320 insertions(+), 39 deletions(-)
 create mode 100644 src/storage/BucketPriorityQueue.cpp
 create mode 100644 src/storage/BucketPriorityQueue.h

diff --git a/src/builder/DftExplorationHeuristic.cpp b/src/builder/DftExplorationHeuristic.cpp
index 3b9c2e110..dbd64088b 100644
--- a/src/builder/DftExplorationHeuristic.cpp
+++ b/src/builder/DftExplorationHeuristic.cpp
@@ -4,28 +4,20 @@
 #include "src/utility/constants.h"
 #include "src/exceptions/NotImplementedException.h"
 
-#include <limits>
-
 namespace storm {
     namespace builder {
 
         template<typename ValueType>
-        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic(size_t id) : id(id), expand(false), depth(std::numeric_limits<std::size_t>::max()), rate(storm::utility::zero<ValueType>()), exitRate(storm::utility::zero<ValueType>()) {
-            // Intentionally left empty
+        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic(size_t id, size_t depth, ValueType rate, ValueType exitRate) : id(id), expand(false), depth(depth) {
+            STORM_LOG_ASSERT(storm::utility::zero<ValueType>() < exitRate, "Exit rate is 0");
+            rateRatio = rate/exitRate;
         }
 
         template<>
         bool DFTExplorationHeuristicRateRatio<double>::updateHeuristicValues(size_t depth, double rate, double exitRate) {
-            bool update = false;
-            if (this->rate < rate) {
-                this->rate = rate;
-                update = true;
-            }
-            if (this->exitRate < exitRate) {
-                this->exitRate = exitRate;
-                update = true;
-            }
-            return update;
+            STORM_LOG_ASSERT(exitRate > 0, "Exit rate is 0");
+            rateRatio += rate/exitRate;
+            return true;
         }
 
         template<>
@@ -36,7 +28,7 @@ namespace storm {
 
         template<>
         double DFTExplorationHeuristicRateRatio<double>::getPriority() const {
-            return rate/exitRate;
+            return rateRatio;
         }
 
         template<>
diff --git a/src/builder/DftExplorationHeuristic.h b/src/builder/DftExplorationHeuristic.h
index 2b4fc5047..d23c673fc 100644
--- a/src/builder/DftExplorationHeuristic.h
+++ b/src/builder/DftExplorationHeuristic.h
@@ -20,7 +20,7 @@ namespace storm {
         class DFTExplorationHeuristic {
 
         public:
-            DFTExplorationHeuristic(size_t id);
+            DFTExplorationHeuristic(size_t id, size_t depth, ValueType rate, ValueType exitRate);
 
             virtual bool updateHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) = 0;
 
@@ -44,15 +44,13 @@ namespace storm {
             size_t id;
             bool expand;
             size_t depth;
-            ValueType rate;
-            ValueType exitRate;
-
+            ValueType rateRatio;
         };
 
         template<typename ValueType>
         class DFTExplorationHeuristicNone : public DFTExplorationHeuristic<ValueType> {
         public:
-            DFTExplorationHeuristicNone(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
+            DFTExplorationHeuristicNone(size_t id, size_t depth, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, depth, rate, exitRate) {
                 // Intentionally left empty
             }
 
@@ -76,7 +74,7 @@ namespace storm {
         template<typename ValueType>
         class DFTExplorationHeuristicDepth : public DFTExplorationHeuristic<ValueType> {
         public:
-            DFTExplorationHeuristicDepth(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
+            DFTExplorationHeuristicDepth(size_t id, size_t depth, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, depth, rate, exitRate) {
                 // Intentionally left empty
             }
 
@@ -105,7 +103,7 @@ namespace storm {
         template<typename ValueType>
         class DFTExplorationHeuristicRateRatio : public DFTExplorationHeuristic<ValueType> {
         public:
-            DFTExplorationHeuristicRateRatio(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
+            DFTExplorationHeuristicRateRatio(size_t id, size_t depth, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, depth, rate, exitRate) {
                 // Intentionally left empty
             }
 
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index ed7c1500d..07863bb01 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -31,11 +31,13 @@ namespace storm {
                 generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates),
                 matrixBuilder(!generator.isDeterministicModel()),
                 stateStorage(((dft.stateVectorSize() / 64) + 1) * 64),
-                explorationQueue([this](ExplorationHeuristicPointer a, ExplorationHeuristicPointer b) {
-                        return *a < *b;
-                    })
+                // TODO Matthias: make choosable
+                //explorationQueue(dft.nrElements(), 0, 1)
+                explorationQueue(41, 0, 1.0/20)
         {
             // Intentionally left empty.
+            // TODO Matthias: remove again
+            heuristic = storm::builder::ApproximationHeuristic::RATERATIO;
         }
 
         template<typename ValueType, typename StateType>
@@ -76,7 +78,11 @@ namespace storm {
                 initialStateIndex = stateStorage.initialStateIndices[0];
                 STORM_LOG_TRACE("Initial state: " << initialStateIndex);
                 // Initialize heuristic values for inital state
-                statesNotExplored.at(initialStateIndex).second->updateHeuristicValues(0, storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>());
+                STORM_LOG_ASSERT(!statesNotExplored.at(initialStateIndex).second, "Heuristic for initial state is already initialized");
+                ExplorationHeuristicPointer heuristic = std::make_shared<ExplorationHeuristic>(initialStateIndex, 0, storm::utility::zero<ValueType>(), storm::utility::one<ValueType>());
+                heuristic->markExpand();
+                statesNotExplored[initialStateIndex].second = heuristic;
+                explorationQueue.push(heuristic);
             } else {
                 initializeNextIteration();
             }
@@ -84,6 +90,7 @@ namespace storm {
             switch (heuristic) {
                 case storm::builder::ApproximationHeuristic::NONE:
                     // Do not change anything
+                    approximationThreshold = 0;
                     break;
                 case storm::builder::ApproximationHeuristic::DEPTH:
                     approximationThreshold = iteration;
@@ -225,8 +232,12 @@ namespace storm {
         void ExplicitDFTModelBuilderApprox<ValueType, StateType>::exploreStateSpace(double approximationThreshold) {
             size_t nrExpandedStates = 0;
             size_t nrSkippedStates = 0;
+            size_t fix = 0;
             // TODO Matthias: do not empty queue every time but break before
             while (!explorationQueue.empty()) {
+                explorationQueue.fix();
+                //explorationQueue.print(std::cout);
+                //printNotExplored();
                 // Get the first state in the queue
                 ExplorationHeuristicPointer currentExplorationHeuristic = explorationQueue.popTop();
                 StateType currentId = currentExplorationHeuristic->getId();
@@ -253,7 +264,6 @@ namespace storm {
                 matrixBuilder.newRowGroup();
 
                 // Try to explore the next state
-                bool fixQueue = false;
                 generator.load(currentState);
 
                 if (currentExplorationHeuristic->isSkip(approximationThreshold)) {
@@ -286,22 +296,31 @@ namespace storm {
                             if (iter != statesNotExplored.end()) {
                                 // Update heuristic values
                                 DFTStatePointer state = iter->second.first;
+                                if (!iter->second.second) {
+                                    // Initialize heuristic values
+                                    ExplorationHeuristicPointer heuristic = std::make_shared<ExplorationHeuristic>(stateProbabilityPair.first, currentExplorationHeuristic->getDepth() + 1, stateProbabilityPair.second, choice.getTotalMass());
+                                    iter->second.second = heuristic;
+                                    explorationQueue.push(heuristic);
+                                } else {
+                                    double oldPriority = iter->second.second->getPriority();
+                                    if (iter->second.second->updateHeuristicValues(currentExplorationHeuristic->getDepth() + 1, stateProbabilityPair.second, choice.getTotalMass())) {
+                                        // Update priority queue
+                                        ++fix;
+                                        explorationQueue.update(iter->second.second, oldPriority);
+                                    }
+                                }
                                 if (state->hasFailed(dft.getTopLevelIndex()) || state->isFailsafe(dft.getTopLevelIndex()) || state->nrFailableDependencies() > 0 || (state->nrFailableDependencies() == 0 && state->nrFailableBEs() == 0)) {
                                     // Do not skip absorbing state or if reached by dependencies
                                     iter->second.second->markExpand();
+                                    // TODO Matthias give highest priority to ensure expanding before all skipped
                                 }
-                                fixQueue = iter->second.second->updateHeuristicValues(currentExplorationHeuristic->getDepth() + 1, stateProbabilityPair.second, choice.getTotalMass());
                             }
                         }
                         matrixBuilder.finishRow();
                     }
                 }
-
-                // Update priority queue
-                if (fixQueue) {
-                    explorationQueue.fix();
-                }
             } // end exploration
+            std::cout << "Fixed queue " << fix << " times" << std::endl;
 
             STORM_LOG_INFO("Expanded " << nrExpandedStates << " states");
             STORM_LOG_INFO("Skipped " << nrSkippedStates << " states");
@@ -502,9 +521,8 @@ namespace storm {
                 stateId = stateStorage.stateToId.findOrAdd(state->status(), state->getId());
                 STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not match.");
                 // Insert state as not yet explored
-                ExplorationHeuristicPointer heuristic = std::make_shared<ExplorationHeuristic>(stateId);
-                statesNotExplored[stateId] = std::make_pair(state, heuristic);
-                explorationQueue.push(heuristic);
+                ExplorationHeuristicPointer nullHeuristic;
+                statesNotExplored[stateId] = std::make_pair(state, nullHeuristic);
                 // Reserve one slot for the new state in the remapping
                 matrixBuilder.stateRemapping.push_back(0);
                 STORM_LOG_TRACE("New " << (state->isPseudoState() ? "pseudo" : "concrete") << " state: " << dft.getStateString(state));
@@ -521,6 +539,15 @@ namespace storm {
             modelComponents.markovianStates.set(matrixBuilder.getCurrentRowGroup() - 1, markovian);
         }
 
+        template<typename ValueType, typename StateType>
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::printNotExplored() const {
+            std::cout << "states not explored:" << std::endl;
+            for (auto it : statesNotExplored) {
+                std::cout << it.first << " -> " << dft.getStateString(it.second.first) << std::endl;
+            }
+        }
+
+
         // Explicitly instantiate the class.
         template class ExplicitDFTModelBuilderApprox<double>;
 
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index 4238194eb..e23a8e819 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -10,7 +10,7 @@
 #include "src/storage/sparse/StateStorage.h"
 #include "src/storage/dft/DFT.h"
 #include "src/storage/dft/SymmetricUnits.h"
-#include "src/storage/DynamicPriorityQueue.h"
+#include "src/storage/BucketPriorityQueue.h"
 #include <boost/container/flat_set.hpp>
 #include <boost/optional/optional.hpp>
 #include <stack>
@@ -28,7 +28,7 @@ namespace storm {
 
             using DFTStatePointer = std::shared_ptr<storm::storage::DFTState<ValueType>>;
             // TODO Matthias: make choosable
-            using ExplorationHeuristic = DFTExplorationHeuristicNone<ValueType>;
+            using ExplorationHeuristic = DFTExplorationHeuristicRateRatio<ValueType>;
             using ExplorationHeuristicPointer = std::shared_ptr<ExplorationHeuristic>;
 
 
@@ -240,6 +240,8 @@ namespace storm {
              */
             bool isPriorityGreater(StateType idA, StateType idB) const;
 
+            void printNotExplored() const;
+
             /*!
              * Create the model model from the model components.
              *
@@ -293,7 +295,8 @@ namespace storm {
             storm::storage::sparse::StateStorage<StateType> stateStorage;
 
             // A priority queue of states that still need to be explored.
-            storm::storage::DynamicPriorityQueue<ExplorationHeuristicPointer, std::vector<ExplorationHeuristicPointer>, std::function<bool(ExplorationHeuristicPointer, ExplorationHeuristicPointer)>> explorationQueue;
+            storm::storage::BucketPriorityQueue<ValueType> explorationQueue;
+            //storm::storage::DynamicPriorityQueue<ExplorationHeuristicPointer, std::vector<ExplorationHeuristicPointer>, std::function<bool(ExplorationHeuristicPointer, ExplorationHeuristicPointer)>> explorationQueue;
 
             // A mapping of not yet explored states from the id to the tuple (state object, heuristic values).
             std::map<StateType, std::pair<DFTStatePointer, ExplorationHeuristicPointer>> statesNotExplored;
diff --git a/src/storage/BucketPriorityQueue.cpp b/src/storage/BucketPriorityQueue.cpp
new file mode 100644
index 000000000..e87e25506
--- /dev/null
+++ b/src/storage/BucketPriorityQueue.cpp
@@ -0,0 +1,191 @@
+#include "src/storage/BucketPriorityQueue.h"
+#include "src/utility/macros.h"
+#include "src/adapters/CarlAdapter.h"
+
+namespace storm {
+    namespace storage {
+
+        template<typename ValueType>
+        BucketPriorityQueue<ValueType>::BucketPriorityQueue(size_t nrBuckets, double lowerValue, double stepPerBucket) : buckets(nrBuckets), currentBucket(nrBuckets), lowerValue(lowerValue), stepPerBucket(stepPerBucket), nrUnsortedItems(0) {
+            compare = ([this](HeuristicPointer a, HeuristicPointer b) {
+                return *a < *b;
+            });
+        }
+
+        template<typename ValueType>
+        void BucketPriorityQueue<ValueType>::fix() {
+            if (currentBucket < buckets.size() && nrUnsortedItems > 0) {
+                // Fix current bucket
+                std::make_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
+                nrUnsortedItems = 0;
+            }
+        }
+
+        template<typename ValueType>
+        bool BucketPriorityQueue<ValueType>::empty() const {
+            return currentBucket == buckets.size();
+        }
+
+        template<typename ValueType>
+        std::size_t BucketPriorityQueue<ValueType>::size() const {
+            size_t size = 0;
+            for (size_t i = currentBucket; currentBucket < buckets.size(); ++i) {
+                size += buckets[i].size();
+            }
+            STORM_LOG_ASSERT(size == heuristicMapping.size(), "Sizes to not coincide");
+            return size;
+        }
+
+        template<typename ValueType>
+        typename BucketPriorityQueue<ValueType>::HeuristicPointer const& BucketPriorityQueue<ValueType>::top() const {
+            STORM_LOG_ASSERT(!empty(), "BucketPriorityQueue is empty");
+            STORM_LOG_ASSERT(nrUnsortedItems == 0, "First bucket is not sorted");
+            return buckets[currentBucket].front();
+        }
+
+        template<typename ValueType>
+        void BucketPriorityQueue<ValueType>::push(HeuristicPointer const& item) {
+            size_t bucket = getBucket(item->getPriority());
+            if (bucket < currentBucket) {
+                setMappingBucket(currentBucket);
+                currentBucket = bucket;
+                nrUnsortedItems = 0;
+            }
+            buckets[bucket].push_back(item);
+            if (bucket == currentBucket) {
+                // Insert in first bucket
+                if (AUTOSORT) {
+                    std::push_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
+                } else {
+                    ++nrUnsortedItems;
+                }
+            }
+            // Set mapping
+            heuristicMapping[item->getId()] = std::make_pair(bucket, buckets[bucket].size() - 1);
+        }
+
+        template<typename ValueType>
+        void BucketPriorityQueue<ValueType>::update(HeuristicPointer const& item, double oldPriority) {
+            size_t newBucket = getBucket(item->getPriority());
+            size_t oldBucket = getBucket(oldPriority);
+
+            if (oldBucket == newBucket) {
+                if (currentBucket < newBucket) {
+                    // No change as the bucket is not sorted yet
+                } else {
+                    if (AUTOSORT) {
+                        // Sort first bucket
+                        fix();
+                    } else {
+                        ++nrUnsortedItems;
+                    }
+                }
+            } else {
+                // Move to new bucket
+                STORM_LOG_ASSERT(newBucket < oldBucket, "Will update to higher bucket");
+                if (newBucket < currentBucket) {
+                    setMappingBucket(currentBucket);
+                    currentBucket = newBucket;
+                    nrUnsortedItems = 0;
+                }
+                // Remove old entry by swap-and-pop
+                if (buckets[oldBucket].size() >= 2) {
+                    size_t oldIndex = heuristicMapping.at(item->getId()).second;
+                    std::iter_swap(buckets[oldBucket].begin() + oldIndex, buckets[oldBucket].end() - 1);
+                    // Set mapping for swapped item
+                    heuristicMapping[buckets[oldBucket][oldIndex]->getId()] = std::make_pair(oldBucket, oldIndex);
+                }
+                buckets[oldBucket].pop_back();
+                // Insert new element
+                buckets[newBucket].push_back(item);
+                if (newBucket == currentBucket) {
+                    if (AUTOSORT) {
+                        // Sort in first bucket
+                        std::push_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
+                    } else {
+                        ++nrUnsortedItems;
+                    }
+                }
+                // Set mapping
+                heuristicMapping[item->getId()] = std::make_pair(newBucket, buckets[newBucket].size() - 1);
+            }
+        }
+
+
+        template<typename ValueType>
+        void BucketPriorityQueue<ValueType>::pop() {
+            STORM_LOG_ASSERT(!empty(), "BucketPriorityQueue is empty");
+            STORM_LOG_ASSERT(nrUnsortedItems == 0, "First bucket is not sorted");
+            std::pop_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
+            // Remove from mapping
+            heuristicMapping.erase(buckets[currentBucket].back()->getId());
+            buckets[currentBucket].pop_back();
+            if (buckets[currentBucket].empty()) {
+                // Find next bucket with elements
+                for ( ; currentBucket < buckets.size(); ++currentBucket) {
+                    if (!buckets[currentBucket].empty()) {
+                        nrUnsortedItems = buckets[currentBucket].size();
+                        if (AUTOSORT) {
+                            fix();
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+
+        template<typename ValueType>
+        typename BucketPriorityQueue<ValueType>::HeuristicPointer BucketPriorityQueue<ValueType>::popTop() {
+            HeuristicPointer item = top();
+            pop();
+            return item;
+        }
+
+        template<typename ValueType>
+        size_t BucketPriorityQueue<ValueType>::getBucket(double priority) const {
+            STORM_LOG_ASSERT(priority >= lowerValue, "Priority " << priority << " is too low");
+            size_t newBucket = (priority - lowerValue) / stepPerBucket;
+            if (HIGHER) {
+                newBucket = buckets.size()-1 - newBucket;
+            }
+            //std::cout << "get Bucket: " << priority << ", " << newBucket << ", " << ((priority - lowerValue) / stepPerBucket) << std::endl;
+            STORM_LOG_ASSERT(newBucket < buckets.size(), "Priority " << priority << " is too high");
+            return newBucket;
+        }
+
+        template<typename ValueType>
+        void BucketPriorityQueue<ValueType>::setMappingBucket(size_t bucket) {
+            if (bucket < buckets.size()) {
+                for (size_t index = 0; index < buckets[bucket].size(); ++index) {
+                    heuristicMapping[buckets[bucket][index]->getId()] = std::make_pair(bucket, index);
+                }
+            }
+        }
+
+        template<typename ValueType>
+        void BucketPriorityQueue<ValueType>::print(std::ostream& out) const {
+            out << "Bucket priority queue with size " << buckets.size() << ", lower value: " << lowerValue << " and step per bucket: " << stepPerBucket << std::endl;
+            out << "Current bucket (" << currentBucket << ") has " << nrUnsortedItems  << " unsorted items" << std::endl;
+            for (size_t bucket = 0; bucket < buckets.size(); ++bucket) {
+                if (!buckets[bucket].empty()) {
+                    out << "Bucket " << bucket << " (" << (HIGHER ? buckets.size() -1 - bucket * stepPerBucket : bucket * stepPerBucket) << "):" << std::endl;
+                    for (HeuristicPointer heuristic : buckets[bucket]) {
+                        out << "\t" << heuristic->getId() << ": " << heuristic->getPriority() << std::endl;
+                    }
+                }
+            }
+            out << "Mapping:" << std::endl;
+            for (auto it : heuristicMapping) {
+                out << it.first << " -> " << it.second.first << ", " << it.second.second << std::endl;
+            }
+        }
+
+
+        // Template instantiations
+        template class BucketPriorityQueue<double>;
+
+#ifdef STORM_HAVE_CARL
+        template class BucketPriorityQueue<storm::RationalFunction>;
+#endif
+    }
+}
diff --git a/src/storage/BucketPriorityQueue.h b/src/storage/BucketPriorityQueue.h
new file mode 100644
index 000000000..a08bfbd3b
--- /dev/null
+++ b/src/storage/BucketPriorityQueue.h
@@ -0,0 +1,70 @@
+#ifndef STORM_STORAGE_BUCKETPRIORITYQUEUE_H_
+#define STORM_STORAGE_BUCKETPRIORITYQUEUE_H_
+
+#include "src/builder/DftExplorationHeuristic.h"
+#include <algorithm>
+#include <functional>
+#include <unordered_map>
+#include <vector>
+
+namespace storm {
+    namespace storage {
+
+        template<typename ValueType>
+        class BucketPriorityQueue {
+
+            using HeuristicPointer = std::shared_ptr<storm::builder::DFTExplorationHeuristicRateRatio<ValueType>>;
+
+        public:
+            explicit BucketPriorityQueue(size_t nrBuckets, double lowerValue, double stepPerBucket);
+
+            void fix();
+
+            bool empty() const;
+
+            std::size_t size() const;
+
+            HeuristicPointer const& top() const;
+
+            void push(HeuristicPointer const& item);
+
+            void update(HeuristicPointer const& item, double oldPriority);
+
+            void pop();
+
+            HeuristicPointer popTop();
+
+            void print(std::ostream& out) const;
+
+        private:
+
+            size_t getBucket(double priority) const;
+
+            void setMappingBucket(size_t bucket);
+
+            // List of buckets
+            std::vector<std::vector<HeuristicPointer>> buckets;
+
+            // Index of first bucket which contains items
+            size_t currentBucket;
+
+            // Mapping from id to (bucket, index in bucket)
+            std::unordered_map<size_t, std::pair<size_t, size_t>> heuristicMapping;
+
+            std::function<bool(HeuristicPointer, HeuristicPointer)> compare;
+
+            double lowerValue;
+
+            double stepPerBucket;
+
+            size_t nrUnsortedItems;
+
+            const bool HIGHER = true;
+
+            const bool AUTOSORT = false;
+        };
+
+    }
+}
+
+#endif // STORM_STORAGE_BUCKETPRIORITYQUEUE_H_

From ef7d4ac87b564cdc62096c96b658b29524924563 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Mon, 24 Oct 2016 17:29:14 +0200
Subject: [PATCH 36/65] Do not sort BEs anymore

Former-commit-id: 1789ad3644a4dbbb3b58764831e4d5f5b0147aa2
---
 src/storage/dft/DFTState.cpp | 14 +-------------
 src/storage/dft/DFTState.h   |  5 -----
 2 files changed, 1 insertion(+), 18 deletions(-)

diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index 70ff18122..0b2ff7ee8 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -32,8 +32,6 @@ namespace storm {
                 STORM_LOG_ASSERT(it != mCurrentlyNotFailableBE.end(), "Id not found.");
                 mCurrentlyNotFailableBE.erase(it);
             }
-
-            sortFailableBEs();
         }
 
         template<typename ValueType>
@@ -69,8 +67,7 @@ namespace storm {
                     STORM_LOG_TRACE("Spare " << index << " uses " << useId);
                 }
             }
-            sortFailableBEs();
-            
+
             // Initialize failable dependencies
             for (size_t dependencyId : mDft.getDependencies()) {
                 std::shared_ptr<DFTDependency<ValueType> const> dependency = mDft.getDependency(dependencyId);
@@ -324,7 +321,6 @@ namespace storm {
                     propagateActivation(uses(elem));
                 }
             }
-            sortFailableBEs();
         }
 
         template<typename ValueType>
@@ -422,14 +418,6 @@ namespace storm {
             }
             return changed;
         }
-        
-        template<typename ValueType>
-        void DFTState<ValueType>::sortFailableBEs() {
-            std::sort(mCurrentlyFailableBE.begin( ), mCurrentlyFailableBE.end( ), [&](size_t const& lhs, size_t const& rhs) {
-                // Sort decreasing
-                return getBERate(rhs, true) < getBERate(lhs, true);
-            });
-        }
 
 
         // Explicitly instantiate the class.
diff --git a/src/storage/dft/DFTState.h b/src/storage/dft/DFTState.h
index 207eecac3..4ff36d1ab 100644
--- a/src/storage/dft/DFTState.h
+++ b/src/storage/dft/DFTState.h
@@ -313,11 +313,6 @@ namespace storm {
              */
             ValueType getBERate(size_t id, bool considerPassive) const;
 
-            /*!
-             * Sort failable BEs in decreasing order of their active failure rate.
-             */
-            void sortFailableBEs();
-
         };
 
     }

From 815bbf10abd7c5cdc2d30a476f0f8d7ab6a6c908 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Mon, 24 Oct 2016 18:27:27 +0200
Subject: [PATCH 37/65] Remove map and use linear search in BucketPriorityQueue

Former-commit-id: 3fc131facb4ad1a582ba3245292b5a3443343c35
---
 src/storage/BucketPriorityQueue.cpp | 34 ++++++++---------------------
 src/storage/BucketPriorityQueue.h   |  5 -----
 2 files changed, 9 insertions(+), 30 deletions(-)

diff --git a/src/storage/BucketPriorityQueue.cpp b/src/storage/BucketPriorityQueue.cpp
index e87e25506..bc3ca8780 100644
--- a/src/storage/BucketPriorityQueue.cpp
+++ b/src/storage/BucketPriorityQueue.cpp
@@ -32,7 +32,6 @@ namespace storm {
             for (size_t i = currentBucket; currentBucket < buckets.size(); ++i) {
                 size += buckets[i].size();
             }
-            STORM_LOG_ASSERT(size == heuristicMapping.size(), "Sizes to not coincide");
             return size;
         }
 
@@ -47,7 +46,6 @@ namespace storm {
         void BucketPriorityQueue<ValueType>::push(HeuristicPointer const& item) {
             size_t bucket = getBucket(item->getPriority());
             if (bucket < currentBucket) {
-                setMappingBucket(currentBucket);
                 currentBucket = bucket;
                 nrUnsortedItems = 0;
             }
@@ -60,8 +58,6 @@ namespace storm {
                     ++nrUnsortedItems;
                 }
             }
-            // Set mapping
-            heuristicMapping[item->getId()] = std::make_pair(bucket, buckets[bucket].size() - 1);
         }
 
         template<typename ValueType>
@@ -84,16 +80,21 @@ namespace storm {
                 // Move to new bucket
                 STORM_LOG_ASSERT(newBucket < oldBucket, "Will update to higher bucket");
                 if (newBucket < currentBucket) {
-                    setMappingBucket(currentBucket);
                     currentBucket = newBucket;
                     nrUnsortedItems = 0;
                 }
                 // Remove old entry by swap-and-pop
                 if (buckets[oldBucket].size() >= 2) {
-                    size_t oldIndex = heuristicMapping.at(item->getId()).second;
+                    // Find old index by linear search
+                    // Notice: using a map to rememeber index was not efficient
+                    size_t oldIndex = 0;
+                    for ( ; oldIndex < buckets[oldBucket].size(); ++oldIndex) {
+                        if (buckets[oldBucket][oldIndex]->getId() == item->getId()) {
+                            break;
+                        }
+                    }
+                    STORM_LOG_ASSERT(oldIndex < buckets[oldBucket].size(), "Id " << item->getId() << " not found");
                     std::iter_swap(buckets[oldBucket].begin() + oldIndex, buckets[oldBucket].end() - 1);
-                    // Set mapping for swapped item
-                    heuristicMapping[buckets[oldBucket][oldIndex]->getId()] = std::make_pair(oldBucket, oldIndex);
                 }
                 buckets[oldBucket].pop_back();
                 // Insert new element
@@ -106,8 +107,6 @@ namespace storm {
                         ++nrUnsortedItems;
                     }
                 }
-                // Set mapping
-                heuristicMapping[item->getId()] = std::make_pair(newBucket, buckets[newBucket].size() - 1);
             }
         }
 
@@ -117,8 +116,6 @@ namespace storm {
             STORM_LOG_ASSERT(!empty(), "BucketPriorityQueue is empty");
             STORM_LOG_ASSERT(nrUnsortedItems == 0, "First bucket is not sorted");
             std::pop_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
-            // Remove from mapping
-            heuristicMapping.erase(buckets[currentBucket].back()->getId());
             buckets[currentBucket].pop_back();
             if (buckets[currentBucket].empty()) {
                 // Find next bucket with elements
@@ -153,15 +150,6 @@ namespace storm {
             return newBucket;
         }
 
-        template<typename ValueType>
-        void BucketPriorityQueue<ValueType>::setMappingBucket(size_t bucket) {
-            if (bucket < buckets.size()) {
-                for (size_t index = 0; index < buckets[bucket].size(); ++index) {
-                    heuristicMapping[buckets[bucket][index]->getId()] = std::make_pair(bucket, index);
-                }
-            }
-        }
-
         template<typename ValueType>
         void BucketPriorityQueue<ValueType>::print(std::ostream& out) const {
             out << "Bucket priority queue with size " << buckets.size() << ", lower value: " << lowerValue << " and step per bucket: " << stepPerBucket << std::endl;
@@ -174,10 +162,6 @@ namespace storm {
                     }
                 }
             }
-            out << "Mapping:" << std::endl;
-            for (auto it : heuristicMapping) {
-                out << it.first << " -> " << it.second.first << ", " << it.second.second << std::endl;
-            }
         }
 
 
diff --git a/src/storage/BucketPriorityQueue.h b/src/storage/BucketPriorityQueue.h
index a08bfbd3b..2e36e3cb6 100644
--- a/src/storage/BucketPriorityQueue.h
+++ b/src/storage/BucketPriorityQueue.h
@@ -40,17 +40,12 @@ namespace storm {
 
             size_t getBucket(double priority) const;
 
-            void setMappingBucket(size_t bucket);
-
             // List of buckets
             std::vector<std::vector<HeuristicPointer>> buckets;
 
             // Index of first bucket which contains items
             size_t currentBucket;
 
-            // Mapping from id to (bucket, index in bucket)
-            std::unordered_map<size_t, std::pair<size_t, size_t>> heuristicMapping;
-
             std::function<bool(HeuristicPointer, HeuristicPointer)> compare;
 
             double lowerValue;

From 945447e7e01b176f8eab01e41ae961a1ed8e449e Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Mon, 24 Oct 2016 18:41:07 +0200
Subject: [PATCH 38/65] Use DFS as default

Former-commit-id: 34f9e80d1bd25c18085ca6f89beb5c163644ccdd
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 8 ++++----
 src/builder/ExplicitDFTModelBuilderApprox.h   | 2 +-
 src/storage/BucketPriorityQueue.cpp           | 2 +-
 src/storage/BucketPriorityQueue.h             | 2 +-
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 07863bb01..78272238c 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -32,12 +32,12 @@ namespace storm {
                 matrixBuilder(!generator.isDeterministicModel()),
                 stateStorage(((dft.stateVectorSize() / 64) + 1) * 64),
                 // TODO Matthias: make choosable
-                //explorationQueue(dft.nrElements(), 0, 1)
-                explorationQueue(41, 0, 1.0/20)
+                explorationQueue(dft.nrElements()+1, 0, 1)
+                //explorationQueue(141, 0, 0.02)
         {
             // Intentionally left empty.
             // TODO Matthias: remove again
-            heuristic = storm::builder::ApproximationHeuristic::RATERATIO;
+            heuristic = storm::builder::ApproximationHeuristic::NONE;
         }
 
         template<typename ValueType, typename StateType>
@@ -90,7 +90,7 @@ namespace storm {
             switch (heuristic) {
                 case storm::builder::ApproximationHeuristic::NONE:
                     // Do not change anything
-                    approximationThreshold = 0;
+                    approximationThreshold = dft.nrElements()+10;
                     break;
                 case storm::builder::ApproximationHeuristic::DEPTH:
                     approximationThreshold = iteration;
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index e23a8e819..1f779e44f 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -28,7 +28,7 @@ namespace storm {
 
             using DFTStatePointer = std::shared_ptr<storm::storage::DFTState<ValueType>>;
             // TODO Matthias: make choosable
-            using ExplorationHeuristic = DFTExplorationHeuristicRateRatio<ValueType>;
+            using ExplorationHeuristic = DFTExplorationHeuristicDepth<ValueType>;
             using ExplorationHeuristicPointer = std::shared_ptr<ExplorationHeuristic>;
 
 
diff --git a/src/storage/BucketPriorityQueue.cpp b/src/storage/BucketPriorityQueue.cpp
index bc3ca8780..fe1ca95b5 100644
--- a/src/storage/BucketPriorityQueue.cpp
+++ b/src/storage/BucketPriorityQueue.cpp
@@ -16,7 +16,7 @@ namespace storm {
         void BucketPriorityQueue<ValueType>::fix() {
             if (currentBucket < buckets.size() && nrUnsortedItems > 0) {
                 // Fix current bucket
-                std::make_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
+                //std::make_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
                 nrUnsortedItems = 0;
             }
         }
diff --git a/src/storage/BucketPriorityQueue.h b/src/storage/BucketPriorityQueue.h
index 2e36e3cb6..3d3c2d35d 100644
--- a/src/storage/BucketPriorityQueue.h
+++ b/src/storage/BucketPriorityQueue.h
@@ -13,7 +13,7 @@ namespace storm {
         template<typename ValueType>
         class BucketPriorityQueue {
 
-            using HeuristicPointer = std::shared_ptr<storm::builder::DFTExplorationHeuristicRateRatio<ValueType>>;
+            using HeuristicPointer = std::shared_ptr<storm::builder::DFTExplorationHeuristicDepth<ValueType>>;
 
         public:
             explicit BucketPriorityQueue(size_t nrBuckets, double lowerValue, double stepPerBucket);

From 8b78ed234068f118c45eb23fe45b74e614f7e4e9 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Tue, 25 Oct 2016 00:24:53 +0200
Subject: [PATCH 39/65] Renamed rateratio to probability

Former-commit-id: 6d07985b1d63af7c94245926a8ac5dddb560cade
---
 src/builder/DftExplorationHeuristic.cpp       | 25 ++++++----
 src/builder/DftExplorationHeuristic.h         | 46 +++++++++++++------
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 13 +++---
 src/settings/modules/DFTSettings.cpp          |  6 +--
 4 files changed, 57 insertions(+), 33 deletions(-)

diff --git a/src/builder/DftExplorationHeuristic.cpp b/src/builder/DftExplorationHeuristic.cpp
index dbd64088b..75556a06f 100644
--- a/src/builder/DftExplorationHeuristic.cpp
+++ b/src/builder/DftExplorationHeuristic.cpp
@@ -8,31 +8,36 @@ namespace storm {
     namespace builder {
 
         template<typename ValueType>
-        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic(size_t id, size_t depth, ValueType rate, ValueType exitRate) : id(id), expand(false), depth(depth) {
+        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic(size_t id) : id(id), expand(false), depth(0), probability(storm::utility::zero<ValueType>()) {
+            // Intentionally left empty
+        }
+
+        template<typename ValueType>
+        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) : id(id), expand(false), depth(predecessor.depth + 1) {
             STORM_LOG_ASSERT(storm::utility::zero<ValueType>() < exitRate, "Exit rate is 0");
-            rateRatio = rate/exitRate;
+            probability = predecessor.probability * rate/exitRate;
         }
 
         template<>
-        bool DFTExplorationHeuristicRateRatio<double>::updateHeuristicValues(size_t depth, double rate, double exitRate) {
+        bool DFTExplorationHeuristicProbability<double>::updateHeuristicValues(DFTExplorationHeuristic<double> const& predecessor, double rate, double exitRate) {
             STORM_LOG_ASSERT(exitRate > 0, "Exit rate is 0");
-            rateRatio += rate/exitRate;
+            probability += predecessor.getProbability() * rate/exitRate;
             return true;
         }
 
         template<>
-        bool DFTExplorationHeuristicRateRatio<storm::RationalFunction>::updateHeuristicValues(size_t depth, storm::RationalFunction rate, storm::RationalFunction exitRate) {
+        bool DFTExplorationHeuristicProbability<storm::RationalFunction>::updateHeuristicValues(DFTExplorationHeuristic<storm::RationalFunction> const& predecessor, storm::RationalFunction rate, storm::RationalFunction exitRate) {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work for rational functions.");
             return false;
         }
 
         template<>
-        double DFTExplorationHeuristicRateRatio<double>::getPriority() const {
-            return rateRatio;
+        double DFTExplorationHeuristicProbability<double>::getPriority() const {
+            return probability;
         }
 
         template<>
-        double DFTExplorationHeuristicRateRatio<storm::RationalFunction>::getPriority() const {
+        double DFTExplorationHeuristicProbability<storm::RationalFunction>::getPriority() const {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work for rational functions.");
         }
 
@@ -41,13 +46,13 @@ namespace storm {
         template class DFTExplorationHeuristic<double>;
         template class DFTExplorationHeuristicNone<double>;
         template class DFTExplorationHeuristicDepth<double>;
-        template class DFTExplorationHeuristicRateRatio<double>;
+        template class DFTExplorationHeuristicProbability<double>;
 
 #ifdef STORM_HAVE_CARL
         template class DFTExplorationHeuristic<storm::RationalFunction>;
         template class DFTExplorationHeuristicNone<storm::RationalFunction>;
         template class DFTExplorationHeuristicDepth<storm::RationalFunction>;
-        template class DFTExplorationHeuristicRateRatio<storm::RationalFunction>;
+        template class DFTExplorationHeuristicProbability<storm::RationalFunction>;
 #endif
     }
 }
diff --git a/src/builder/DftExplorationHeuristic.h b/src/builder/DftExplorationHeuristic.h
index d23c673fc..f24d7defb 100644
--- a/src/builder/DftExplorationHeuristic.h
+++ b/src/builder/DftExplorationHeuristic.h
@@ -10,7 +10,7 @@ namespace storm {
         /*!
          * Enum representing the heuristic used for deciding which states to expand.
          */
-        enum class ApproximationHeuristic { NONE, DEPTH, RATERATIO };
+        enum class ApproximationHeuristic { NONE, DEPTH, PROBABILITY };
 
 
         /*!
@@ -20,9 +20,11 @@ namespace storm {
         class DFTExplorationHeuristic {
 
         public:
-            DFTExplorationHeuristic(size_t id, size_t depth, ValueType rate, ValueType exitRate);
+            DFTExplorationHeuristic(size_t id);
 
-            virtual bool updateHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) = 0;
+            DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate);
+
+            virtual bool updateHeuristicValues(DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) = 0;
 
             virtual double getPriority() const = 0;
 
@@ -40,21 +42,29 @@ namespace storm {
                 return depth;
             }
 
+            ValueType getProbability() const {
+                return probability;
+            }
+
         protected:
             size_t id;
             bool expand;
             size_t depth;
-            ValueType rateRatio;
+            ValueType probability;
         };
 
         template<typename ValueType>
         class DFTExplorationHeuristicNone : public DFTExplorationHeuristic<ValueType> {
         public:
-            DFTExplorationHeuristicNone(size_t id, size_t depth, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, depth, rate, exitRate) {
+            DFTExplorationHeuristicNone(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
+                // Intentionally left empty
+            }
+
+            DFTExplorationHeuristicNone(size_t id, DFTExplorationHeuristicNone<ValueType> const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate) {
                 // Intentionally left empty
             }
 
-            bool updateHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) override {
+            bool updateHeuristicValues(DFTExplorationHeuristic<ValueType> const& predecessor, ValueType rate, ValueType exitRate) override {
                 return false;
             }
 
@@ -74,13 +84,17 @@ namespace storm {
         template<typename ValueType>
         class DFTExplorationHeuristicDepth : public DFTExplorationHeuristic<ValueType> {
         public:
-            DFTExplorationHeuristicDepth(size_t id, size_t depth, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, depth, rate, exitRate) {
+            DFTExplorationHeuristicDepth(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
                 // Intentionally left empty
             }
 
-            bool updateHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) override {
-                if (depth < this->depth) {
-                    this->depth = depth;
+            DFTExplorationHeuristicDepth(size_t id, DFTExplorationHeuristicDepth<ValueType> const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate) {
+                // Intentionally left empty
+            }
+
+            bool updateHeuristicValues(DFTExplorationHeuristic<ValueType> const& predecessor, ValueType rate, ValueType exitRate) override {
+                if (predecessor.getDepth() < this->depth) {
+                    this->depth = predecessor.getDepth();
                     return true;
                 }
                 return false;
@@ -101,13 +115,17 @@ namespace storm {
         };
 
         template<typename ValueType>
-        class DFTExplorationHeuristicRateRatio : public DFTExplorationHeuristic<ValueType> {
+        class DFTExplorationHeuristicProbability : public DFTExplorationHeuristic<ValueType> {
         public:
-            DFTExplorationHeuristicRateRatio(size_t id, size_t depth, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, depth, rate, exitRate) {
+            DFTExplorationHeuristicProbability(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
+                // Intentionally left empty
+            }
+
+            DFTExplorationHeuristicProbability(size_t id, DFTExplorationHeuristicProbability<ValueType> const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate) {
                 // Intentionally left empty
             }
 
-            bool updateHeuristicValues(size_t depth, ValueType rate, ValueType exitRate) override;
+            bool updateHeuristicValues(DFTExplorationHeuristic<ValueType> const& predecessor, ValueType rate, ValueType exitRate) override;
 
             double getPriority() const override;
 
@@ -115,7 +133,7 @@ namespace storm {
                 return !this->expand && this->getPriority() < approximationThreshold;
             }
 
-            bool operator<(DFTExplorationHeuristicRateRatio<ValueType> const& other) const {
+            bool operator<(DFTExplorationHeuristicProbability<ValueType> const& other) const {
                 return this->getPriority() < other.getPriority();
             }
         };
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 78272238c..6b35344cd 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -37,7 +37,7 @@ namespace storm {
         {
             // Intentionally left empty.
             // TODO Matthias: remove again
-            heuristic = storm::builder::ApproximationHeuristic::NONE;
+            heuristic = storm::builder::ApproximationHeuristic::PROBABILITY;
         }
 
         template<typename ValueType, typename StateType>
@@ -79,7 +79,7 @@ namespace storm {
                 STORM_LOG_TRACE("Initial state: " << initialStateIndex);
                 // Initialize heuristic values for inital state
                 STORM_LOG_ASSERT(!statesNotExplored.at(initialStateIndex).second, "Heuristic for initial state is already initialized");
-                ExplorationHeuristicPointer heuristic = std::make_shared<ExplorationHeuristic>(initialStateIndex, 0, storm::utility::zero<ValueType>(), storm::utility::one<ValueType>());
+                ExplorationHeuristicPointer heuristic = std::make_shared<ExplorationHeuristic>(initialStateIndex);
                 heuristic->markExpand();
                 statesNotExplored[initialStateIndex].second = heuristic;
                 explorationQueue.push(heuristic);
@@ -95,8 +95,9 @@ namespace storm {
                 case storm::builder::ApproximationHeuristic::DEPTH:
                     approximationThreshold = iteration;
                     break;
-                case storm::builder::ApproximationHeuristic::RATERATIO:
-                    approximationThreshold = std::pow(0.1, iteration) * approximationThreshold;
+                case storm::builder::ApproximationHeuristic::PROBABILITY:
+                    //approximationThreshold = std::pow(0.1, iteration) * approximationThreshold;
+                    approximationThreshold = 10 * std::pow(2, iteration);
                     break;
             }
             exploreStateSpace(approximationThreshold);
@@ -298,12 +299,12 @@ namespace storm {
                                 DFTStatePointer state = iter->second.first;
                                 if (!iter->second.second) {
                                     // Initialize heuristic values
-                                    ExplorationHeuristicPointer heuristic = std::make_shared<ExplorationHeuristic>(stateProbabilityPair.first, currentExplorationHeuristic->getDepth() + 1, stateProbabilityPair.second, choice.getTotalMass());
+                                    ExplorationHeuristicPointer heuristic = std::make_shared<ExplorationHeuristic>(stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass());
                                     iter->second.second = heuristic;
                                     explorationQueue.push(heuristic);
                                 } else {
                                     double oldPriority = iter->second.second->getPriority();
-                                    if (iter->second.second->updateHeuristicValues(currentExplorationHeuristic->getDepth() + 1, stateProbabilityPair.second, choice.getTotalMass())) {
+                                    if (iter->second.second->updateHeuristicValues(*currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass())) {
                                         // Update priority queue
                                         ++fix;
                                         explorationQueue.update(iter->second.second, oldPriority);
diff --git a/src/settings/modules/DFTSettings.cpp b/src/settings/modules/DFTSettings.cpp
index 0dcb49f1d..ab707b5a4 100644
--- a/src/settings/modules/DFTSettings.cpp
+++ b/src/settings/modules/DFTSettings.cpp
@@ -40,7 +40,7 @@ namespace storm {
                 this->addOption(storm::settings::OptionBuilder(moduleName, modularisationOptionName, false, "Use modularisation (not applicable for expected time).").build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, disableDCOptionName, false, "Disable Dont Care propagation.").build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, approximationErrorOptionName, false, "Approximation error allowed.").setShortName(approximationErrorOptionShortName).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("error", "The relative approximation error to use.").addValidationFunctionDouble(storm::settings::ArgumentValidators::doubleGreaterValidatorIncluding(0.0)).build()).build());
-                this->addOption(storm::settings::OptionBuilder(moduleName, approximationHeuristicOptionName, false, "Set the heuristic used for approximation.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("heuristic", "Sets which heuristic is used for approximation. Must be in {depth, rateratio}. Default is").setDefaultValueString("depth").addValidationFunctionString(storm::settings::ArgumentValidators::stringInListValidator({"depth", "rateratio"})).build()).build());
+                this->addOption(storm::settings::OptionBuilder(moduleName, approximationHeuristicOptionName, false, "Set the heuristic used for approximation.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("heuristic", "Sets which heuristic is used for approximation. Must be in {depth, probability}. Default is").setDefaultValueString("depth").addValidationFunctionString(storm::settings::ArgumentValidators::stringInListValidator({"depth", "rateratio"})).build()).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, propExpectedTimeOptionName, false, "Compute expected time of system failure.").setShortName(propExpectedTimeOptionShortName).build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, propProbabilityOptionName, false, "Compute probability of system failure.").build());
                 this->addOption(storm::settings::OptionBuilder(moduleName, propTimeBoundOptionName, false, "Compute probability of system failure up to given timebound.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("time", "The timebound to use.").addValidationFunctionDouble(storm::settings::ArgumentValidators::doubleGreaterValidatorExcluding(0.0)).build()).build());
@@ -87,8 +87,8 @@ namespace storm {
                 std::string heuristicAsString = this->getOption(approximationHeuristicOptionName).getArgumentByName("heuristic").getValueAsString();
                 if (heuristicAsString == "depth") {
                     return storm::builder::ApproximationHeuristic::DEPTH;
-                } else if (heuristicAsString == "rateratio") {
-                    return storm::builder::ApproximationHeuristic::RATERATIO;
+                } else if (heuristicAsString == "probability") {
+                    return storm::builder::ApproximationHeuristic::PROBABILITY;
                 }
                 STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Illegal value '" << heuristicAsString << "' set as heuristic for approximation.");
             }

From 20b00e8f1dcff6e72df2c6011b5b4622f7046870 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Tue, 25 Oct 2016 00:25:35 +0200
Subject: [PATCH 40/65] Propagate dont care to currently not failable BEs

Former-commit-id: 1fcb15f4ec045d244e1397b4fbe2100435ea9557
---
 src/storage/dft/DFTState.cpp | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index 0b2ff7ee8..369bed3f7 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -200,8 +200,13 @@ namespace storm {
         template<typename ValueType>
         void DFTState<ValueType>::beNoLongerFailable(size_t id) {
             auto it = std::find(mCurrentlyFailableBE.begin(), mCurrentlyFailableBE.end(), id);
-            if(it != mCurrentlyFailableBE.end()) {
+            if (it != mCurrentlyFailableBE.end()) {
                 mCurrentlyFailableBE.erase(it);
+            } else {
+                it = std::find(mCurrentlyNotFailableBE.begin(), mCurrentlyNotFailableBE.end(), id);
+                if (it != mCurrentlyNotFailableBE.end()) {
+                    mCurrentlyNotFailableBE.erase(it);
+                }
             }
         }
 
@@ -253,7 +258,7 @@ namespace storm {
         ValueType DFTState<ValueType>::getNotFailableBERate(size_t index) const {
             STORM_LOG_ASSERT(index < nrNotFailableBEs(), "Index invalid.");
             STORM_LOG_ASSERT(storm::utility::isZero<ValueType>(mDft.getBasicElement(mCurrentlyNotFailableBE[index])->activeFailureRate()) ||
-                             (mDft.hasRepresentant(mCurrentlyNotFailableBE[index]) && !isActive(mDft.getRepresentant(mCurrentlyNotFailableBE[index]))), "BE " << mCurrentlyNotFailableBE[index] << " can fail");
+                             (mDft.hasRepresentant(mCurrentlyNotFailableBE[index]) && !isActive(mDft.getRepresentant(mCurrentlyNotFailableBE[index]))), "BE " << mCurrentlyNotFailableBE[index] << " can fail in state: " << mDft.getStateString(mStatus, mStateGenerationInfo, mId));
             // Use active failure rate as passive failure rate is 0.
             return getBERate(mCurrentlyNotFailableBE[index], false);
         }

From 0d9cdd6ef882fbe21b5db8e9b1ee6d85a02bd767 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Tue, 25 Oct 2016 13:47:06 +0200
Subject: [PATCH 41/65] Use Heuristic None

Former-commit-id: 63f78f3db06074f322326d9169deed15256b8304
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 6b35344cd..7de1e0bb4 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -33,11 +33,11 @@ namespace storm {
                 stateStorage(((dft.stateVectorSize() / 64) + 1) * 64),
                 // TODO Matthias: make choosable
                 explorationQueue(dft.nrElements()+1, 0, 1)
-                //explorationQueue(141, 0, 0.02)
+                //explorationQueue(1001, 0, 0.001)
         {
             // Intentionally left empty.
             // TODO Matthias: remove again
-            heuristic = storm::builder::ApproximationHeuristic::PROBABILITY;
+            heuristic = storm::builder::ApproximationHeuristic::NONE;
         }
 
         template<typename ValueType, typename StateType>
@@ -97,7 +97,7 @@ namespace storm {
                     break;
                 case storm::builder::ApproximationHeuristic::PROBABILITY:
                     //approximationThreshold = std::pow(0.1, iteration) * approximationThreshold;
-                    approximationThreshold = 10 * std::pow(2, iteration);
+                    approximationThreshold = iteration;//10 * std::pow(2, iteration);
                     break;
             }
             exploreStateSpace(approximationThreshold);
@@ -267,6 +267,7 @@ namespace storm {
                 // Try to explore the next state
                 generator.load(currentState);
 
+                //if (nrExpandedStates > approximationThreshold) {
                 if (currentExplorationHeuristic->isSkip(approximationThreshold)) {
                     // Skip the current state
                     ++nrSkippedStates;

From 58f870729307fb4df9612b292187ea711403a589 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Tue, 25 Oct 2016 23:19:41 +0200
Subject: [PATCH 42/65] Tighter over-approximation

Former-commit-id: 824e74f88df07a49ab306b2599fd82f9ced47366
---
 src/builder/DftExplorationHeuristic.cpp       |  21 ++-
 src/builder/DftExplorationHeuristic.h         |  55 +++++++-
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 124 +++++++++++-------
 src/builder/ExplicitDFTModelBuilderApprox.h   |  22 +++-
 src/modelchecker/dft/DFTModelChecker.cpp      |   1 +
 src/storage/BucketPriorityQueue.cpp           |  23 +++-
 src/storage/BucketPriorityQueue.h             |   5 +-
 src/storage/dft/DFTState.cpp                  |   8 +-
 8 files changed, 196 insertions(+), 63 deletions(-)

diff --git a/src/builder/DftExplorationHeuristic.cpp b/src/builder/DftExplorationHeuristic.cpp
index 75556a06f..db26fc60d 100644
--- a/src/builder/DftExplorationHeuristic.cpp
+++ b/src/builder/DftExplorationHeuristic.cpp
@@ -8,16 +8,22 @@ namespace storm {
     namespace builder {
 
         template<typename ValueType>
-        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic(size_t id) : id(id), expand(false), depth(0), probability(storm::utility::zero<ValueType>()) {
+        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic(size_t id) : id(id), expand(false), lowerBound(storm::utility::zero<ValueType>()), upperBound(storm::utility::infinity<ValueType>()), depth(0), probability(storm::utility::one<ValueType>()) {
             // Intentionally left empty
         }
 
         template<typename ValueType>
-        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) : id(id), expand(false), depth(predecessor.depth + 1) {
+        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate, ValueType lowerBound, ValueType upperBound) : id(id), expand(false), lowerBound(lowerBound), upperBound(upperBound), depth(predecessor.depth + 1) {
             STORM_LOG_ASSERT(storm::utility::zero<ValueType>() < exitRate, "Exit rate is 0");
             probability = predecessor.probability * rate/exitRate;
         }
 
+        template<typename ValueType>
+        void DFTExplorationHeuristic<ValueType>::setBounds(ValueType lowerBound, ValueType upperBound) {
+            this->lowerBound = lowerBound;
+            this->upperBound = upperBound;
+        }
+
         template<>
         bool DFTExplorationHeuristicProbability<double>::updateHeuristicValues(DFTExplorationHeuristic<double> const& predecessor, double rate, double exitRate) {
             STORM_LOG_ASSERT(exitRate > 0, "Exit rate is 0");
@@ -41,18 +47,29 @@ namespace storm {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work for rational functions.");
         }
 
+        template<>
+        double DFTExplorationHeuristicBoundDifference<double>::getPriority() const {
+            return upperBound / lowerBound;
+        }
+
+        template<>
+        double DFTExplorationHeuristicBoundDifference<storm::RationalFunction>::getPriority() const {
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic bound difference does not work for rational functions.");
+        }
 
         // Instantiate templates.
         template class DFTExplorationHeuristic<double>;
         template class DFTExplorationHeuristicNone<double>;
         template class DFTExplorationHeuristicDepth<double>;
         template class DFTExplorationHeuristicProbability<double>;
+        template class DFTExplorationHeuristicBoundDifference<double>;
 
 #ifdef STORM_HAVE_CARL
         template class DFTExplorationHeuristic<storm::RationalFunction>;
         template class DFTExplorationHeuristicNone<storm::RationalFunction>;
         template class DFTExplorationHeuristicDepth<storm::RationalFunction>;
         template class DFTExplorationHeuristicProbability<storm::RationalFunction>;
+        template class DFTExplorationHeuristicBoundDifference<storm::RationalFunction>;
 #endif
     }
 }
diff --git a/src/builder/DftExplorationHeuristic.h b/src/builder/DftExplorationHeuristic.h
index f24d7defb..12f178f25 100644
--- a/src/builder/DftExplorationHeuristic.h
+++ b/src/builder/DftExplorationHeuristic.h
@@ -22,7 +22,9 @@ namespace storm {
         public:
             DFTExplorationHeuristic(size_t id);
 
-            DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate);
+            DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate, ValueType lowerBound, ValueType upperBound);
+
+            void setBounds(ValueType lowerBound, ValueType upperBound);
 
             virtual bool updateHeuristicValues(DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) = 0;
 
@@ -38,6 +40,10 @@ namespace storm {
                 return id;
             }
 
+            bool isExpand() {
+                return expand;
+            }
+
             size_t getDepth() const {
                 return depth;
             }
@@ -46,9 +52,19 @@ namespace storm {
                 return probability;
             }
 
+            ValueType getLowerBound() const {
+                return lowerBound;
+            }
+
+            ValueType getUpperBound() const {
+                return upperBound;
+            }
+
         protected:
             size_t id;
             bool expand;
+            ValueType lowerBound;
+            ValueType upperBound;
             size_t depth;
             ValueType probability;
         };
@@ -60,7 +76,7 @@ namespace storm {
                 // Intentionally left empty
             }
 
-            DFTExplorationHeuristicNone(size_t id, DFTExplorationHeuristicNone<ValueType> const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate) {
+            DFTExplorationHeuristicNone(size_t id, DFTExplorationHeuristicNone<ValueType> const& predecessor, ValueType rate, ValueType exitRate, ValueType lowerBound, ValueType upperBound) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate, lowerBound, upperBound) {
                 // Intentionally left empty
             }
 
@@ -88,7 +104,7 @@ namespace storm {
                 // Intentionally left empty
             }
 
-            DFTExplorationHeuristicDepth(size_t id, DFTExplorationHeuristicDepth<ValueType> const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate) {
+            DFTExplorationHeuristicDepth(size_t id, DFTExplorationHeuristicDepth<ValueType> const& predecessor, ValueType rate, ValueType exitRate, ValueType lowerBound, ValueType upperBound) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate, lowerBound, upperBound) {
                 // Intentionally left empty
             }
 
@@ -121,7 +137,7 @@ namespace storm {
                 // Intentionally left empty
             }
 
-            DFTExplorationHeuristicProbability(size_t id, DFTExplorationHeuristicProbability<ValueType> const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate) {
+            DFTExplorationHeuristicProbability(size_t id, DFTExplorationHeuristicProbability<ValueType> const& predecessor, ValueType rate, ValueType exitRate, ValueType lowerBound, ValueType upperBound) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate, lowerBound, upperBound) {
                 // Intentionally left empty
             }
 
@@ -138,6 +154,37 @@ namespace storm {
             }
         };
 
+        template<typename ValueType>
+        class DFTExplorationHeuristicBoundDifference : public DFTExplorationHeuristic<ValueType> {
+        public:
+            DFTExplorationHeuristicBoundDifference(size_t id) : DFTExplorationHeuristic<ValueType>(id) {
+                // Intentionally left empty
+            }
+
+            DFTExplorationHeuristicBoundDifference(size_t id, DFTExplorationHeuristicBoundDifference<ValueType> const& predecessor, ValueType rate, ValueType exitRate, ValueType lowerBound, ValueType upperBound) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate, lowerBound, upperBound) {
+                // Intentionally left empty
+            }
+
+            bool updateHeuristicValues(DFTExplorationHeuristic<ValueType> const& predecessor, ValueType rate, ValueType exitRate) override {
+                return false;
+            }
+
+            double getPriority() const override;
+
+            bool isSkip(double approximationThreshold) const override {
+                return !this->expand && this->getPriority() < approximationThreshold;
+            }
+
+            bool operator<(DFTExplorationHeuristicBoundDifference<ValueType> const& other) const {
+                return this->getPriority() < other.getPriority();
+            }
+
+        private:
+            ValueType lowerBound;
+            ValueType upperBound;
+        };
+
+
     }
 }
 
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 7de1e0bb4..0328cf055 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -3,6 +3,7 @@
 #include <src/models/sparse/Ctmc.h>
 #include <src/utility/constants.h>
 #include <src/utility/vector.h>
+#include "src/utility/bitoperations.h"
 #include <src/exceptions/UnexpectedException.h>
 #include "src/settings/modules/DFTSettings.h"
 #include "src/settings/SettingsManager.h"
@@ -32,12 +33,12 @@ namespace storm {
                 matrixBuilder(!generator.isDeterministicModel()),
                 stateStorage(((dft.stateVectorSize() / 64) + 1) * 64),
                 // TODO Matthias: make choosable
-                explorationQueue(dft.nrElements()+1, 0, 1)
-                //explorationQueue(1001, 0, 0.001)
+                //explorationQueue(dft.nrElements()+1, 0, 1)
+                explorationQueue(1001, 0, 0.001)
         {
             // Intentionally left empty.
             // TODO Matthias: remove again
-            heuristic = storm::builder::ApproximationHeuristic::NONE;
+            heuristic = storm::builder::ApproximationHeuristic::PROBABILITY;
         }
 
         template<typename ValueType, typename StateType>
@@ -256,6 +257,9 @@ namespace storm {
                 if (currentState->isPseudoState()) {
                     // Create concrete state from pseudo state
                     currentState->construct();
+                    ValueType lowerBound = getLowerBound(currentState);
+                    ValueType upperBound = getUpperBound(currentState);
+                    currentExplorationHeuristic->setBounds(lowerBound, upperBound);
                 }
                 STORM_LOG_ASSERT(!currentState->isPseudoState(), "State is pseudo state.");
 
@@ -267,8 +271,8 @@ namespace storm {
                 // Try to explore the next state
                 generator.load(currentState);
 
-                //if (nrExpandedStates > approximationThreshold) {
-                if (currentExplorationHeuristic->isSkip(approximationThreshold)) {
+                if (nrExpandedStates > approximationThreshold && !currentExplorationHeuristic->isExpand()) {
+                //if (currentExplorationHeuristic->isSkip(approximationThreshold)) {
                     // Skip the current state
                     ++nrSkippedStates;
                     STORM_LOG_TRACE("Skip expansion of state: " << dft.getStateString(currentState));
@@ -299,11 +303,24 @@ namespace storm {
                                 // Update heuristic values
                                 DFTStatePointer state = iter->second.first;
                                 if (!iter->second.second) {
+                                    ValueType lowerBound;
+                                    ValueType upperBound;
+                                    if (state->isPseudoState()) {
+                                        lowerBound = storm::utility::infinity<ValueType>();
+                                        upperBound = storm::utility::infinity<ValueType>();
+                                    } else {
+                                        lowerBound = getLowerBound(state);
+                                        upperBound = getUpperBound(state);
+                                    }
                                     // Initialize heuristic values
-                                    ExplorationHeuristicPointer heuristic = std::make_shared<ExplorationHeuristic>(stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass());
+                                    ExplorationHeuristicPointer heuristic = std::make_shared<ExplorationHeuristic>(stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass(), lowerBound, upperBound);
                                     iter->second.second = heuristic;
+                                    if (state->hasFailed(dft.getTopLevelIndex()) || state->isFailsafe(dft.getTopLevelIndex()) || state->nrFailableDependencies() > 0 || (state->nrFailableDependencies() == 0 && state->nrFailableBEs() == 0)) {
+                                        // Do not skip absorbing state or if reached by dependencies
+                                        iter->second.second->markExpand();
+                                    }
                                     explorationQueue.push(heuristic);
-                                } else {
+                                } else if (!iter->second.second->isExpand()) {
                                     double oldPriority = iter->second.second->getPriority();
                                     if (iter->second.second->updateHeuristicValues(*currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass())) {
                                         // Update priority queue
@@ -311,11 +328,6 @@ namespace storm {
                                         explorationQueue.update(iter->second.second, oldPriority);
                                     }
                                 }
-                                if (state->hasFailed(dft.getTopLevelIndex()) || state->isFailsafe(dft.getTopLevelIndex()) || state->nrFailableDependencies() > 0 || (state->nrFailableDependencies() == 0 && state->nrFailableBEs() == 0)) {
-                                    // Do not skip absorbing state or if reached by dependencies
-                                    iter->second.second->markExpand();
-                                    // TODO Matthias give highest priority to ensure expanding before all skipped
-                                }
                             }
                         }
                         matrixBuilder.finishRow();
@@ -383,11 +395,7 @@ namespace storm {
         template<typename ValueType, typename StateType>
         std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilderApprox<ValueType, StateType>::getModelApproximation(bool lowerBound) {
             // TODO Matthias: handle case with no skipped states
-            if (lowerBound) {
-                changeMatrixLowerBound(modelComponents.transitionMatrix);
-            } else {
-                changeMatrixUpperBound(modelComponents.transitionMatrix);
-            }
+            changeMatrixBound(modelComponents.transitionMatrix, lowerBound);
             return createModel(true);
         }
 
@@ -443,44 +451,72 @@ namespace storm {
         }
 
         template<typename ValueType, typename StateType>
-        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::changeMatrixLowerBound(storm::storage::SparseMatrix<ValueType> & matrix) const {
+        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::changeMatrixBound(storm::storage::SparseMatrix<ValueType> & matrix, bool lowerBound) const {
             // Set lower bound for skipped states
             for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
                 auto matrixEntry = matrix.getRow(it->first, 0).begin();
                 STORM_LOG_ASSERT(matrixEntry->getColumn() == failedStateId, "Transition has wrong target state.");
-                // Get the lower bound by considering the failure of all possible BEs
-                DFTStatePointer state = it->second.first;
-                ValueType newRate = storm::utility::zero<ValueType>();
-                for (size_t index = 0; index < state->nrFailableBEs(); ++index) {
-                    newRate += state->getFailableBERate(index);
-                }
-                for (size_t index = 0; index < state->nrNotFailableBEs(); ++index) {
-                    newRate += state->getNotFailableBERate(index);
+                STORM_LOG_ASSERT(!it->second.first->isPseudoState(), "State is still pseudo state.");
+                if (lowerBound) {
+                    matrixEntry->setValue(it->second.second->getLowerBound());
+                } else {
+                    matrixEntry->setValue(it->second.second->getUpperBound());
                 }
-                matrixEntry->setValue(newRate);
             }
         }
 
         template<typename ValueType, typename StateType>
-        void ExplicitDFTModelBuilderApprox<ValueType, StateType>::changeMatrixUpperBound(storm::storage::SparseMatrix<ValueType> & matrix) const {
-            // Set uppper bound for skipped states
-            for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
-                auto matrixEntry = matrix.getRow(it->first, 0).begin();
-                STORM_LOG_ASSERT(matrixEntry->getColumn() == failedStateId, "Transition has wrong target state.");
-                // Get the upper bound by considering the failure of all BEs
-                // The used formula for the rate is 1/( 1/a + 1/b + ...)
-                // TODO Matthias: improve by using closed formula for AND of all BEs
-                DFTStatePointer state = it->second.first;
-                ValueType newRate = storm::utility::zero<ValueType>();
-                for (size_t index = 0; index < state->nrFailableBEs(); ++index) {
-                    newRate += storm::utility::one<ValueType>() / state->getFailableBERate(index);
-                }
-                for (size_t index = 0; index < state->nrNotFailableBEs(); ++index) {
-                    newRate += storm::utility::one<ValueType>() / state->getNotFailableBERate(index);
+        ValueType ExplicitDFTModelBuilderApprox<ValueType, StateType>::getLowerBound(DFTStatePointer const& state) const {
+            // Get the lower bound by considering the failure of all possible BEs
+            ValueType lowerBound = storm::utility::zero<ValueType>();
+            for (size_t index = 0; index < state->nrFailableBEs(); ++index) {
+                lowerBound += state->getFailableBERate(index);
+            }
+            for (size_t index = 0; index < state->nrNotFailableBEs(); ++index) {
+                lowerBound += state->getNotFailableBERate(index);
+            }
+            return lowerBound;
+        }
+
+        template<typename ValueType, typename StateType>
+        ValueType ExplicitDFTModelBuilderApprox<ValueType, StateType>::getUpperBound(DFTStatePointer const& state) const {
+            // Get the upper bound by considering the failure of all BEs
+            // The used formula for the rate is 1/( 1/a + 1/b + ...)
+            // TODO Matthias: improve by using closed formula for AND of all BEs
+            ValueType upperBound = storm::utility::zero<ValueType>();
+
+            // Get all possible rates
+            std::vector<ValueType> rates(state->nrFailableBEs() + state->nrNotFailableBEs());
+            for (size_t index = 0; index < state->nrFailableBEs(); ++index) {
+                rates[index] = state->getFailableBERate(index);
+            }
+            for (size_t index = 0; index < state->nrNotFailableBEs(); ++index) {
+                rates[index + state->nrFailableBEs()] = state->getNotFailableBERate(index);
+            }
+
+            // TODO Matthias: works only for <64 BEs!
+            for (size_t i = 1; i < 4 && i <= rates.size(); ++i) {
+                size_t permutation = smallestIntWithNBitsSet(static_cast<size_t>(i));
+                ValueType sum = storm::utility::zero<ValueType>();
+                do {
+                    ValueType permResult = storm::utility::zero<ValueType>();
+                    for(size_t j = 0; j < rates.size(); ++j) {
+                        if(permutation & (1 << j)) {
+                            permResult += rates[j];
+                        }
+                    }
+                    permutation = nextBitPermutation(permutation);
+                    STORM_LOG_ASSERT(!storm::utility::isZero(permResult), "PermResult is 0");
+                    sum += storm::utility::one<ValueType>() / permResult;
+                } while(permutation < (1 << rates.size()) && permutation != 0);
+                if (i % 2 == 0) {
+                    upperBound -= sum;
+                } else {
+                    upperBound += sum;
                 }
-                newRate = storm::utility::one<ValueType>() / newRate;
-                matrixEntry->setValue(newRate);
             }
+            STORM_LOG_ASSERT(!storm::utility::isZero(upperBound), "UpperBound is 0");
+            return storm::utility::one<ValueType>() / upperBound;
         }
 
         template<typename ValueType, typename StateType>
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index 1f779e44f..446bed6ad 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -28,7 +28,7 @@ namespace storm {
 
             using DFTStatePointer = std::shared_ptr<storm::storage::DFTState<ValueType>>;
             // TODO Matthias: make choosable
-            using ExplorationHeuristic = DFTExplorationHeuristicDepth<ValueType>;
+            using ExplorationHeuristic = DFTExplorationHeuristicProbability<ValueType>;
             using ExplorationHeuristicPointer = std::shared_ptr<ExplorationHeuristic>;
 
 
@@ -217,18 +217,26 @@ namespace storm {
             void setMarkovian(bool markovian);
 
             /**
-             * Change matrix to reflect the lower approximation bound.
+             * Change matrix to reflect the lower or upper approximation bound.
              *
-             * @param matrix Matrix to change. The change are reflected here.
+             * @param matrix     Matrix to change. The change are reflected here.
+             * @param lowerBound Flag indicating if the lower bound should be used. Otherwise the upper bound is used.
              */
-            void changeMatrixLowerBound(storm::storage::SparseMatrix<ValueType> & matrix) const;
+            void changeMatrixBound(storm::storage::SparseMatrix<ValueType> & matrix, bool lowerBound) const;
 
             /*!
-             * Change matrix to reflect the upper approximation bound.
+             * Get lower bound approximation for state.
              *
-             * @param matrix Matrix to change. The change are reflected here.
+             * @return Lower bound approximation.
              */
-            void changeMatrixUpperBound(storm::storage::SparseMatrix<ValueType> & matrix) const;
+            ValueType getLowerBound(DFTStatePointer const& state) const;
+
+            /*!
+             * Get upper bound approximation for state.
+             *
+             * @return Upper bound approximation.
+             */
+            ValueType getUpperBound(DFTStatePointer const& state) const;
 
             /*!
              * Compares the priority of two states.
diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index f19943f2f..59d85f5c2 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -255,6 +255,7 @@ namespace storm {
 
         template<>
         bool DFTModelChecker<double>::isApproximationSufficient(double lowerBound, double upperBound, double approximationError) {
+            STORM_LOG_THROW(!std::isnan(lowerBound) && !std::isnan(upperBound), storm::exceptions::NotSupportedException, "Approximation does not work if result is NaN.");
             return upperBound - lowerBound <= approximationError * (lowerBound + upperBound) / 2;
         }
 
diff --git a/src/storage/BucketPriorityQueue.cpp b/src/storage/BucketPriorityQueue.cpp
index fe1ca95b5..eb174cce0 100644
--- a/src/storage/BucketPriorityQueue.cpp
+++ b/src/storage/BucketPriorityQueue.cpp
@@ -16,19 +16,19 @@ namespace storm {
         void BucketPriorityQueue<ValueType>::fix() {
             if (currentBucket < buckets.size() && nrUnsortedItems > 0) {
                 // Fix current bucket
-                //std::make_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
+                std::make_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
                 nrUnsortedItems = 0;
             }
         }
 
         template<typename ValueType>
         bool BucketPriorityQueue<ValueType>::empty() const {
-            return currentBucket == buckets.size();
+            return currentBucket == buckets.size() && immediateBucket.empty();
         }
 
         template<typename ValueType>
         std::size_t BucketPriorityQueue<ValueType>::size() const {
-            size_t size = 0;
+            size_t size = immediateBucket.size();
             for (size_t i = currentBucket; currentBucket < buckets.size(); ++i) {
                 size += buckets[i].size();
             }
@@ -37,6 +37,9 @@ namespace storm {
 
         template<typename ValueType>
         typename BucketPriorityQueue<ValueType>::HeuristicPointer const& BucketPriorityQueue<ValueType>::top() const {
+            if (!immediateBucket.empty()) {
+                return immediateBucket.back();
+            }
             STORM_LOG_ASSERT(!empty(), "BucketPriorityQueue is empty");
             STORM_LOG_ASSERT(nrUnsortedItems == 0, "First bucket is not sorted");
             return buckets[currentBucket].front();
@@ -44,6 +47,10 @@ namespace storm {
 
         template<typename ValueType>
         void BucketPriorityQueue<ValueType>::push(HeuristicPointer const& item) {
+            if (item->isExpand()) {
+                immediateBucket.push_back(item);
+                return;
+            }
             size_t bucket = getBucket(item->getPriority());
             if (bucket < currentBucket) {
                 currentBucket = bucket;
@@ -62,6 +69,7 @@ namespace storm {
 
         template<typename ValueType>
         void BucketPriorityQueue<ValueType>::update(HeuristicPointer const& item, double oldPriority) {
+            STORM_LOG_ASSERT(!item->isExpand(), "Item is marked for expansion");
             size_t newBucket = getBucket(item->getPriority());
             size_t oldBucket = getBucket(oldPriority);
 
@@ -113,6 +121,10 @@ namespace storm {
 
         template<typename ValueType>
         void BucketPriorityQueue<ValueType>::pop() {
+            if (!immediateBucket.empty()) {
+                immediateBucket.pop_back();
+                return;
+            }
             STORM_LOG_ASSERT(!empty(), "BucketPriorityQueue is empty");
             STORM_LOG_ASSERT(nrUnsortedItems == 0, "First bucket is not sorted");
             std::pop_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
@@ -153,6 +165,11 @@ namespace storm {
         template<typename ValueType>
         void BucketPriorityQueue<ValueType>::print(std::ostream& out) const {
             out << "Bucket priority queue with size " << buckets.size() << ", lower value: " << lowerValue << " and step per bucket: " << stepPerBucket << std::endl;
+            out << "Immediate bucket: ";
+            for (HeuristicPointer heuristic : immediateBucket) {
+                out << heuristic->getId() << ", ";
+            }
+            out << std::endl;
             out << "Current bucket (" << currentBucket << ") has " << nrUnsortedItems  << " unsorted items" << std::endl;
             for (size_t bucket = 0; bucket < buckets.size(); ++bucket) {
                 if (!buckets[bucket].empty()) {
diff --git a/src/storage/BucketPriorityQueue.h b/src/storage/BucketPriorityQueue.h
index 3d3c2d35d..253b34e19 100644
--- a/src/storage/BucketPriorityQueue.h
+++ b/src/storage/BucketPriorityQueue.h
@@ -13,7 +13,7 @@ namespace storm {
         template<typename ValueType>
         class BucketPriorityQueue {
 
-            using HeuristicPointer = std::shared_ptr<storm::builder::DFTExplorationHeuristicDepth<ValueType>>;
+            using HeuristicPointer = std::shared_ptr<storm::builder::DFTExplorationHeuristicProbability<ValueType>>;
 
         public:
             explicit BucketPriorityQueue(size_t nrBuckets, double lowerValue, double stepPerBucket);
@@ -43,6 +43,9 @@ namespace storm {
             // List of buckets
             std::vector<std::vector<HeuristicPointer>> buckets;
 
+            // Bucket containing all items which should be considered immediately
+            std::vector<HeuristicPointer> immediateBucket;
+
             // Index of first bucket which contains items
             size_t currentBucket;
 
diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index 369bed3f7..b9381598f 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -18,7 +18,9 @@ namespace storm {
             }
 
             for (auto elem : mDft.getBasicElements()) {
-                mCurrentlyNotFailableBE.push_back(elem->id());
+                if (!storm::utility::isZero(elem->activeFailureRate())) {
+                    mCurrentlyNotFailableBE.push_back(elem->id());
+                }
             }
 
             // Initialize activation
@@ -242,8 +244,10 @@ namespace storm {
         ValueType DFTState<ValueType>::getBERate(size_t id, bool considerPassive) const {
             STORM_LOG_ASSERT(mDft.isBasicElement(id), "Element is no BE.");
             if (considerPassive && mDft.hasRepresentant(id) && !isActive(mDft.getRepresentant(id))) {
+                STORM_LOG_ASSERT(!storm::utility::isZero(mDft.getBasicElement(id)->passiveFailureRate()), "Failure rate of BE " << mDft.getBasicElement(id)->id() << " is 0 in state " << mDft.getStateString(mStatus, mStateGenerationInfo, mId));
                 return mDft.getBasicElement(id)->passiveFailureRate();
             } else {
+                STORM_LOG_ASSERT(!storm::utility::isZero(mDft.getBasicElement(id)->activeFailureRate()), "Failure rate of BE " << mDft.getBasicElement(id)->id() << " is 0 in state " << mDft.getStateString(mStatus, mStateGenerationInfo, mId));
                 return mDft.getBasicElement(id)->activeFailureRate();
             }
         }
@@ -257,7 +261,7 @@ namespace storm {
         template<typename ValueType>
         ValueType DFTState<ValueType>::getNotFailableBERate(size_t index) const {
             STORM_LOG_ASSERT(index < nrNotFailableBEs(), "Index invalid.");
-            STORM_LOG_ASSERT(storm::utility::isZero<ValueType>(mDft.getBasicElement(mCurrentlyNotFailableBE[index])->activeFailureRate()) ||
+            STORM_LOG_ASSERT(isPseudoState() || storm::utility::isZero<ValueType>(mDft.getBasicElement(mCurrentlyNotFailableBE[index])->activeFailureRate()) ||
                              (mDft.hasRepresentant(mCurrentlyNotFailableBE[index]) && !isActive(mDft.getRepresentant(mCurrentlyNotFailableBE[index]))), "BE " << mCurrentlyNotFailableBE[index] << " can fail in state: " << mDft.getStateString(mStatus, mStateGenerationInfo, mId));
             // Use active failure rate as passive failure rate is 0.
             return getBERate(mCurrentlyNotFailableBE[index], false);

From a9f97bd210418cf8afb999e362af118d2c92fc30 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Tue, 25 Oct 2016 23:28:35 +0200
Subject: [PATCH 43/65] Set heuristic to probability

Former-commit-id: a7d8fd77385ce805b2161b8d0b655240b9319f90
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 0328cf055..6a6474ad8 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -97,8 +97,7 @@ namespace storm {
                     approximationThreshold = iteration;
                     break;
                 case storm::builder::ApproximationHeuristic::PROBABILITY:
-                    //approximationThreshold = std::pow(0.1, iteration) * approximationThreshold;
-                    approximationThreshold = iteration;//10 * std::pow(2, iteration);
+                    approximationThreshold = 10 * std::pow(2, iteration);
                     break;
             }
             exploreStateSpace(approximationThreshold);
@@ -234,7 +233,6 @@ namespace storm {
         void ExplicitDFTModelBuilderApprox<ValueType, StateType>::exploreStateSpace(double approximationThreshold) {
             size_t nrExpandedStates = 0;
             size_t nrSkippedStates = 0;
-            size_t fix = 0;
             // TODO Matthias: do not empty queue every time but break before
             while (!explorationQueue.empty()) {
                 explorationQueue.fix();
@@ -324,7 +322,6 @@ namespace storm {
                                     double oldPriority = iter->second.second->getPriority();
                                     if (iter->second.second->updateHeuristicValues(*currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass())) {
                                         // Update priority queue
-                                        ++fix;
                                         explorationQueue.update(iter->second.second, oldPriority);
                                     }
                                 }
@@ -334,7 +331,6 @@ namespace storm {
                     }
                 }
             } // end exploration
-            std::cout << "Fixed queue " << fix << " times" << std::endl;
 
             STORM_LOG_INFO("Expanded " << nrExpandedStates << " states");
             STORM_LOG_INFO("Skipped " << nrSkippedStates << " states");

From 8e159133da0617fd8c88e20196e83d6f37b29a21 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Wed, 26 Oct 2016 23:10:57 +0200
Subject: [PATCH 44/65] Compute lower/upper bounds only when needed

Former-commit-id: 8f3af1ab100516000aba505fbe3620c5875d7f8f
---
 src/builder/DftExplorationHeuristic.cpp       |  4 +--
 src/builder/DftExplorationHeuristic.h         | 12 ++++-----
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 25 +++++++++----------
 3 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/src/builder/DftExplorationHeuristic.cpp b/src/builder/DftExplorationHeuristic.cpp
index db26fc60d..40d00115f 100644
--- a/src/builder/DftExplorationHeuristic.cpp
+++ b/src/builder/DftExplorationHeuristic.cpp
@@ -8,12 +8,12 @@ namespace storm {
     namespace builder {
 
         template<typename ValueType>
-        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic(size_t id) : id(id), expand(false), lowerBound(storm::utility::zero<ValueType>()), upperBound(storm::utility::infinity<ValueType>()), depth(0), probability(storm::utility::one<ValueType>()) {
+        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic(size_t id) : id(id), expand(true), lowerBound(storm::utility::zero<ValueType>()), upperBound(storm::utility::infinity<ValueType>()), depth(0), probability(storm::utility::one<ValueType>()) {
             // Intentionally left empty
         }
 
         template<typename ValueType>
-        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate, ValueType lowerBound, ValueType upperBound) : id(id), expand(false), lowerBound(lowerBound), upperBound(upperBound), depth(predecessor.depth + 1) {
+        DFTExplorationHeuristic<ValueType>::DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) : id(id), expand(false), lowerBound(storm::utility::zero<ValueType>()), upperBound(storm::utility::zero<ValueType>()), depth(predecessor.depth + 1) {
             STORM_LOG_ASSERT(storm::utility::zero<ValueType>() < exitRate, "Exit rate is 0");
             probability = predecessor.probability * rate/exitRate;
         }
diff --git a/src/builder/DftExplorationHeuristic.h b/src/builder/DftExplorationHeuristic.h
index 12f178f25..8feb0fefa 100644
--- a/src/builder/DftExplorationHeuristic.h
+++ b/src/builder/DftExplorationHeuristic.h
@@ -22,7 +22,7 @@ namespace storm {
         public:
             DFTExplorationHeuristic(size_t id);
 
-            DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate, ValueType lowerBound, ValueType upperBound);
+            DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate);
 
             void setBounds(ValueType lowerBound, ValueType upperBound);
 
@@ -76,7 +76,7 @@ namespace storm {
                 // Intentionally left empty
             }
 
-            DFTExplorationHeuristicNone(size_t id, DFTExplorationHeuristicNone<ValueType> const& predecessor, ValueType rate, ValueType exitRate, ValueType lowerBound, ValueType upperBound) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate, lowerBound, upperBound) {
+            DFTExplorationHeuristicNone(size_t id, DFTExplorationHeuristicNone<ValueType> const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate) {
                 // Intentionally left empty
             }
 
@@ -85,7 +85,7 @@ namespace storm {
             }
 
             double getPriority() const override {
-                return this->id;
+                return 0;
             }
 
             bool isSkip(double approximationThreshold) const override {
@@ -104,7 +104,7 @@ namespace storm {
                 // Intentionally left empty
             }
 
-            DFTExplorationHeuristicDepth(size_t id, DFTExplorationHeuristicDepth<ValueType> const& predecessor, ValueType rate, ValueType exitRate, ValueType lowerBound, ValueType upperBound) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate, lowerBound, upperBound) {
+            DFTExplorationHeuristicDepth(size_t id, DFTExplorationHeuristicDepth<ValueType> const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate) {
                 // Intentionally left empty
             }
 
@@ -137,7 +137,7 @@ namespace storm {
                 // Intentionally left empty
             }
 
-            DFTExplorationHeuristicProbability(size_t id, DFTExplorationHeuristicProbability<ValueType> const& predecessor, ValueType rate, ValueType exitRate, ValueType lowerBound, ValueType upperBound) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate, lowerBound, upperBound) {
+            DFTExplorationHeuristicProbability(size_t id, DFTExplorationHeuristicProbability<ValueType> const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate) {
                 // Intentionally left empty
             }
 
@@ -161,7 +161,7 @@ namespace storm {
                 // Intentionally left empty
             }
 
-            DFTExplorationHeuristicBoundDifference(size_t id, DFTExplorationHeuristicBoundDifference<ValueType> const& predecessor, ValueType rate, ValueType exitRate, ValueType lowerBound, ValueType upperBound) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate, lowerBound, upperBound) {
+            DFTExplorationHeuristicBoundDifference(size_t id, DFTExplorationHeuristicBoundDifference<ValueType> const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic<ValueType>(id, predecessor, rate, exitRate) {
                 // Intentionally left empty
             }
 
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 6a6474ad8..432636161 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -255,9 +255,6 @@ namespace storm {
                 if (currentState->isPseudoState()) {
                     // Create concrete state from pseudo state
                     currentState->construct();
-                    ValueType lowerBound = getLowerBound(currentState);
-                    ValueType upperBound = getUpperBound(currentState);
-                    currentExplorationHeuristic->setBounds(lowerBound, upperBound);
                 }
                 STORM_LOG_ASSERT(!currentState->isPseudoState(), "State is pseudo state.");
 
@@ -301,17 +298,8 @@ namespace storm {
                                 // Update heuristic values
                                 DFTStatePointer state = iter->second.first;
                                 if (!iter->second.second) {
-                                    ValueType lowerBound;
-                                    ValueType upperBound;
-                                    if (state->isPseudoState()) {
-                                        lowerBound = storm::utility::infinity<ValueType>();
-                                        upperBound = storm::utility::infinity<ValueType>();
-                                    } else {
-                                        lowerBound = getLowerBound(state);
-                                        upperBound = getUpperBound(state);
-                                    }
                                     // Initialize heuristic values
-                                    ExplorationHeuristicPointer heuristic = std::make_shared<ExplorationHeuristic>(stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass(), lowerBound, upperBound);
+                                    ExplorationHeuristicPointer heuristic = std::make_shared<ExplorationHeuristic>(stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass());
                                     iter->second.second = heuristic;
                                     if (state->hasFailed(dft.getTopLevelIndex()) || state->isFailsafe(dft.getTopLevelIndex()) || state->nrFailableDependencies() > 0 || (state->nrFailableDependencies() == 0 && state->nrFailableBEs() == 0)) {
                                         // Do not skip absorbing state or if reached by dependencies
@@ -453,6 +441,16 @@ namespace storm {
                 auto matrixEntry = matrix.getRow(it->first, 0).begin();
                 STORM_LOG_ASSERT(matrixEntry->getColumn() == failedStateId, "Transition has wrong target state.");
                 STORM_LOG_ASSERT(!it->second.first->isPseudoState(), "State is still pseudo state.");
+
+                ExplorationHeuristicPointer heuristic = it->second.second;
+                if (storm::utility::isZero(heuristic->getUpperBound())) {
+                    // Initialize bounds
+                    ValueType lowerBound = getLowerBound(it->second.first);
+                    ValueType upperBound = getUpperBound(it->second.first);
+                    heuristic->setBounds(lowerBound, upperBound);
+                }
+
+                // Change bound
                 if (lowerBound) {
                     matrixEntry->setValue(it->second.second->getLowerBound());
                 } else {
@@ -489,6 +487,7 @@ namespace storm {
             for (size_t index = 0; index < state->nrNotFailableBEs(); ++index) {
                 rates[index + state->nrFailableBEs()] = state->getNotFailableBERate(index);
             }
+            STORM_LOG_ASSERT(rates.size() > 0, "State is absorbing");
 
             // TODO Matthias: works only for <64 BEs!
             for (size_t i = 1; i < 4 && i <= rates.size(); ++i) {

From 386d4c7f056b3ce475c76f574bf0f56c49d8f75f Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Wed, 26 Oct 2016 23:14:21 +0200
Subject: [PATCH 45/65] Use heuristic NONE to explore complete state space

Former-commit-id: 25990b5ddaa23c00702940d75ac03879df11aeae
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 10 +++++-----
 src/builder/ExplicitDFTModelBuilderApprox.h   |  2 +-
 src/storage/BucketPriorityQueue.h             |  2 +-
 src/storage/dft/DFTState.cpp                  |  2 +-
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 432636161..5a3e65585 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -33,12 +33,12 @@ namespace storm {
                 matrixBuilder(!generator.isDeterministicModel()),
                 stateStorage(((dft.stateVectorSize() / 64) + 1) * 64),
                 // TODO Matthias: make choosable
-                //explorationQueue(dft.nrElements()+1, 0, 1)
-                explorationQueue(1001, 0, 0.001)
+                explorationQueue(dft.nrElements()+1, 0, 1)
+                //explorationQueue(1001, 0, 0.001)
         {
             // Intentionally left empty.
             // TODO Matthias: remove again
-            heuristic = storm::builder::ApproximationHeuristic::PROBABILITY;
+            heuristic = storm::builder::ApproximationHeuristic::NONE;
         }
 
         template<typename ValueType, typename StateType>
@@ -266,8 +266,8 @@ namespace storm {
                 // Try to explore the next state
                 generator.load(currentState);
 
-                if (nrExpandedStates > approximationThreshold && !currentExplorationHeuristic->isExpand()) {
-                //if (currentExplorationHeuristic->isSkip(approximationThreshold)) {
+                //if (nrExpandedStates > approximationThreshold && !currentExplorationHeuristic->isExpand()) {
+                if (currentExplorationHeuristic->isSkip(approximationThreshold)) {
                     // Skip the current state
                     ++nrSkippedStates;
                     STORM_LOG_TRACE("Skip expansion of state: " << dft.getStateString(currentState));
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index 446bed6ad..c3ffe4467 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -28,7 +28,7 @@ namespace storm {
 
             using DFTStatePointer = std::shared_ptr<storm::storage::DFTState<ValueType>>;
             // TODO Matthias: make choosable
-            using ExplorationHeuristic = DFTExplorationHeuristicProbability<ValueType>;
+            using ExplorationHeuristic = DFTExplorationHeuristicNone<ValueType>;
             using ExplorationHeuristicPointer = std::shared_ptr<ExplorationHeuristic>;
 
 
diff --git a/src/storage/BucketPriorityQueue.h b/src/storage/BucketPriorityQueue.h
index 253b34e19..1aa18689d 100644
--- a/src/storage/BucketPriorityQueue.h
+++ b/src/storage/BucketPriorityQueue.h
@@ -13,7 +13,7 @@ namespace storm {
         template<typename ValueType>
         class BucketPriorityQueue {
 
-            using HeuristicPointer = std::shared_ptr<storm::builder::DFTExplorationHeuristicProbability<ValueType>>;
+            using HeuristicPointer = std::shared_ptr<storm::builder::DFTExplorationHeuristicNone<ValueType>>;
 
         public:
             explicit BucketPriorityQueue(size_t nrBuckets, double lowerValue, double stepPerBucket);
diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index b9381598f..aaad9367f 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -323,7 +323,7 @@ namespace storm {
                         mCurrentlyFailableBE.push_back(elem);
                         // Remove from not failable BEs
                         auto it = std::find(mCurrentlyNotFailableBE.begin(), mCurrentlyNotFailableBE.end(), elem);
-                        STORM_LOG_ASSERT(it != mCurrentlyNotFailableBE.end(), "Element not found.");
+                        STORM_LOG_ASSERT(it != mCurrentlyNotFailableBE.end(), "Element " << elem << " not found.");
                         mCurrentlyNotFailableBE.erase(it);
                     }
                 } else if (mDft.getElement(elem)->isSpareGate() && !isActive(uses(elem))) {

From d9b1285644ea8c5f97b194537ea259533cb9c526 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Thu, 27 Oct 2016 16:54:12 +0200
Subject: [PATCH 46/65] Alternative way of computing permutations (at the
 moment in parallel)

Former-commit-id: f5886860bcf2854e1322fc780c113b530cec5094
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 5a3e65585..3be21bfb4 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -510,6 +510,25 @@ namespace storm {
                     upperBound += sum;
                 }
             }
+
+            // Compute upper bound with permutations of size <= 3
+            ValueType upperBound2 = storm::utility::zero<ValueType>();
+            for (size_t i1 = 0; i1 < rates.size(); ++i1) {
+                // + 1/a
+                ValueType sum = rates[i1];
+                upperBound2 += storm::utility::one<ValueType>() / sum;
+                for (size_t i2 = 0; i2 < i1; ++i2) {
+                    // - 1/(a+b)
+                    ValueType sum2 = sum + rates[i2];
+                    upperBound2 -= storm::utility::one<ValueType>() / sum2;
+                    for (size_t i3 = 0; i3 < i2; ++i3) {
+                        // + 1/(a+b+c)
+                        upperBound2 += storm::utility::one<ValueType>() / (sum2 + rates[i3]);
+                    }
+                }
+            }
+            STORM_LOG_ASSERT(upperBound == upperBound2, "Upperbounds are different: " << upperBound << " and " << upperBound2);
+
             STORM_LOG_ASSERT(!storm::utility::isZero(upperBound), "UpperBound is 0");
             return storm::utility::one<ValueType>() / upperBound;
         }

From 876b147aa8a5123ffa1d8b4e86b3935d110479aa Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Thu, 27 Oct 2016 16:55:50 +0200
Subject: [PATCH 47/65] Fixed bug with iterator

Former-commit-id: f7248a57c175d5ee47d5929fd739187c59507118
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 5a3e65585..ac61efc0f 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -153,7 +153,8 @@ namespace storm {
             auto iterSkipped = skippedStates.begin();
             size_t skippedBefore = 0;
             for (size_t i = 0; i < indexRemapping.size(); ++i) {
-                while (iterSkipped->first <= i) {
+                while (iterSkipped != skippedStates.end() && iterSkipped->first <= i) {
+                    STORM_LOG_ASSERT(iterSkipped->first < indexRemapping.size(), "Skipped is too high.");
                     ++skippedBefore;
                     ++iterSkipped;
                 }

From c12bbe29045202b3caa2108e6a46d1b3d4aca65b Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Thu, 27 Oct 2016 18:57:26 +0200
Subject: [PATCH 48/65] Disable old way of computing permutations as there is a
 bug for >31 elements

Former-commit-id: ae7af404f3ab73f03463c6e5d1776bab229379b3
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 22 +++++++++----------
 src/modelchecker/dft/DFTModelChecker.cpp      |  2 ++
 src/utility/bitoperations.h                   |  2 +-
 3 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 3be21bfb4..1991cec95 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -475,8 +475,7 @@ namespace storm {
         template<typename ValueType, typename StateType>
         ValueType ExplicitDFTModelBuilderApprox<ValueType, StateType>::getUpperBound(DFTStatePointer const& state) const {
             // Get the upper bound by considering the failure of all BEs
-            // The used formula for the rate is 1/( 1/a + 1/b + ...)
-            // TODO Matthias: improve by using closed formula for AND of all BEs
+            // The used formula for the rate is 1/( 1/a + 1/b + 1/c + ... - 1/(a+b) - 1/(a+c) - ... + 1/(a+b+c) + ... - ...)
             ValueType upperBound = storm::utility::zero<ValueType>();
 
             // Get all possible rates
@@ -490,44 +489,45 @@ namespace storm {
             STORM_LOG_ASSERT(rates.size() > 0, "State is absorbing");
 
             // TODO Matthias: works only for <64 BEs!
-            for (size_t i = 1; i < 4 && i <= rates.size(); ++i) {
+            // WARNING: this code produces wrong results for more than 32 BEs
+            /*for (size_t i = 1; i < 4 && i <= rates.size(); ++i) {
                 size_t permutation = smallestIntWithNBitsSet(static_cast<size_t>(i));
                 ValueType sum = storm::utility::zero<ValueType>();
                 do {
                     ValueType permResult = storm::utility::zero<ValueType>();
                     for(size_t j = 0; j < rates.size(); ++j) {
-                        if(permutation & (1 << j)) {
+                        if(permutation & static_cast<size_t>(1 << static_cast<size_t>(j))) {
+                            // WARNING: if the first bit is set, it also recognizes the 32nd bit as set
+                            // TODO: fix
                             permResult += rates[j];
                         }
                     }
                     permutation = nextBitPermutation(permutation);
                     STORM_LOG_ASSERT(!storm::utility::isZero(permResult), "PermResult is 0");
                     sum += storm::utility::one<ValueType>() / permResult;
-                } while(permutation < (1 << rates.size()) && permutation != 0);
+                } while(permutation < (static_cast<size_t>(1) << rates.size()) && permutation != 0);
                 if (i % 2 == 0) {
                     upperBound -= sum;
                 } else {
                     upperBound += sum;
                 }
-            }
+            }*/
 
             // Compute upper bound with permutations of size <= 3
-            ValueType upperBound2 = storm::utility::zero<ValueType>();
             for (size_t i1 = 0; i1 < rates.size(); ++i1) {
                 // + 1/a
                 ValueType sum = rates[i1];
-                upperBound2 += storm::utility::one<ValueType>() / sum;
+                upperBound += storm::utility::one<ValueType>() / sum;
                 for (size_t i2 = 0; i2 < i1; ++i2) {
                     // - 1/(a+b)
                     ValueType sum2 = sum + rates[i2];
-                    upperBound2 -= storm::utility::one<ValueType>() / sum2;
+                    upperBound -= storm::utility::one<ValueType>() / sum2;
                     for (size_t i3 = 0; i3 < i2; ++i3) {
                         // + 1/(a+b+c)
-                        upperBound2 += storm::utility::one<ValueType>() / (sum2 + rates[i3]);
+                        upperBound += storm::utility::one<ValueType>() / (sum2 + rates[i3]);
                     }
                 }
             }
-            STORM_LOG_ASSERT(upperBound == upperBound2, "Upperbounds are different: " << upperBound << " and " << upperBound2);
 
             STORM_LOG_ASSERT(!storm::utility::isZero(upperBound), "UpperBound is 0");
             return storm::utility::one<ValueType>() / upperBound;
diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index 59d85f5c2..ff2148982 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -100,6 +100,8 @@ namespace storm {
                     ValueType result = storm::utility::zero<ValueType>();
                     int limK = invResults ? -1 : nrM+1;
                     int chK = invResults ? -1 : 1;
+                    // WARNING: there is a bug for computing permutations with more than 32 elements
+                    STORM_LOG_ASSERT(res.size() < 32, "Permutations work only for < 32 elements");
                     for(int cK = nrK; cK != limK; cK += chK ) {
                         STORM_LOG_ASSERT(cK >= 0, "ck negative.");
                         size_t permutation = smallestIntWithNBitsSet(static_cast<size_t>(cK));
diff --git a/src/utility/bitoperations.h b/src/utility/bitoperations.h
index bec6a6414..18b42a1cd 100644
--- a/src/utility/bitoperations.h
+++ b/src/utility/bitoperations.h
@@ -10,6 +10,6 @@ inline size_t smallestIntWithNBitsSet(size_t n) {
 inline size_t nextBitPermutation(size_t v) {
     if (v==0) return static_cast<size_t>(0);
     // From https://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation
-    unsigned int t = (v | (v - 1)) + 1;  
+    size_t t = (v | (v - 1)) + 1;
     return t | ((((t & -t) / (v & -v)) >> 1) - 1);  
 }

From 6778a018ad9848faabd8702b50f8bd53ecbf143f Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Thu, 27 Oct 2016 19:05:24 +0200
Subject: [PATCH 49/65] Use heuristic probability

Former-commit-id: 747b34cfdc1bcabdb673155939946287923af3da
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 10 +++++-----
 src/builder/ExplicitDFTModelBuilderApprox.h   |  2 +-
 src/storage/BucketPriorityQueue.h             |  2 +-
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 86a45235d..131c0389e 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -33,12 +33,12 @@ namespace storm {
                 matrixBuilder(!generator.isDeterministicModel()),
                 stateStorage(((dft.stateVectorSize() / 64) + 1) * 64),
                 // TODO Matthias: make choosable
-                explorationQueue(dft.nrElements()+1, 0, 1)
-                //explorationQueue(1001, 0, 0.001)
+                //explorationQueue(dft.nrElements()+1, 0, 1)
+                explorationQueue(1001, 0, 0.001)
         {
             // Intentionally left empty.
             // TODO Matthias: remove again
-            heuristic = storm::builder::ApproximationHeuristic::NONE;
+            heuristic = storm::builder::ApproximationHeuristic::PROBABILITY;
         }
 
         template<typename ValueType, typename StateType>
@@ -267,8 +267,8 @@ namespace storm {
                 // Try to explore the next state
                 generator.load(currentState);
 
-                //if (nrExpandedStates > approximationThreshold && !currentExplorationHeuristic->isExpand()) {
-                if (currentExplorationHeuristic->isSkip(approximationThreshold)) {
+                if (nrExpandedStates > approximationThreshold && !currentExplorationHeuristic->isExpand()) {
+                //if (currentExplorationHeuristic->isSkip(approximationThreshold)) {
                     // Skip the current state
                     ++nrSkippedStates;
                     STORM_LOG_TRACE("Skip expansion of state: " << dft.getStateString(currentState));
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index c3ffe4467..446bed6ad 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -28,7 +28,7 @@ namespace storm {
 
             using DFTStatePointer = std::shared_ptr<storm::storage::DFTState<ValueType>>;
             // TODO Matthias: make choosable
-            using ExplorationHeuristic = DFTExplorationHeuristicNone<ValueType>;
+            using ExplorationHeuristic = DFTExplorationHeuristicProbability<ValueType>;
             using ExplorationHeuristicPointer = std::shared_ptr<ExplorationHeuristic>;
 
 
diff --git a/src/storage/BucketPriorityQueue.h b/src/storage/BucketPriorityQueue.h
index 1aa18689d..253b34e19 100644
--- a/src/storage/BucketPriorityQueue.h
+++ b/src/storage/BucketPriorityQueue.h
@@ -13,7 +13,7 @@ namespace storm {
         template<typename ValueType>
         class BucketPriorityQueue {
 
-            using HeuristicPointer = std::shared_ptr<storm::builder::DFTExplorationHeuristicNone<ValueType>>;
+            using HeuristicPointer = std::shared_ptr<storm::builder::DFTExplorationHeuristicProbability<ValueType>>;
 
         public:
             explicit BucketPriorityQueue(size_t nrBuckets, double lowerValue, double stepPerBucket);

From b669a3acef838a2841695eda8add73d85cc421d7 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Thu, 27 Oct 2016 21:42:11 +0200
Subject: [PATCH 50/65] Only sort bucket queue if more than 10% is unsorted

Former-commit-id: 7ebd1e49c8a74198e4e36e5eeffdfc0ddb158020
---
 src/storage/BucketPriorityQueue.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/storage/BucketPriorityQueue.cpp b/src/storage/BucketPriorityQueue.cpp
index eb174cce0..c758be7ee 100644
--- a/src/storage/BucketPriorityQueue.cpp
+++ b/src/storage/BucketPriorityQueue.cpp
@@ -14,7 +14,7 @@ namespace storm {
 
         template<typename ValueType>
         void BucketPriorityQueue<ValueType>::fix() {
-            if (currentBucket < buckets.size() && nrUnsortedItems > 0) {
+            if (currentBucket < buckets.size() && nrUnsortedItems > buckets[currentBucket].size() / 10) {
                 // Fix current bucket
                 std::make_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
                 nrUnsortedItems = 0;

From a2c484bba43de66721bd575ad98002eef7fabf0b Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Thu, 27 Oct 2016 21:43:02 +0200
Subject: [PATCH 51/65] Support for probability approximation without
 modularisation

Former-commit-id: 921c8d310c9eab5b82300c908d3f039e9451500a
---
 src/modelchecker/dft/DFTModelChecker.cpp | 18 ++++++++++++------
 src/modelchecker/dft/DFTModelChecker.h   |  6 ++++--
 2 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index ff2148982..e49db7a37 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -158,6 +158,8 @@ namespace storm {
                 storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
                 typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
 
+                bool probabilityFormula = formula->isProbabilityOperatorFormula();
+                STORM_LOG_ASSERT((formula->isTimeOperatorFormula() && !probabilityFormula) || (!formula->isTimeOperatorFormula() && probabilityFormula), "Probability formula not initialized correctly");
                 size_t iteration = 0;
                 do {
                     // Iteratively build finer models
@@ -170,7 +172,7 @@ namespace storm {
 
                     // Build model for lower bound
                     STORM_LOG_INFO("Getting model for lower bound...");
-                    model = builder.getModelApproximation(true);
+                    model = builder.getModelApproximation(probabilityFormula ? false : true);
                     // We only output the info from the lower bound as the info for the upper bound is the same
                     STORM_LOG_INFO("No. states: " << model->getNumberOfStates());
                     STORM_LOG_INFO("No. transitions: " << model->getNumberOfTransitions());
@@ -185,7 +187,7 @@ namespace storm {
                     // Build model for upper bound
                     STORM_LOG_INFO("Getting model for upper bound...");
                     explorationStart = std::chrono::high_resolution_clock::now();
-                    model = builder.getModelApproximation(false);
+                    model = builder.getModelApproximation(probabilityFormula ? true : false);
                     explorationTime += std::chrono::high_resolution_clock::now() - explorationStart;
                     // Check upper bound
                     result = checkModel(model, formula);
@@ -197,7 +199,7 @@ namespace storm {
                     ++iteration;
                     STORM_LOG_INFO("Result after iteration " << iteration << ": (" << std::setprecision(10) << approxResult.first << ", " << approxResult.second << ")");
                     STORM_LOG_THROW(!storm::utility::isInfinity<ValueType>(approxResult.first) && !storm::utility::isInfinity<ValueType>(approxResult.second), storm::exceptions::NotSupportedException, "Approximation does not work if result might be infinity.");
-                } while (!isApproximationSufficient(approxResult.first, approxResult.second, approximationError));
+                } while (!isApproximationSufficient(approxResult.first, approxResult.second, approximationError, probabilityFormula));
 
                 STORM_LOG_INFO("Finished approximation after " << iteration << " iteration" << (iteration > 1 ? "s." : "."));
                 return approxResult;
@@ -251,14 +253,18 @@ namespace storm {
         }
 
         template<typename ValueType>
-        bool DFTModelChecker<ValueType>::isApproximationSufficient(ValueType lowerBound, ValueType upperBound, double approximationError) {
+        bool DFTModelChecker<ValueType>::isApproximationSufficient(ValueType lowerBound, ValueType upperBound, double approximationError, bool relative) {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Approximation works only for double.");
         }
 
         template<>
-        bool DFTModelChecker<double>::isApproximationSufficient(double lowerBound, double upperBound, double approximationError) {
+        bool DFTModelChecker<double>::isApproximationSufficient(double lowerBound, double upperBound, double approximationError, bool relative) {
             STORM_LOG_THROW(!std::isnan(lowerBound) && !std::isnan(upperBound), storm::exceptions::NotSupportedException, "Approximation does not work if result is NaN.");
-            return upperBound - lowerBound <= approximationError * (lowerBound + upperBound) / 2;
+            if (relative) {
+                return upperBound - lowerBound <= approximationError;
+            } else {
+                return upperBound - lowerBound <= approximationError * (lowerBound + upperBound) / 2;
+            }
         }
 
         template<typename ValueType>
diff --git a/src/modelchecker/dft/DFTModelChecker.h b/src/modelchecker/dft/DFTModelChecker.h
index 83df59bfa..b351ab67b 100644
--- a/src/modelchecker/dft/DFTModelChecker.h
+++ b/src/modelchecker/dft/DFTModelChecker.h
@@ -107,15 +107,17 @@ namespace storm {
 
             /*!
              * Checks if the computed approximation is sufficient, i.e.
-             * upperBound - lowerBound <= approximationError * mean(upperBound, lowerBound).
+             * upperBound - lowerBound <= approximationError * mean(lowerBound, upperBound).
              *
              * @param lowerBound         The lower bound on the result.
              * @param upperBound         The upper bound on the result.
              * @param approximationError The allowed error for approximating.
+             * @param relative           Flag indicating if the error should be relative to 1 or
+                                         to the mean of lower and upper bound.
              *
              * @return True, if the approximation is sufficient.
              */
-            bool isApproximationSufficient(ValueType lowerBound, ValueType upperBound, double approximationError);
+            bool isApproximationSufficient(ValueType lowerBound, ValueType upperBound, double approximationError, bool relative);
 
         };
     }

From 02c4195f31102da38c3c37615197145f26c669f8 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Fri, 28 Oct 2016 17:56:09 +0200
Subject: [PATCH 52/65] Better upper bound for independent subtrees

Former-commit-id: 64f5a1ca603833ea1dafedb1078f17be7c049e20
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 115 +++++++++++++++---
 src/builder/ExplicitDFTModelBuilderApprox.h   |  13 ++
 src/storage/BucketPriorityQueue.cpp           |   2 -
 src/storage/dft/DFTState.cpp                  |  23 ++--
 src/storage/dft/DFTState.h                    |  22 ++--
 5 files changed, 135 insertions(+), 40 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 131c0389e..7f3e8c09e 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -39,6 +39,61 @@ namespace storm {
             // Intentionally left empty.
             // TODO Matthias: remove again
             heuristic = storm::builder::ApproximationHeuristic::PROBABILITY;
+
+            // Compute independent subtrees
+            if (dft.topLevelType() == storm::storage::DFTElementType::OR) {
+                // We only support this for approximation with top level element OR
+                for (auto const& child : dft.getGate(dft.getTopLevelIndex())->children()) {
+                    // Consider all children of the top level gate
+                    std::vector<size_t> isubdft;
+                    if (child->nrParents() > 1 || child->hasOutgoingDependencies()) {
+                        STORM_LOG_TRACE("child " << child->name() << "does not allow modularisation.");
+                        isubdft.clear();
+                    } else if (dft.isGate(child->id())) {
+                        isubdft = dft.getGate(child->id())->independentSubDft(false);
+                    } else {
+                        STORM_LOG_ASSERT(dft.isBasicElement(child->id()), "Child is no BE.");
+                        if(dft.getBasicElement(child->id())->hasIngoingDependencies()) {
+                            STORM_LOG_TRACE("child " << child->name() << "does not allow modularisation.");
+                            isubdft.clear();
+                        } else {
+                            isubdft = {child->id()};
+                        }
+                    }
+                    if(isubdft.empty()) {
+                        subtreeBEs.clear();
+                        break;
+                    } else {
+                        // Add new independent subtree
+                        std::vector<size_t> subtree;
+                        for (size_t id : isubdft) {
+                            if (dft.isBasicElement(id)) {
+                                subtree.push_back(id);
+                            }
+                        }
+                        subtreeBEs.push_back(subtree);
+                    }
+                }
+            }
+            if (subtreeBEs.empty()) {
+                // Consider complete tree
+                std::vector<size_t> subtree;
+                for (size_t id = 0; id < dft.nrElements(); ++id) {
+                    if (dft.isBasicElement(id)) {
+                        subtree.push_back(id);
+                    }
+                }
+                subtreeBEs.push_back(subtree);
+            }
+
+            for (auto tree : subtreeBEs) {
+                std::stringstream stream;
+                stream << "Subtree: ";
+                for (size_t id : tree) {
+                    stream << id << ", ";
+                }
+                STORM_LOG_TRACE(stream.str());
+            }
         }
 
         template<typename ValueType, typename StateType>
@@ -476,18 +531,42 @@ namespace storm {
         template<typename ValueType, typename StateType>
         ValueType ExplicitDFTModelBuilderApprox<ValueType, StateType>::getUpperBound(DFTStatePointer const& state) const {
             // Get the upper bound by considering the failure of all BEs
-            // The used formula for the rate is 1/( 1/a + 1/b + 1/c + ... - 1/(a+b) - 1/(a+c) - ... + 1/(a+b+c) + ... - ...)
-            ValueType upperBound = storm::utility::zero<ValueType>();
+            ValueType upperBound = storm::utility::one<ValueType>();
+            ValueType rateSum = storm::utility::zero<ValueType>();
+
+            // Compute for each independent subtree
+            for (std::vector<size_t> const& subtree : subtreeBEs) {
+                // Get all possible rates
+                std::vector<ValueType> rates;
+                for (size_t id : subtree) {
+                    if (state->isOperational(id)) {
+                        // Get BE rate
+                        rates.push_back(state->getBERate(id, true));
+                        rateSum += rates.back();
+                    }
+                }
 
-            // Get all possible rates
-            std::vector<ValueType> rates(state->nrFailableBEs() + state->nrNotFailableBEs());
-            for (size_t index = 0; index < state->nrFailableBEs(); ++index) {
-                rates[index] = state->getFailableBERate(index);
+                // We move backwards and start with swapping the last element to itself
+                // Then we do not need to swap back
+                for (auto it = rates.rbegin(); it != rates.rend(); ++it) {
+                    // Compute AND MTTF of subtree without current rate and scale with current rate
+                    std::iter_swap(it, rates.end() - 1);
+                    upperBound += rates.back() * computeMTTFAnd(rates, rates.size() - 1);
+                }
             }
-            for (size_t index = 0; index < state->nrNotFailableBEs(); ++index) {
-                rates[index + state->nrFailableBEs()] = state->getNotFailableBERate(index);
+
+            STORM_LOG_TRACE("Upper bound is " << (rateSum / upperBound) << " for state " << state->getId());
+            STORM_LOG_ASSERT(!storm::utility::isZero(upperBound), "Upper bound is 0");
+            STORM_LOG_ASSERT(!storm::utility::isZero(rateSum), "State is absorbing");
+            return rateSum / upperBound;
+        }
+
+        template<typename ValueType, typename StateType>
+        ValueType ExplicitDFTModelBuilderApprox<ValueType, StateType>::computeMTTFAnd(std::vector<ValueType> rates, size_t size) const {
+            ValueType result = storm::utility::zero<ValueType>();
+            if (size == 0) {
+                return result;
             }
-            STORM_LOG_ASSERT(rates.size() > 0, "State is absorbing");
 
             // TODO Matthias: works only for <64 BEs!
             // WARNING: this code produces wrong results for more than 32 BEs
@@ -508,30 +587,30 @@ namespace storm {
                     sum += storm::utility::one<ValueType>() / permResult;
                 } while(permutation < (static_cast<size_t>(1) << rates.size()) && permutation != 0);
                 if (i % 2 == 0) {
-                    upperBound -= sum;
+                    result -= sum;
                 } else {
-                    upperBound += sum;
+                    result += sum;
                 }
             }*/
 
-            // Compute upper bound with permutations of size <= 3
-            for (size_t i1 = 0; i1 < rates.size(); ++i1) {
+            // Compute result with permutations of size <= 3
+            for (size_t i1 = 0; i1 < size; ++i1) {
                 // + 1/a
                 ValueType sum = rates[i1];
-                upperBound += storm::utility::one<ValueType>() / sum;
+                result += storm::utility::one<ValueType>() / sum;
                 for (size_t i2 = 0; i2 < i1; ++i2) {
                     // - 1/(a+b)
                     ValueType sum2 = sum + rates[i2];
-                    upperBound -= storm::utility::one<ValueType>() / sum2;
+                    result -= storm::utility::one<ValueType>() / sum2;
                     for (size_t i3 = 0; i3 < i2; ++i3) {
                         // + 1/(a+b+c)
-                        upperBound += storm::utility::one<ValueType>() / (sum2 + rates[i3]);
+                        result += storm::utility::one<ValueType>() / (sum2 + rates[i3]);
                     }
                 }
             }
 
-            STORM_LOG_ASSERT(!storm::utility::isZero(upperBound), "UpperBound is 0");
-            return storm::utility::one<ValueType>() / upperBound;
+            STORM_LOG_ASSERT(!storm::utility::isZero(result), "UpperBound is 0");
+            return result;
         }
 
         template<typename ValueType, typename StateType>
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index 446bed6ad..8cc53a176 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -238,6 +238,16 @@ namespace storm {
              */
             ValueType getUpperBound(DFTStatePointer const& state) const;
 
+            /*!
+             * Compute the MTTF of an AND gate via a closed formula.
+             * The used formula is 1/( 1/a + 1/b + 1/c + ... - 1/(a+b) - 1/(a+c) - ... + 1/(a+b+c) + ... - ...)
+             *
+             * @param rates List of rates of children of AND.
+             * @param size  Only indices < size are considered in the vector.
+             * @return MTTF.
+             */
+            ValueType computeMTTFAnd(std::vector<ValueType> rates, size_t size) const;
+
             /*!
              * Compares the priority of two states.
              *
@@ -314,6 +324,9 @@ namespace storm {
             // Notice that we need an ordered map here to easily iterate in increasing order over state ids.
             // TODO remove again
             std::map<StateType, std::pair<DFTStatePointer, ExplorationHeuristicPointer>> skippedStates;
+
+            // List of independent subtrees and the BEs contained in them.
+            std::vector<std::vector<size_t>> subtreeBEs;
         };
 
     }
diff --git a/src/storage/BucketPriorityQueue.cpp b/src/storage/BucketPriorityQueue.cpp
index c758be7ee..99ed19cd4 100644
--- a/src/storage/BucketPriorityQueue.cpp
+++ b/src/storage/BucketPriorityQueue.cpp
@@ -41,7 +41,6 @@ namespace storm {
                 return immediateBucket.back();
             }
             STORM_LOG_ASSERT(!empty(), "BucketPriorityQueue is empty");
-            STORM_LOG_ASSERT(nrUnsortedItems == 0, "First bucket is not sorted");
             return buckets[currentBucket].front();
         }
 
@@ -126,7 +125,6 @@ namespace storm {
                 return;
             }
             STORM_LOG_ASSERT(!empty(), "BucketPriorityQueue is empty");
-            STORM_LOG_ASSERT(nrUnsortedItems == 0, "First bucket is not sorted");
             std::pop_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
             buckets[currentBucket].pop_back();
             if (buckets[currentBucket].empty()) {
diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index aaad9367f..64728cbd5 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -241,21 +241,26 @@ namespace storm {
         }
 
         template<typename ValueType>
-        ValueType DFTState<ValueType>::getBERate(size_t id, bool considerPassive) const {
+        ValueType DFTState<ValueType>::getBERate(size_t id, bool avoidCold) const {
             STORM_LOG_ASSERT(mDft.isBasicElement(id), "Element is no BE.");
-            if (considerPassive && mDft.hasRepresentant(id) && !isActive(mDft.getRepresentant(id))) {
-                STORM_LOG_ASSERT(!storm::utility::isZero(mDft.getBasicElement(id)->passiveFailureRate()), "Failure rate of BE " << mDft.getBasicElement(id)->id() << " is 0 in state " << mDft.getStateString(mStatus, mStateGenerationInfo, mId));
-                return mDft.getBasicElement(id)->passiveFailureRate();
-            } else {
-                STORM_LOG_ASSERT(!storm::utility::isZero(mDft.getBasicElement(id)->activeFailureRate()), "Failure rate of BE " << mDft.getBasicElement(id)->id() << " is 0 in state " << mDft.getStateString(mStatus, mStateGenerationInfo, mId));
-                return mDft.getBasicElement(id)->activeFailureRate();
+
+            if (mDft.hasRepresentant(id) && !isActive(mDft.getRepresentant(id))) {
+                if (avoidCold && mDft.getBasicElement(id)->isColdBasicElement()) {
+                    // Return active failure rate instead of 0.
+                    return mDft.getBasicElement(id)->activeFailureRate();
+                } else {
+                    // Return passive failure rate
+                    return mDft.getBasicElement(id)->passiveFailureRate();
+                }
             }
+            // Return active failure rate
+            return mDft.getBasicElement(id)->activeFailureRate();
         }
 
         template<typename ValueType>
         ValueType DFTState<ValueType>::getFailableBERate(size_t index) const {
             STORM_LOG_ASSERT(index < nrFailableBEs(), "Index invalid.");
-            return getBERate(mCurrentlyFailableBE[index], true);
+            return getBERate(mCurrentlyFailableBE[index], false);
         }
 
         template<typename ValueType>
@@ -264,7 +269,7 @@ namespace storm {
             STORM_LOG_ASSERT(isPseudoState() || storm::utility::isZero<ValueType>(mDft.getBasicElement(mCurrentlyNotFailableBE[index])->activeFailureRate()) ||
                              (mDft.hasRepresentant(mCurrentlyNotFailableBE[index]) && !isActive(mDft.getRepresentant(mCurrentlyNotFailableBE[index]))), "BE " << mCurrentlyNotFailableBE[index] << " can fail in state: " << mDft.getStateString(mStatus, mStateGenerationInfo, mId));
             // Use active failure rate as passive failure rate is 0.
-            return getBERate(mCurrentlyNotFailableBE[index], false);
+            return getBERate(mCurrentlyNotFailableBE[index], true);
         }
 
         template<typename ValueType>
diff --git a/src/storage/dft/DFTState.h b/src/storage/dft/DFTState.h
index 4ff36d1ab..0f8280591 100644
--- a/src/storage/dft/DFTState.h
+++ b/src/storage/dft/DFTState.h
@@ -208,6 +208,17 @@ namespace storm {
              */
             ValueType getNotFailableBERate(size_t index) const;
 
+            /**
+             * Get the failure rate of the given BE.
+             *
+             * @param id        Id of BE.
+             * @param avoidCold Flag indicating if a cold passive failure rate should be avoided by giving
+             *                  the active failure rate instead.
+             *
+             * @return Failure rate of the BE.
+             */
+            ValueType getBERate(size_t id, bool avoidCold) const;
+
             /** Get number of currently failable dependencies.
              *
              * @return Number of failable dependencies.
@@ -302,17 +313,6 @@ namespace storm {
         private:
             void propagateActivation(size_t representativeId);
 
-            /**
-             * Get the failure rate of the given BE.
-             *
-             * @param id              Id of BE.
-             * @param considerPassive Flag indicating if the passive failure rate should be returned if
-             *                        the BE currently is passive.
-             *
-             * @return Failure rate of the BE.
-             */
-            ValueType getBERate(size_t id, bool considerPassive) const;
-
         };
 
     }

From dae1a7eefe69c9ed7bdf7c34d7c43a437f63f105 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Fri, 28 Oct 2016 19:31:59 +0200
Subject: [PATCH 53/65] Do not use cold BEs in first step of approximation
 formula

Former-commit-id: d204be9633c605c450933ee4659a9b8a5e1ac4cd
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 32 ++++++-----
 src/storage/dft/DFTState.cpp                  | 53 +++----------------
 src/storage/dft/DFTState.h                    | 25 +--------
 3 files changed, 29 insertions(+), 81 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 7f3e8c09e..28b943ba9 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -522,9 +522,6 @@ namespace storm {
             for (size_t index = 0; index < state->nrFailableBEs(); ++index) {
                 lowerBound += state->getFailableBERate(index);
             }
-            for (size_t index = 0; index < state->nrNotFailableBEs(); ++index) {
-                lowerBound += state->getNotFailableBERate(index);
-            }
             return lowerBound;
         }
 
@@ -538,20 +535,31 @@ namespace storm {
             for (std::vector<size_t> const& subtree : subtreeBEs) {
                 // Get all possible rates
                 std::vector<ValueType> rates;
-                for (size_t id : subtree) {
+                storm::storage::BitVector coldBEs(subtree.size(), false);
+                for (size_t i = 0; i < subtree.size(); ++i) {
+                    size_t id = subtree[i];
                     if (state->isOperational(id)) {
                         // Get BE rate
-                        rates.push_back(state->getBERate(id, true));
-                        rateSum += rates.back();
+                        ValueType rate = state->getBERate(id);
+                        if (storm::utility::isZero<ValueType>(rate)) {
+                            // Get active failure rate for cold BE
+                            rate = dft.getBasicElement(id)->activeFailureRate();
+                            // Mark BE as cold
+                            coldBEs.set(i, true);
+                        }
+                        rates.push_back(rate);
+                        rateSum += rate;
                     }
                 }
 
-                // We move backwards and start with swapping the last element to itself
-                // Then we do not need to swap back
-                for (auto it = rates.rbegin(); it != rates.rend(); ++it) {
-                    // Compute AND MTTF of subtree without current rate and scale with current rate
-                    std::iter_swap(it, rates.end() - 1);
-                    upperBound += rates.back() * computeMTTFAnd(rates, rates.size() - 1);
+                for (size_t i = 0; i < rates.size(); ++i) {
+                    // Cold BEs cannot fail in the first step
+                    if (!coldBEs.get(i)) {
+                        // Compute AND MTTF of subtree without current rate and scale with current rate
+                        upperBound += rates.back() * computeMTTFAnd(rates, rates.size() - 1);
+                        // Swap here to avoid swapping back
+                        std::iter_swap(rates.begin() + i, rates.end() - 1);
+                    }
                 }
             }
 
diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index 64728cbd5..cc0eaabec 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -17,23 +17,11 @@ namespace storm {
                 this->setUses(spareId, elem->children()[0]->id());
             }
 
-            for (auto elem : mDft.getBasicElements()) {
-                if (!storm::utility::isZero(elem->activeFailureRate())) {
-                    mCurrentlyNotFailableBE.push_back(elem->id());
-                }
-            }
-
             // Initialize activation
             propagateActivation(mDft.getTopLevelIndex());
 
             std::vector<size_t> alwaysActiveBEs = mDft.nonColdBEs();
             mCurrentlyFailableBE.insert(mCurrentlyFailableBE.end(), alwaysActiveBEs.begin(), alwaysActiveBEs.end());
-            // Remove always active BEs from currently not failable BEs
-            for (size_t id : alwaysActiveBEs) {
-                auto it = std::find(mCurrentlyNotFailableBE.begin(), mCurrentlyNotFailableBE.end(), id);
-                STORM_LOG_ASSERT(it != mCurrentlyNotFailableBE.end(), "Id not found.");
-                mCurrentlyNotFailableBE.erase(it);
-            }
         }
 
         template<typename ValueType>
@@ -46,7 +34,6 @@ namespace storm {
             STORM_LOG_TRACE("Construct concrete state from pseudo state " << mDft.getStateString(mStatus, mStateGenerationInfo, mId));
             // Clear information from pseudo state
             mCurrentlyFailableBE.clear();
-            mCurrentlyNotFailableBE.clear();
             mFailableDependencies.clear();
             mUsedRepresentants.clear();
             STORM_LOG_ASSERT(mPseudoState, "Only pseudo states can be constructed.");
@@ -57,10 +44,6 @@ namespace storm {
                     if ((!be->isColdBasicElement() && be->canFail()) || !mDft.hasRepresentant(index) || isActive(mDft.getRepresentant(index))) {
                         mCurrentlyFailableBE.push_back(index);
                         STORM_LOG_TRACE("Currently failable: " << mDft.getBasicElement(index)->toString());
-                    } else {
-                        // BE currently is not failable
-                        mCurrentlyNotFailableBE.push_back(index);
-                        STORM_LOG_TRACE("Currently not failable: " << mDft.getBasicElement(index)->toString());
                     }
                 } else if (mDft.getElement(index)->isSpareGate()) {
                     // Initialize used representants
@@ -204,11 +187,6 @@ namespace storm {
             auto it = std::find(mCurrentlyFailableBE.begin(), mCurrentlyFailableBE.end(), id);
             if (it != mCurrentlyFailableBE.end()) {
                 mCurrentlyFailableBE.erase(it);
-            } else {
-                it = std::find(mCurrentlyNotFailableBE.begin(), mCurrentlyNotFailableBE.end(), id);
-                if (it != mCurrentlyNotFailableBE.end()) {
-                    mCurrentlyNotFailableBE.erase(it);
-                }
             }
         }
 
@@ -241,35 +219,22 @@ namespace storm {
         }
 
         template<typename ValueType>
-        ValueType DFTState<ValueType>::getBERate(size_t id, bool avoidCold) const {
+        ValueType DFTState<ValueType>::getBERate(size_t id) const {
             STORM_LOG_ASSERT(mDft.isBasicElement(id), "Element is no BE.");
 
             if (mDft.hasRepresentant(id) && !isActive(mDft.getRepresentant(id))) {
-                if (avoidCold && mDft.getBasicElement(id)->isColdBasicElement()) {
-                    // Return active failure rate instead of 0.
-                    return mDft.getBasicElement(id)->activeFailureRate();
-                } else {
-                    // Return passive failure rate
-                    return mDft.getBasicElement(id)->passiveFailureRate();
-                }
+                // Return passive failure rate
+                return mDft.getBasicElement(id)->passiveFailureRate();
+            } else {
+                // Return active failure rate
+                return mDft.getBasicElement(id)->activeFailureRate();
             }
-            // Return active failure rate
-            return mDft.getBasicElement(id)->activeFailureRate();
         }
 
         template<typename ValueType>
         ValueType DFTState<ValueType>::getFailableBERate(size_t index) const {
             STORM_LOG_ASSERT(index < nrFailableBEs(), "Index invalid.");
-            return getBERate(mCurrentlyFailableBE[index], false);
-        }
-
-        template<typename ValueType>
-        ValueType DFTState<ValueType>::getNotFailableBERate(size_t index) const {
-            STORM_LOG_ASSERT(index < nrNotFailableBEs(), "Index invalid.");
-            STORM_LOG_ASSERT(isPseudoState() || storm::utility::isZero<ValueType>(mDft.getBasicElement(mCurrentlyNotFailableBE[index])->activeFailureRate()) ||
-                             (mDft.hasRepresentant(mCurrentlyNotFailableBE[index]) && !isActive(mDft.getRepresentant(mCurrentlyNotFailableBE[index]))), "BE " << mCurrentlyNotFailableBE[index] << " can fail in state: " << mDft.getStateString(mStatus, mStateGenerationInfo, mId));
-            // Use active failure rate as passive failure rate is 0.
-            return getBERate(mCurrentlyNotFailableBE[index], true);
+            return getBERate(mCurrentlyFailableBE[index]);
         }
 
         template<typename ValueType>
@@ -326,10 +291,6 @@ namespace storm {
                     if (be->isColdBasicElement() && be->canFail()) {
                         // Add to failable BEs
                         mCurrentlyFailableBE.push_back(elem);
-                        // Remove from not failable BEs
-                        auto it = std::find(mCurrentlyNotFailableBE.begin(), mCurrentlyNotFailableBE.end(), elem);
-                        STORM_LOG_ASSERT(it != mCurrentlyNotFailableBE.end(), "Element " << elem << " not found.");
-                        mCurrentlyNotFailableBE.erase(it);
                     }
                 } else if (mDft.getElement(elem)->isSpareGate() && !isActive(uses(elem))) {
                     propagateActivation(uses(elem));
diff --git a/src/storage/dft/DFTState.h b/src/storage/dft/DFTState.h
index 0f8280591..b077b58b0 100644
--- a/src/storage/dft/DFTState.h
+++ b/src/storage/dft/DFTState.h
@@ -27,7 +27,6 @@ namespace storm {
             storm::storage::BitVector mStatus;
             size_t mId;
             std::vector<size_t> mCurrentlyFailableBE;
-            std::vector<size_t> mCurrentlyNotFailableBE;
             std::vector<size_t> mFailableDependencies;
             std::vector<size_t> mUsedRepresentants;
             bool mPseudoState;
@@ -181,15 +180,6 @@ namespace storm {
                 return mCurrentlyFailableBE.size();
             }
 
-            /**
-             * Get number of currently not failable BEs. These are cold BE which can fail in the future.
-             *
-             * @return Number of not failable BEs.
-             */
-            size_t nrNotFailableBEs() const {
-                return mCurrentlyNotFailableBE.size();
-            }
-
             /**
              * Get the failure rate of the currently failable BE on the given index.
              *
@@ -200,24 +190,13 @@ namespace storm {
             ValueType getFailableBERate(size_t index) const;
 
             /**
-             * Get the failure rate of the currently not failable BE on the given index.
-             *
-             * @param index Index of BE in list of currently not failable BEs.
-             *
-             * @return Failure rate of the BE.
-             */
-            ValueType getNotFailableBERate(size_t index) const;
-
-            /**
-             * Get the failure rate of the given BE.
+             * Get the current failure rate of the given BE.
              *
              * @param id        Id of BE.
-             * @param avoidCold Flag indicating if a cold passive failure rate should be avoided by giving
-             *                  the active failure rate instead.
              *
              * @return Failure rate of the BE.
              */
-            ValueType getBERate(size_t id, bool avoidCold) const;
+            ValueType getBERate(size_t id) const;
 
             /** Get number of currently failable dependencies.
              *

From 64699a7badb5a7e56f6e8366bb85758b5175f46d Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Fri, 28 Oct 2016 21:35:16 +0200
Subject: [PATCH 54/65] Several improvements

Former-commit-id: 047ebde33bd77dcde7b0a2df5c5e384828f91684
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 12 +++---
 src/modelchecker/dft/DFTModelChecker.cpp      | 26 +++++++------
 src/modelchecker/dft/DFTModelChecker.h        |  1 +
 src/storage/BucketPriorityQueue.cpp           | 37 +++++++++++++------
 src/storage/BucketPriorityQueue.h             | 25 ++++++++-----
 5 files changed, 60 insertions(+), 41 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 28b943ba9..1d04e5210 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -34,7 +34,7 @@ namespace storm {
                 stateStorage(((dft.stateVectorSize() / 64) + 1) * 64),
                 // TODO Matthias: make choosable
                 //explorationQueue(dft.nrElements()+1, 0, 1)
-                explorationQueue(1001, 0, 0.001)
+                explorationQueue(200, 0, 0.9)
         {
             // Intentionally left empty.
             // TODO Matthias: remove again
@@ -291,9 +291,6 @@ namespace storm {
             size_t nrSkippedStates = 0;
             // TODO Matthias: do not empty queue every time but break before
             while (!explorationQueue.empty()) {
-                explorationQueue.fix();
-                //explorationQueue.print(std::cout);
-                //printNotExplored();
                 // Get the first state in the queue
                 ExplorationHeuristicPointer currentExplorationHeuristic = explorationQueue.popTop();
                 StateType currentId = currentExplorationHeuristic->getId();
@@ -602,17 +599,18 @@ namespace storm {
             }*/
 
             // Compute result with permutations of size <= 3
+            ValueType one = storm::utility::one<ValueType>();
             for (size_t i1 = 0; i1 < size; ++i1) {
                 // + 1/a
                 ValueType sum = rates[i1];
-                result += storm::utility::one<ValueType>() / sum;
+                result += one / sum;
                 for (size_t i2 = 0; i2 < i1; ++i2) {
                     // - 1/(a+b)
                     ValueType sum2 = sum + rates[i2];
-                    result -= storm::utility::one<ValueType>() / sum2;
+                    result -= one / sum2;
                     for (size_t i3 = 0; i3 < i2; ++i3) {
                         // + 1/(a+b+c)
-                        result += storm::utility::one<ValueType>() / (sum2 + rates[i3]);
+                        result += one / (sum2 + rates[i3]);
                     }
                 }
             }
diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index e49db7a37..5eee17e3e 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -17,13 +17,13 @@ namespace storm {
         template<typename ValueType>
         void DFTModelChecker<ValueType>::check(storm::storage::DFT<ValueType> const& origDft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool allowModularisation, bool enableDC, double approximationError) {
             // Initialize
-            this->buildingTime = std::chrono::duration<double>::zero();
             this->explorationTime = std::chrono::duration<double>::zero();
+            this->buildingTime = std::chrono::duration<double>::zero();
             this->bisimulationTime = std::chrono::duration<double>::zero();
             this->modelCheckingTime = std::chrono::duration<double>::zero();
             this->totalTime = std::chrono::duration<double>::zero();
             this->approximationError = approximationError;
-            std::chrono::high_resolution_clock::time_point totalStart = std::chrono::high_resolution_clock::now();
+            totalStart = std::chrono::high_resolution_clock::now();
 
             // Optimizing DFT
             storm::storage::DFT<ValueType> dft = origDft.optimize();
@@ -134,7 +134,7 @@ namespace storm {
 
         template<typename ValueType>
         typename DFTModelChecker<ValueType>::dft_result DFTModelChecker<ValueType>::checkDFT(storm::storage::DFT<ValueType> const& dft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool enableDC, double approximationError) {
-            std::chrono::high_resolution_clock::time_point buildingStart = std::chrono::high_resolution_clock::now();
+            std::chrono::high_resolution_clock::time_point checkingStart = std::chrono::high_resolution_clock::now();
 
             // Find symmetries
             std::map<size_t, std::vector<std::vector<size_t>>> emptySymmetry;
@@ -145,15 +145,12 @@ namespace storm {
                 STORM_LOG_INFO("Found " << symmetries.groups.size() << " symmetries.");
                 STORM_LOG_TRACE("Symmetries: " << std::endl << symmetries);
             }
-            std::chrono::high_resolution_clock::time_point buildingEnd = std::chrono::high_resolution_clock::now();
-            buildingTime += buildingEnd - buildingStart;
 
             if (approximationError > 0.0) {
                 // Comparator for checking the error of the approximation
                 storm::utility::ConstantsComparator<ValueType> comparator;
                 // Build approximate Markov Automata for lower and upper bound
                 approximation_result approxResult = std::make_pair(storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>());
-                std::chrono::high_resolution_clock::time_point explorationStart;
                 std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
                 storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
                 typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
@@ -163,10 +160,12 @@ namespace storm {
                 size_t iteration = 0;
                 do {
                     // Iteratively build finer models
-                    explorationStart = std::chrono::high_resolution_clock::now();
+                    std::chrono::high_resolution_clock::time_point explorationStart = std::chrono::high_resolution_clock::now();
                     STORM_LOG_INFO("Building model...");
                     // TODO Matthias refine model using existing model and MC results
                     builder.buildModel(labeloptions, iteration, approximationError);
+                    std::chrono::high_resolution_clock::time_point explorationEnd = std::chrono::high_resolution_clock::now();
+                    explorationTime = explorationEnd - explorationStart;
 
                     // TODO Matthias: possible to do bisimulation on approximated model and not on concrete one?
 
@@ -176,7 +175,8 @@ namespace storm {
                     // We only output the info from the lower bound as the info for the upper bound is the same
                     STORM_LOG_INFO("No. states: " << model->getNumberOfStates());
                     STORM_LOG_INFO("No. transitions: " << model->getNumberOfTransitions());
-                    explorationTime += std::chrono::high_resolution_clock::now() - explorationStart;
+                    buildingTime += std::chrono::high_resolution_clock::now() - explorationEnd;
+
                     // Check lower bound
                     std::unique_ptr<storm::modelchecker::CheckResult> result = checkModel(model, formula);
                     result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
@@ -186,9 +186,9 @@ namespace storm {
 
                     // Build model for upper bound
                     STORM_LOG_INFO("Getting model for upper bound...");
-                    explorationStart = std::chrono::high_resolution_clock::now();
+                    explorationEnd = std::chrono::high_resolution_clock::now();
                     model = builder.getModelApproximation(probabilityFormula ? true : false);
-                    explorationTime += std::chrono::high_resolution_clock::now() - explorationStart;
+                    buildingTime += std::chrono::high_resolution_clock::now() - explorationEnd;
                     // Check upper bound
                     result = checkModel(model, formula);
                     result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
@@ -198,6 +198,8 @@ namespace storm {
 
                     ++iteration;
                     STORM_LOG_INFO("Result after iteration " << iteration << ": (" << std::setprecision(10) << approxResult.first << ", " << approxResult.second << ")");
+                    totalTime = std::chrono::high_resolution_clock::now() - totalStart;
+                    printTimings();
                     STORM_LOG_THROW(!storm::utility::isInfinity<ValueType>(approxResult.first) && !storm::utility::isInfinity<ValueType>(approxResult.second), storm::exceptions::NotSupportedException, "Approximation does not work if result might be infinity.");
                 } while (!isApproximationSufficient(approxResult.first, approxResult.second, approximationError, probabilityFormula));
 
@@ -221,7 +223,7 @@ namespace storm {
                 //model->printModelInformationToStream(std::cout);
                 STORM_LOG_INFO("No. states (Explored): " << model->getNumberOfStates());
                 STORM_LOG_INFO("No. transitions (Explored): " << model->getNumberOfTransitions());
-                explorationTime += std::chrono::high_resolution_clock::now() - buildingEnd;
+                explorationTime += std::chrono::high_resolution_clock::now() - checkingStart;
 
                 // Model checking
                 std::unique_ptr<storm::modelchecker::CheckResult> result = checkModel(model, formula);
@@ -270,8 +272,8 @@ namespace storm {
         template<typename ValueType>
         void DFTModelChecker<ValueType>::printTimings(std::ostream& os) {
             os << "Times:" << std::endl;
-            os << "Building:\t" << buildingTime.count() << std::endl;
             os << "Exploration:\t" << explorationTime.count() << std::endl;
+            os << "Building:\t" << buildingTime.count() << std::endl;
             os << "Bisimulation:\t" << bisimulationTime.count() << std::endl;
             os << "Modelchecking:\t" << modelCheckingTime.count() << std::endl;
             os << "Total:\t\t" << totalTime.count() << std::endl;
diff --git a/src/modelchecker/dft/DFTModelChecker.h b/src/modelchecker/dft/DFTModelChecker.h
index b351ab67b..543bf97fd 100644
--- a/src/modelchecker/dft/DFTModelChecker.h
+++ b/src/modelchecker/dft/DFTModelChecker.h
@@ -61,6 +61,7 @@ namespace storm {
             std::chrono::duration<double> bisimulationTime = std::chrono::duration<double>::zero();
             std::chrono::duration<double> modelCheckingTime = std::chrono::duration<double>::zero();
             std::chrono::duration<double> totalTime = std::chrono::duration<double>::zero();
+            std::chrono::high_resolution_clock::time_point totalStart;
 
             // Model checking result
             dft_result checkResult;
diff --git a/src/storage/BucketPriorityQueue.cpp b/src/storage/BucketPriorityQueue.cpp
index 99ed19cd4..224b14cf6 100644
--- a/src/storage/BucketPriorityQueue.cpp
+++ b/src/storage/BucketPriorityQueue.cpp
@@ -2,11 +2,13 @@
 #include "src/utility/macros.h"
 #include "src/adapters/CarlAdapter.h"
 
+#include <cmath>
+
 namespace storm {
     namespace storage {
 
         template<typename ValueType>
-        BucketPriorityQueue<ValueType>::BucketPriorityQueue(size_t nrBuckets, double lowerValue, double stepPerBucket) : buckets(nrBuckets), currentBucket(nrBuckets), lowerValue(lowerValue), stepPerBucket(stepPerBucket), nrUnsortedItems(0) {
+        BucketPriorityQueue<ValueType>::BucketPriorityQueue(size_t nrBuckets, double lowerValue, double ratio) : lowerValue(lowerValue), logBase(std::log(ratio)), nrBuckets(nrBuckets), nrUnsortedItems(0), buckets(nrBuckets), currentBucket(nrBuckets) {
             compare = ([this](HeuristicPointer a, HeuristicPointer b) {
                 return *a < *b;
             });
@@ -14,7 +16,7 @@ namespace storm {
 
         template<typename ValueType>
         void BucketPriorityQueue<ValueType>::fix() {
-            if (currentBucket < buckets.size() && nrUnsortedItems > buckets[currentBucket].size() / 10) {
+            if (currentBucket < nrBuckets && nrUnsortedItems > buckets[currentBucket].size() / 10) {
                 // Fix current bucket
                 std::make_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
                 nrUnsortedItems = 0;
@@ -23,13 +25,13 @@ namespace storm {
 
         template<typename ValueType>
         bool BucketPriorityQueue<ValueType>::empty() const {
-            return currentBucket == buckets.size() && immediateBucket.empty();
+            return currentBucket == nrBuckets && immediateBucket.empty();
         }
 
         template<typename ValueType>
         std::size_t BucketPriorityQueue<ValueType>::size() const {
             size_t size = immediateBucket.size();
-            for (size_t i = currentBucket; currentBucket < buckets.size(); ++i) {
+            for (size_t i = currentBucket; currentBucket < nrBuckets; ++i) {
                 size += buckets[i].size();
             }
             return size;
@@ -129,7 +131,7 @@ namespace storm {
             buckets[currentBucket].pop_back();
             if (buckets[currentBucket].empty()) {
                 // Find next bucket with elements
-                for ( ; currentBucket < buckets.size(); ++currentBucket) {
+                for ( ; currentBucket < nrBuckets; ++currentBucket) {
                     if (!buckets[currentBucket].empty()) {
                         nrUnsortedItems = buckets[currentBucket].size();
                         if (AUTOSORT) {
@@ -151,18 +153,21 @@ namespace storm {
         template<typename ValueType>
         size_t BucketPriorityQueue<ValueType>::getBucket(double priority) const {
             STORM_LOG_ASSERT(priority >= lowerValue, "Priority " << priority << " is too low");
-            size_t newBucket = (priority - lowerValue) / stepPerBucket;
-            if (HIGHER) {
-                newBucket = buckets.size()-1 - newBucket;
+            size_t newBucket = std::log(priority - lowerValue) / logBase;
+            if (newBucket >= nrBuckets) {
+                newBucket = nrBuckets - 1;
+            }
+            if (!HIGHER) {
+                newBucket = nrBuckets-1 - newBucket;
             }
-            //std::cout << "get Bucket: " << priority << ", " << newBucket << ", " << ((priority - lowerValue) / stepPerBucket) << std::endl;
-            STORM_LOG_ASSERT(newBucket < buckets.size(), "Priority " << priority << " is too high");
+            //std::cout << "get Bucket: " << priority << ", " << newBucket << std::endl;
+            STORM_LOG_ASSERT(newBucket < nrBuckets, "Priority " << priority << " is too high");
             return newBucket;
         }
 
         template<typename ValueType>
         void BucketPriorityQueue<ValueType>::print(std::ostream& out) const {
-            out << "Bucket priority queue with size " << buckets.size() << ", lower value: " << lowerValue << " and step per bucket: " << stepPerBucket << std::endl;
+            out << "Bucket priority queue with size " << buckets.size() << ", lower value: " << lowerValue << " and logBase: " << logBase << std::endl;
             out << "Immediate bucket: ";
             for (HeuristicPointer heuristic : immediateBucket) {
                 out << heuristic->getId() << ", ";
@@ -171,7 +176,7 @@ namespace storm {
             out << "Current bucket (" << currentBucket << ") has " << nrUnsortedItems  << " unsorted items" << std::endl;
             for (size_t bucket = 0; bucket < buckets.size(); ++bucket) {
                 if (!buckets[bucket].empty()) {
-                    out << "Bucket " << bucket << " (" << (HIGHER ? buckets.size() -1 - bucket * stepPerBucket : bucket * stepPerBucket) << "):" << std::endl;
+                    out << "Bucket " << bucket << ":" << std::endl;
                     for (HeuristicPointer heuristic : buckets[bucket]) {
                         out << "\t" << heuristic->getId() << ": " << heuristic->getPriority() << std::endl;
                     }
@@ -179,6 +184,14 @@ namespace storm {
             }
         }
 
+        template<typename ValueType>
+        void BucketPriorityQueue<ValueType>::printSizes(std::ostream& out) const {
+            out << "Bucket sizes: " << immediateBucket.size() << " | ";
+            for (size_t bucket = 0; bucket < buckets.size(); ++bucket) {
+                out << buckets[bucket].size() << " ";
+            }
+            std::cout << std::endl;
+        }
 
         // Template instantiations
         template class BucketPriorityQueue<double>;
diff --git a/src/storage/BucketPriorityQueue.h b/src/storage/BucketPriorityQueue.h
index 253b34e19..1719c7124 100644
--- a/src/storage/BucketPriorityQueue.h
+++ b/src/storage/BucketPriorityQueue.h
@@ -16,7 +16,7 @@ namespace storm {
             using HeuristicPointer = std::shared_ptr<storm::builder::DFTExplorationHeuristicProbability<ValueType>>;
 
         public:
-            explicit BucketPriorityQueue(size_t nrBuckets, double lowerValue, double stepPerBucket);
+            explicit BucketPriorityQueue(size_t nrBuckets, double lowerValue, double ratio);
 
             void fix();
 
@@ -36,10 +36,24 @@ namespace storm {
 
             void print(std::ostream& out) const;
 
+            void printSizes(std::ostream& out) const;
+
         private:
 
             size_t getBucket(double priority) const;
 
+            const double lowerValue;
+
+            const bool HIGHER = true;
+
+            const bool AUTOSORT = false;
+
+            const double logBase;
+
+            const size_t nrBuckets;
+
+            size_t nrUnsortedItems;
+
             // List of buckets
             std::vector<std::vector<HeuristicPointer>> buckets;
 
@@ -51,15 +65,6 @@ namespace storm {
 
             std::function<bool(HeuristicPointer, HeuristicPointer)> compare;
 
-            double lowerValue;
-
-            double stepPerBucket;
-
-            size_t nrUnsortedItems;
-
-            const bool HIGHER = true;
-
-            const bool AUTOSORT = false;
         };
 
     }

From d95bb71f75a4febcd93abf7b075261671fe070a5 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Sat, 29 Oct 2016 00:02:20 +0200
Subject: [PATCH 55/65] Tried to gain more performance

Former-commit-id: 9af2ab7ce0cc6fc311bd5f45c8b2ea79f29c989c
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 19 ++++++++++++++++---
 src/builder/ExplicitDFTModelBuilderApprox.h   |  2 +-
 2 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 1d04e5210..93a7b282e 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -549,11 +549,24 @@ namespace storm {
                     }
                 }
 
+                STORM_LOG_ASSERT(rates.size() > 0, "No rates failable");
+
+                // Sort rates
+                std::sort(rates.begin(), rates.end());
+                std::vector<size_t> rateCount(rates.size(), 0);
+                size_t lastIndex = 0;
+                for (size_t i = 0; i < rates.size(); ++i) {
+                    if (rates[lastIndex] != rates[i]) {
+                        lastIndex = i;
+                    }
+                    ++rateCount[lastIndex];
+                }
+
                 for (size_t i = 0; i < rates.size(); ++i) {
                     // Cold BEs cannot fail in the first step
-                    if (!coldBEs.get(i)) {
+                    if (!coldBEs.get(i) && rateCount[i] > 0) {
                         // Compute AND MTTF of subtree without current rate and scale with current rate
-                        upperBound += rates.back() * computeMTTFAnd(rates, rates.size() - 1);
+                        upperBound += rates.back() * rateCount[i] * computeMTTFAnd(rates, rates.size() - 1);
                         // Swap here to avoid swapping back
                         std::iter_swap(rates.begin() + i, rates.end() - 1);
                     }
@@ -567,7 +580,7 @@ namespace storm {
         }
 
         template<typename ValueType, typename StateType>
-        ValueType ExplicitDFTModelBuilderApprox<ValueType, StateType>::computeMTTFAnd(std::vector<ValueType> rates, size_t size) const {
+        ValueType ExplicitDFTModelBuilderApprox<ValueType, StateType>::computeMTTFAnd(std::vector<ValueType> const& rates, size_t size) const {
             ValueType result = storm::utility::zero<ValueType>();
             if (size == 0) {
                 return result;
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index 8cc53a176..933cd3277 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -246,7 +246,7 @@ namespace storm {
              * @param size  Only indices < size are considered in the vector.
              * @return MTTF.
              */
-            ValueType computeMTTFAnd(std::vector<ValueType> rates, size_t size) const;
+            ValueType computeMTTFAnd(std::vector<ValueType> const& rates, size_t size) const;
 
             /*!
              * Compares the priority of two states.

From 464a497093f821c37b5bb106afbc45c55cc65ae7 Mon Sep 17 00:00:00 2001
From: sjunges <sebastian.junges@rwth-aachen.de>
Date: Sat, 29 Oct 2016 21:47:53 +0200
Subject: [PATCH 56/65] smt checker v1, and better error messages

Former-commit-id: ab7391e85db4b7e94d9a6dfb2dfa383d570ff8c0
---
 DFTASFChecker.cpp                      |   9 +
 DFTASFChecker.hpp                      |  14 +
 src/modelchecker/dft/DFTASFChecker.cpp | 413 +++++++++++++++++++++++++
 src/modelchecker/dft/DFTASFChecker.h   |  61 ++++
 src/storage/dft/DFTBuilder.cpp         |   2 +-
 src/storage/dft/DFTState.cpp           |   2 +-
 src/storm-dyftee.cpp                   |  13 +-
 7 files changed, 507 insertions(+), 7 deletions(-)
 create mode 100644 DFTASFChecker.cpp
 create mode 100644 DFTASFChecker.hpp
 create mode 100644 src/modelchecker/dft/DFTASFChecker.cpp
 create mode 100644 src/modelchecker/dft/DFTASFChecker.h

diff --git a/DFTASFChecker.cpp b/DFTASFChecker.cpp
new file mode 100644
index 000000000..de7a59428
--- /dev/null
+++ b/DFTASFChecker.cpp
@@ -0,0 +1,9 @@
+//
+//  DFTASFChecker.cpp
+//  storm
+//
+//  Created by Sebastian Junges on 27/10/16.
+//
+//
+
+#include "DFTASFChecker.hpp"
diff --git a/DFTASFChecker.hpp b/DFTASFChecker.hpp
new file mode 100644
index 000000000..7920f026a
--- /dev/null
+++ b/DFTASFChecker.hpp
@@ -0,0 +1,14 @@
+//
+//  DFTASFChecker.hpp
+//  storm
+//
+//  Created by Sebastian Junges on 27/10/16.
+//
+//
+
+#ifndef DFTASFChecker_hpp
+#define DFTASFChecker_hpp
+
+#include <stdio.h>
+
+#endif /* DFTASFChecker_hpp */
diff --git a/src/modelchecker/dft/DFTASFChecker.cpp b/src/modelchecker/dft/DFTASFChecker.cpp
new file mode 100644
index 000000000..ac28ba5cf
--- /dev/null
+++ b/src/modelchecker/dft/DFTASFChecker.cpp
@@ -0,0 +1,413 @@
+#include "DFTASFChecker.h"
+#include <string>
+
+namespace storm {
+    
+    namespace modelchecker {
+        
+        /*
+         *  Variable[VarIndex] is the maximum of the others
+         */
+        class IsMaximum : public DFTConstraint {
+        public:
+            IsMaximum(uint64_t varIndex, std::vector<uint64_t> const& varIndices) : varIndex(varIndex), varIndices(varIndices) {
+                
+            }
+            
+            virtual ~IsMaximum() {
+                
+            }
+            
+            std::string toSmtlib2(std::vector<std::string> const& varNames) const override {
+                std::stringstream sstr;
+                sstr << "(and ";
+                // assert it is largereq than all values.
+                for (auto const& ovi : varIndices) {
+                    sstr << "(>= " << varNames.at(varIndex) << " " << varNames.at(ovi) << ") ";
+                }
+                // assert it is one of the values.
+                sstr << "(or ";
+                for (auto const& ovi : varIndices) {
+                    sstr << "(= " << varNames.at(varIndex) << " " << varNames.at(ovi) << ") ";
+                }
+                sstr << ")"; // end of the or
+                sstr << ")"; // end outer and.
+                return sstr.str();
+                
+            }
+                
+                
+            private:
+                uint64_t varIndex;
+                std::vector<uint64_t> varIndices;
+                };
+                /*
+                 *  First is the minimum of the others
+                 */
+                class IsMinimum : public DFTConstraint {
+                public:
+                    IsMinimum(uint64_t varIndex, std::vector<uint64_t> const& varIndices) : varIndex(varIndex), varIndices(varIndices) {
+                        
+                    }
+                    
+                    
+                    virtual ~IsMinimum() {
+                        
+                    }
+                    
+                    std::string toSmtlib2(std::vector<std::string> const& varNames) const override {
+                        std::stringstream sstr;
+                        sstr << "(and ";
+                        // assert it is smallereq than all values.
+                        for (auto const& ovi : varIndices) {
+                            sstr << "(<= " << varNames.at(varIndex) << " " << varNames.at(ovi) << ") ";
+                        }
+                        // assert it is one of the values.
+                        sstr << "(or ";
+                        for (auto const& ovi : varIndices) {
+                            sstr << "(= " << varNames.at(varIndex) << " " << varNames.at(ovi) << ") ";
+                        }
+                        sstr << ")"; // end of the or
+                        sstr << ")"; // end outer and.
+                        return sstr.str();
+                        
+                    }
+                    
+                    
+                private:
+                    uint64_t varIndex;
+                    std::vector<uint64_t> varIndices;
+                };
+                
+                class BetweenValues : public DFTConstraint {
+                public:
+                    BetweenValues(uint64_t varIndex, uint64_t lower, uint64_t upper) : varIndex(varIndex), upperBound(upper) , lowerBound(lower) {
+                        
+                    }
+                    virtual ~BetweenValues() {
+                        
+                    }
+                    
+                    std::string toSmtlib2(std::vector<std::string> const& varNames) const override {
+                        std::stringstream sstr;
+                        sstr << "(and ";
+                        sstr << "(>= " << varNames.at(varIndex) << " " << lowerBound << ")";
+                        sstr << "(<= " << varNames.at(varIndex) << " " << upperBound << ")";
+                        sstr << ")";
+                        return sstr.str();
+                    }
+                    
+                private:
+                    uint64_t varIndex;
+                    uint64_t upperBound;
+                    uint64_t lowerBound;
+                };
+                
+                class And : public DFTConstraint {
+                public:
+                    And(std::vector<std::shared_ptr<DFTConstraint>> const& constraints) : constraints(constraints) {}
+                    
+                    virtual ~And() {
+                        
+                    }
+                    
+                    std::string toSmtlib2(std::vector<std::string> const& varNames) const override {
+                        std::stringstream sstr;
+                        sstr << "(and";
+                        for(auto const& c : constraints) {
+                            sstr << " " << c->toSmtlib2(varNames);
+                        }
+                        sstr << ")";
+                        return sstr.str();
+                    }
+                private:
+                    std::vector<std::shared_ptr<DFTConstraint>> constraints;
+                    
+                };
+                
+                class Iff : public DFTConstraint {
+                public:
+                    Iff(std::shared_ptr<DFTConstraint> l, std::shared_ptr<DFTConstraint> r) : lhs(l), rhs(r) {
+                        
+                    }
+                    
+                    
+                    std::string toSmtlib2(std::vector<std::string> const& varNames) const override {
+                        std::stringstream sstr;
+                        sstr << "(= " << lhs->toSmtlib2(varNames) << " " << rhs->toSmtlib2(varNames) << ")";
+                        return sstr.str();
+                    }
+                    
+                private:
+                    std::shared_ptr<DFTConstraint> lhs;
+                    std::shared_ptr<DFTConstraint> rhs;
+                };
+                
+                class IsConstantValue : public DFTConstraint {
+                public:
+                    IsConstantValue(uint64_t varIndex, uint64_t val) : varIndex(varIndex), value(val) {
+                        
+                    }
+                    
+                    virtual ~IsConstantValue() {
+                        
+                    }
+                    
+                    std::string toSmtlib2(std::vector<std::string> const& varNames) const override {
+                        std::stringstream sstr;
+                        assert(varIndex < varNames.size());
+                        sstr << "(= " << varNames.at(varIndex) << " " << value << ")";
+                        return sstr.str();
+                    }
+                    
+                private:
+                    uint64_t varIndex;
+                    uint64_t value;
+                };
+                
+                class IsEqual : public DFTConstraint {
+                public:
+                    IsEqual(uint64_t varIndex1, uint64_t varIndex2) :var1Index(varIndex1), var2Index(varIndex2) {
+                        
+                    }
+                    
+                    virtual ~IsEqual() {
+                        
+                    }
+                    
+                    std::string toSmtlib2(std::vector<std::string> const& varNames) const override {
+                        return "(= " + varNames.at(var1Index) + " " +  varNames.at(var2Index) + " )";
+                    }
+                    
+                private:
+                    uint64_t var1Index;
+                    uint64_t var2Index;
+                };
+                
+                class IsLEqual : public DFTConstraint {
+                public:
+                    IsLEqual(uint64_t varIndex1, uint64_t varIndex2) :var1Index(varIndex1), var2Index(varIndex2) {
+                        
+                    }
+                    
+                    virtual ~IsLEqual() {
+                        
+                    }
+                    
+                    std::string toSmtlib2(std::vector<std::string> const& varNames) const override {
+                        return "(<= " + varNames.at(var1Index) + " " +  varNames.at(var2Index) + " )";
+                    }
+                    
+                private:
+                    uint64_t var1Index;
+                    uint64_t var2Index;
+                };
+                
+                class PairwiseDifferent : public DFTConstraint {
+                public:
+                    PairwiseDifferent(std::vector<uint64_t> const& indices) : varIndices(indices) {
+                        
+                    }
+                    virtual ~PairwiseDifferent() {
+                        
+                    }
+                    
+                    std::string toSmtlib2(std::vector<std::string> const& varNames) const override {
+                        std::stringstream sstr;
+                        sstr << "(distinct";
+                        //                for(uint64_t i = 0; i < varIndices.size(); ++i) {
+                        //                    for(uint64_t j = i + 1; j < varIndices.size(); ++j) {
+                        //                        sstr << "()";
+                        //                    }
+                        //                }
+                        for (auto const& varIndex : varIndices) {
+                            sstr << " " << varNames.at(varIndex);
+                        }
+                        sstr << ")";
+                        return sstr.str();
+                    }
+                    
+                private:
+                    std::vector<uint64_t> varIndices;
+                };
+                
+                class Sorted : public DFTConstraint {
+                public:
+                    Sorted(std::vector<uint64_t> varIndices) : varIndices(varIndices) {
+                        
+                    }
+                    
+                    virtual ~Sorted() {
+                        
+                    }
+                    
+                    std::string toSmtlib2(std::vector<std::string> const& varNames) const override {
+                        std::stringstream sstr;
+                        sstr << "(and ";
+                        for(uint64_t i = 1; i < varIndices.size(); ++i) {
+                            sstr << "(<= " << varNames.at(varIndices.at(i-1)) << " " << varNames.at(varIndices.at(i)) << ")";
+                        }
+                        sstr << ") ";
+                        return sstr.str();
+                    }
+                    
+                    
+                private:
+                    std::vector<uint64_t> varIndices;
+                };
+                
+                class IfThenElse : public DFTConstraint {
+                public:
+                    IfThenElse(std::shared_ptr<DFTConstraint> ifC, std::shared_ptr<DFTConstraint> thenC, std::shared_ptr<DFTConstraint> elseC) : ifConstraint(ifC), thenConstraint(thenC), elseConstraint(elseC) {
+                        
+                    }
+                    
+                    std::string toSmtlib2(std::vector<std::string> const& varNames) const override {
+                        std::stringstream sstr;
+                        sstr << "(ite " << ifConstraint->toSmtlib2(varNames) << " " << thenConstraint->toSmtlib2(varNames) << " " << elseConstraint->toSmtlib2(varNames) << ")";
+                        return sstr.str();
+                    }
+                    
+                private:
+                    std::shared_ptr<DFTConstraint> ifConstraint;
+                    std::shared_ptr<DFTConstraint> thenConstraint;
+                    std::shared_ptr<DFTConstraint> elseConstraint;
+                };
+                
+                
+                DFTASFChecker::DFTASFChecker(storm::storage::DFT<double> const& dft) : dft(dft) {
+                    // Intentionally left empty.
+                }
+                
+                uint64_t DFTASFChecker::getClaimVariableIndex(uint64_t spare, uint64_t child) const {
+                    return claimVariables.at(SpareAndChildPair(spare, child));
+                }
+                
+                void DFTASFChecker::convert() {
+                    
+                    std::vector<uint64_t> beVariables;
+                    // Convert all elements
+                    for (size_t i = 0; i < dft.nrElements(); ++i) {
+                        std::shared_ptr<storm::storage::DFTElement<ValueType> const> element = dft.getElement(i);
+                        varNames.push_back("t_" + element->name());
+                        timePointVariables.emplace(i, varNames.size() - 1);
+                        switch (element->type()) {
+                            case storm::storage::DFTElementType::BE:
+                                beVariables.push_back(varNames.size() - 1);
+                                break;
+                            case storm::storage::DFTElementType::SPARE:
+                            {
+                                auto spare = std::static_pointer_cast<storm::storage::DFTSpare<double> const>(element);
+                                for( auto const& spareChild : spare->children()) {
+                                    varNames.push_back("c_" + element->name() + "_" + spareChild->name());
+                                    claimVariables.emplace(SpareAndChildPair(element->id(), spareChild->id()), varNames.size() - 1);
+                                }
+                                break;
+                            }
+                            default:
+                                break;
+                        }
+                    }
+                    
+                    // BE
+                    constraints.push_back(std::make_shared<PairwiseDifferent>(beVariables));
+                    constraints.back()->setDescription("No two BEs fail at the same time");
+                    for( auto const& beV : beVariables) {
+                        constraints.push_back(std::make_shared<BetweenValues>(beV, 1, dft.nrBasicElements()));
+                    }
+                    
+                    // Claim variables
+                    for (auto const& csvV : claimVariables) {
+                        constraints.push_back(std::make_shared<BetweenValues>(csvV.second, 0, dft.nrBasicElements() + 1));
+                    }
+                    
+                    for (size_t i = 0; i < dft.nrElements(); ++i) {
+                        std::shared_ptr<storm::storage::DFTElement<ValueType> const> element = dft.getElement(i);
+                        if(element->isSpareGate()) {
+                            auto spare = std::static_pointer_cast<storm::storage::DFTSpare<double> const>(element);
+                            auto const& spareChild = spare->children().front();
+                            constraints.push_back(std::make_shared<IsConstantValue>(getClaimVariableIndex(spare->id(), spareChild->id()), 0));
+                            constraints.back()->setDescription("Spare " + spare->name() + " claims first child");
+                            
+                        }
+                    }
+                    
+                    
+                    for (size_t i = 0; i < dft.nrElements(); ++i) {
+                        std::vector<uint64_t> childVarIndices;
+                        if (dft.isGate(i)) {
+                            std::shared_ptr<storm::storage::DFTGate<ValueType> const> gate = dft.getGate(i);
+                            for (auto const& child : gate->children()) {
+                                childVarIndices.push_back(timePointVariables.at(child->id()));
+                            }
+                        }
+                        
+                        std::shared_ptr<storm::storage::DFTElement<ValueType> const> element = dft.getElement(i);
+                        switch (element->type()) {
+                            case storm::storage::DFTElementType::AND:
+                                constraints.push_back(std::make_shared<IsMaximum>(timePointVariables.at(i), childVarIndices));
+                                constraints.back()->setDescription("And gate");
+                                break;
+                            case storm::storage::DFTElementType::OR:
+                                constraints.push_back(std::make_shared<IsMinimum>(timePointVariables.at(i), childVarIndices));
+                                constraints.back()->setDescription("Or gate");
+                                break;
+                            case storm::storage::DFTElementType::PAND:
+                                constraints.push_back(std::make_shared<IfThenElse>(std::make_shared<Sorted>(childVarIndices), std::make_shared<IsEqual>(timePointVariables.at(i), timePointVariables.at(childVarIndices.back())), std::make_shared<IsConstantValue>(timePointVariables.at(i), dft.nrBasicElements()+1)));
+                                constraints.back()->setDescription("Pand gate");
+                            case storm::storage::DFTElementType::SPARE:
+                            {
+                                auto spare = std::static_pointer_cast<storm::storage::DFTSpare<double> const>(element);
+                                auto const& children = spare->children();
+                                
+                                constraints.push_back(std::make_shared<Iff>(std::make_shared<IsLEqual>(getClaimVariableIndex(spare->id(), children.back()->id()), childVarIndices.back()), std::make_shared<IsEqual>(timePointVariables.at(i), childVarIndices.back())));
+                                constraints.back()->setDescription("Last child & claimed -> spare fails");
+                                std::vector<std::shared_ptr<DFTConstraint>> ifcs;
+                                uint64_t xv = childVarIndices.at(childVarIndices.size()-2); // if v is the child, xv is the time x fails.
+                                uint64_t csn = getClaimVariableIndex(spare->id(), children.back()->id()); // csn is the moment the spare claims the next child
+                                uint64_t xn = childVarIndices.back(); // xn is the moment the next child fails
+                                ifcs.push_back(std::make_shared<IsLEqual>(xv, xn));
+                                for(auto const& otherSpare : children.back()->parents()) {
+                                    if(otherSpare->id() == i) { continue; }// not a OTHER spare.
+                                    ifcs.push_back(std::make_shared<IsConstantValue>(getClaimVariableIndex(otherSpare->id(), children.back()->id()), dft.nrBasicElements()+1));
+                                }
+                                std::shared_ptr<DFTConstraint> ite = std::make_shared<IfThenElse>(std::make_shared<And>(ifcs), std::make_shared<IsEqual>(csn, xv), std::make_shared<IsEqual>(timePointVariables.at(i),  xv));
+                                constraints.push_back(std::make_shared<Iff>(std::make_shared<IsLEqual>(getClaimVariableIndex(spare->id(), children.at(children.size()-2)->id()), xv), ite));
+                                constraints.back()->setDescription("1 but last child & claimed");
+                                
+                                for( uint64_t j = 0; j < children.size() - 2; ++j) {
+                                    uint64_t currChild = children.size() - 1 - j;
+                                    
+                                }
+                                break;
+                            }
+                            default:
+                                break;
+                        }
+                    }
+                    
+                    constraints.push_back(std::make_shared<IsConstantValue>(dft.getTopLevelIndex(), dft.nrBasicElements()+1));
+                }
+                
+                void DFTASFChecker::toFile(std::string const& filename) {
+                    std::ofstream ofs;
+                    std::cout << "Writing to " << filename << std::endl;
+                    ofs.open(filename);
+                    ofs << "; time point variables" << std::endl;
+                    for (auto const& timeVarEntry : timePointVariables) {
+                        ofs << "(declare-fun " << varNames[timeVarEntry.second] << "()  Int)" << std::endl;
+                    }
+                    ofs << "; claim variables" << std::endl;
+                    for (auto const& claimVarEntry : claimVariables) {
+                        ofs << "(declare-fun " << varNames[claimVarEntry.second] << "() Int)" << std::endl;
+                    }
+                    for (auto const& constraint : constraints) {
+                        ofs << "; " << constraint->description() << std::endl;
+                        ofs << "(assert " << constraint->toSmtlib2(varNames) << ")" << std::endl;
+                    }
+                    ofs << "(check-sat)" << std::endl;
+                    ofs.close();
+                    
+                }
+    }
+}
\ No newline at end of file
diff --git a/src/modelchecker/dft/DFTASFChecker.h b/src/modelchecker/dft/DFTASFChecker.h
new file mode 100644
index 000000000..73a323b03
--- /dev/null
+++ b/src/modelchecker/dft/DFTASFChecker.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include <string>
+#include <vector>
+#include <unordered_map>
+#include "src/storage/dft/DFT.h"
+
+
+namespace storm {
+    namespace modelchecker {
+        class DFTConstraint {
+        public:
+            virtual ~DFTConstraint() {
+                
+            }
+            
+            virtual  std::string toSmtlib2(std::vector<std::string> const& varNames) const = 0;
+            virtual std::string description() const { return descript; }
+
+            void setDescription(std::string const& descr) {
+                descript = descr;
+            }
+            
+        private:
+            std::string descript;
+        };
+        
+        class SpareAndChildPair {
+            
+        public:
+            SpareAndChildPair(uint64_t spareIndex, uint64_t childIndex) : spareIndex(spareIndex), childIndex(childIndex) {
+                
+            }
+            
+            uint64_t spareIndex;
+            uint64_t childIndex;
+        };
+        
+        bool operator<(SpareAndChildPair const& p1, SpareAndChildPair const& p2) {
+            return p1.spareIndex < p2.spareIndex || (p1.spareIndex == p2.spareIndex && p1.childIndex < p2.childIndex);
+        }
+        
+        class DFTASFChecker {
+            using ValueType = double;
+            
+        public:
+            DFTASFChecker(storm::storage::DFT<ValueType> const&);
+            void convert();
+            void toFile(std::string const&);
+            
+        private:
+            uint64_t getClaimVariableIndex(uint64_t spareIndex, uint64_t childIndex) const;
+            
+            storm::storage::DFT<ValueType> const& dft;
+            std::vector<std::string> varNames;
+            std::unordered_map<uint64_t, uint64_t> timePointVariables;
+            std::vector<std::shared_ptr<DFTConstraint>> constraints;
+            std::map<SpareAndChildPair, uint64_t> claimVariables;
+        };
+    }
+}
\ No newline at end of file
diff --git a/src/storage/dft/DFTBuilder.cpp b/src/storage/dft/DFTBuilder.cpp
index 840f5b77b..55b430863 100644
--- a/src/storage/dft/DFTBuilder.cpp
+++ b/src/storage/dft/DFTBuilder.cpp
@@ -32,7 +32,7 @@ namespace storm {
                         // Child not found -> find first dependent event to assure that child is dependency
                         // TODO: Not sure whether this is the intended behaviour?
                         auto itFind = mElements.find(child + "_1");
-                        STORM_LOG_ASSERT(itFind != mElements.end(), "Child not found.");
+                        STORM_LOG_ASSERT(itFind != mElements.end(), "Child '" << child << "' for gate '" << gate->name() << "' not found.");
                         STORM_LOG_ASSERT(itFind->second->isDependency(), "Child is no dependency.");
                         STORM_LOG_TRACE("Ignore functional dependency " << child << " in gate " << gate->name());
                     }
diff --git a/src/storage/dft/DFTState.cpp b/src/storage/dft/DFTState.cpp
index f6bb692a7..6e2b80035 100644
--- a/src/storage/dft/DFTState.cpp
+++ b/src/storage/dft/DFTState.cpp
@@ -319,7 +319,7 @@ namespace storm {
                         mCurrentlyFailableBE.push_back(elem);
                         // Remove from not failable BEs
                         auto it = std::find(mCurrentlyNotFailableBE.begin(), mCurrentlyNotFailableBE.end(), elem);
-                        STORM_LOG_ASSERT(it != mCurrentlyNotFailableBE.end(), "Element not found.");
+                        STORM_LOG_ASSERT(it != mCurrentlyNotFailableBE.end(), "Element " << mDft.getElement(elem)->name() << " not found.");
                         mCurrentlyNotFailableBE.erase(it);
                     }
                 } else if (mDft.getElement(elem)->isSpareGate() && !isActive(uses(elem))) {
diff --git a/src/storm-dyftee.cpp b/src/storm-dyftee.cpp
index 51061050e..2c7418075 100644
--- a/src/storm-dyftee.cpp
+++ b/src/storm-dyftee.cpp
@@ -3,6 +3,8 @@
 #include "src/utility/storm.h"
 #include "src/parser/DFTGalileoParser.h"
 #include "src/modelchecker/dft/DFTModelChecker.h"
+
+#include "src/modelchecker/dft/DFTASFChecker.h"
 #include "src/cli/cli.h"
 #include "src/exceptions/BaseException.h"
 #include "src/utility/macros.h"
@@ -58,10 +60,11 @@ void analyzeWithSMT(std::string filename) {
     
     storm::parser::DFTGalileoParser<ValueType> parser;
     storm::storage::DFT<ValueType> dft = parser.parseDFT(filename);
-    storm::builder::DFTSMTBuilder<ValueType> dftSmtBuilder;
-    dftSmtBuilder.convertToSMT(dft);
-    bool sat = dftSmtBuilder.check();
-    std::cout << "SMT result: " << sat << std::endl;
+    storm::modelchecker::DFTASFChecker asfChecker(dft);
+    asfChecker.convert();
+    asfChecker.toFile("test.smt2");
+    //bool sat = dftSmtBuilder.check();
+    //std::cout << "SMT result: " << sat << std::endl;
 }
 
 /*!
@@ -120,7 +123,7 @@ int main(const int argc, const char** argv) {
         if (dftSettings.solveWithSMT()) {
             // Solve with SMT
             if (parametric) {
-                analyzeWithSMT<storm::RationalFunction>(dftSettings.getDftFilename());
+            //    analyzeWithSMT<storm::RationalFunction>(dftSettings.getDftFilename());
             } else {
                 analyzeWithSMT<double>(dftSettings.getDftFilename());
             }

From 9947d9b64cc90ffa1368080b2ad98a31572d771c Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Sat, 29 Oct 2016 22:29:26 +0200
Subject: [PATCH 57/65] Add up exploration time

Former-commit-id: f417ecc0214d492e376aab50833dbdb715ad3740
---
 src/modelchecker/dft/DFTModelChecker.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index 5eee17e3e..be5ad6913 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -165,7 +165,7 @@ namespace storm {
                     // TODO Matthias refine model using existing model and MC results
                     builder.buildModel(labeloptions, iteration, approximationError);
                     std::chrono::high_resolution_clock::time_point explorationEnd = std::chrono::high_resolution_clock::now();
-                    explorationTime = explorationEnd - explorationStart;
+                    explorationTime += explorationEnd - explorationStart;
 
                     // TODO Matthias: possible to do bisimulation on approximated model and not on concrete one?
 

From 1c95722711e82a46c78a96996eb92f2584dfc8c3 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Sat, 29 Oct 2016 22:46:20 +0200
Subject: [PATCH 58/65] Do not skip states if approx = 0.0

Former-commit-id: 37dbb9739c95648dcfc91e5e0f85792f28d14afa
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 26 ++++++++++---------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 93a7b282e..c6c584e86 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -143,17 +143,19 @@ namespace storm {
                 initializeNextIteration();
             }
 
-            switch (heuristic) {
-                case storm::builder::ApproximationHeuristic::NONE:
-                    // Do not change anything
-                    approximationThreshold = dft.nrElements()+10;
-                    break;
-                case storm::builder::ApproximationHeuristic::DEPTH:
-                    approximationThreshold = iteration;
-                    break;
-                case storm::builder::ApproximationHeuristic::PROBABILITY:
-                    approximationThreshold = 10 * std::pow(2, iteration);
-                    break;
+            if (approximationThreshold > 0) {
+                switch (heuristic) {
+                    case storm::builder::ApproximationHeuristic::NONE:
+                        // Do not change anything
+                        approximationThreshold = dft.nrElements()+10;
+                        break;
+                    case storm::builder::ApproximationHeuristic::DEPTH:
+                        approximationThreshold = iteration;
+                        break;
+                    case storm::builder::ApproximationHeuristic::PROBABILITY:
+                        approximationThreshold = 10 * std::pow(2, iteration);
+                        break;
+                }
             }
             exploreStateSpace(approximationThreshold);
 
@@ -319,7 +321,7 @@ namespace storm {
                 // Try to explore the next state
                 generator.load(currentState);
 
-                if (nrExpandedStates > approximationThreshold && !currentExplorationHeuristic->isExpand()) {
+                if (approximationThreshold > 0.0 && nrExpandedStates > approximationThreshold && !currentExplorationHeuristic->isExpand()) {
                 //if (currentExplorationHeuristic->isSkip(approximationThreshold)) {
                     // Skip the current state
                     ++nrSkippedStates;

From 875feebdb8b33df83639001d351b5235cf68af05 Mon Sep 17 00:00:00 2001
From: sjunges <sebastian.junges@rwth-aachen.de>
Date: Sun, 30 Oct 2016 01:55:30 +0200
Subject: [PATCH 59/65] modularisation checks for restrictors

Former-commit-id: 6c4eb363cd11f9aa442f823f6cf03c969f0bc72a
---
 src/storage/dft/DFT.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/storage/dft/DFT.cpp b/src/storage/dft/DFT.cpp
index b8024ef56..101f3f962 100644
--- a/src/storage/dft/DFT.cpp
+++ b/src/storage/dft/DFT.cpp
@@ -243,7 +243,7 @@ namespace storm {
             std::map<size_t, std::vector<size_t>> subdfts;
             for(auto const& child : children) {
                 std::vector<size_t> isubdft;
-                if(child->nrParents() > 1 || child->hasOutgoingDependencies()) {
+                if(child->nrParents() > 1 || child->hasOutgoingDependencies() || child->hasRestrictions()) {
                     STORM_LOG_TRACE("child " << child->name() << "does not allow modularisation.");
                     return {*this};
                 }
@@ -696,6 +696,8 @@ namespace storm {
                    // suitable parent gate! - Lets check the independent submodules of the children
                    auto const& children = std::static_pointer_cast<DFTGate<ValueType>>(e)->children();
                    for(auto const& child : children) {
+                       
+                       
                        auto ISD = std::static_pointer_cast<DFTGate<ValueType>>(child)->independentSubDft(true);
                        // In the ISD, check for other children:
                        

From 6fcc97a7b4a7eee22cd94514fd9d4aeb4a9cf046 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Sun, 30 Oct 2016 02:30:39 +0200
Subject: [PATCH 60/65] Implemented modularisation for MTTF via parallel
 composition of CTMCs

Former-commit-id: 552949346b81a4c4def16dc68dd2206e3a993807
---
 src/builder/ParallelCompositionBuilder.cpp | 172 ++++++++++++++++
 src/builder/ParallelCompositionBuilder.h   |  24 +++
 src/modelchecker/dft/DFTModelChecker.cpp   | 218 +++++++++++++++++----
 src/modelchecker/dft/DFTModelChecker.h     |  14 ++
 src/storage/dft/DFT.cpp                    |   2 +-
 src/storm-dyftee.cpp                       |   6 +-
 6 files changed, 392 insertions(+), 44 deletions(-)
 create mode 100644 src/builder/ParallelCompositionBuilder.cpp
 create mode 100644 src/builder/ParallelCompositionBuilder.h

diff --git a/src/builder/ParallelCompositionBuilder.cpp b/src/builder/ParallelCompositionBuilder.cpp
new file mode 100644
index 000000000..5d78d74fa
--- /dev/null
+++ b/src/builder/ParallelCompositionBuilder.cpp
@@ -0,0 +1,172 @@
+#include "src/builder/ParallelCompositionBuilder.h"
+#include "src/models/sparse/StandardRewardModel.h"
+#include <src/utility/constants.h>
+
+namespace storm {
+    namespace builder {
+
+        template<typename ValueType>
+        std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> ParallelCompositionBuilder<ValueType>::compose(std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> const& ctmcA, std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> const& ctmcB, bool labelAnd) {
+            STORM_LOG_TRACE("Parallel composition");
+
+            storm::storage::SparseMatrix<ValueType> matrixA = ctmcA->getTransitionMatrix();
+            storm::storage::SparseMatrix<ValueType> matrixB = ctmcB->getTransitionMatrix();
+            storm::models::sparse::StateLabeling labelingA = ctmcA->getStateLabeling();
+            storm::models::sparse::StateLabeling labelingB = ctmcB->getStateLabeling();
+            size_t sizeA = ctmcA->getNumberOfStates();
+            size_t sizeB = ctmcB->getNumberOfStates();
+            size_t size = sizeA * sizeB;
+            size_t rowIndex = 0;
+
+            // Build matrix
+            storm::storage::SparseMatrixBuilder<ValueType> builder(size, size, 0, true, false, 0);
+
+            for (size_t stateA = 0; stateA < sizeA; ++stateA) {
+                for (size_t stateB = 0; stateB < sizeB; ++stateB) {
+                    STORM_LOG_ASSERT(rowIndex == stateA * sizeB + stateB, "Row " << rowIndex << " is not correct");
+
+                    auto rowA = matrixA.getRow(stateA);
+                    auto itA = rowA.begin();
+                    auto rowB = matrixB.getRow(stateB);
+                    auto itB = rowB.begin();
+
+                    // First consider all target states of A < the current stateA
+                    while (itA != rowA.end() && itA->getColumn() < stateA) {
+                        builder.addNextValue(rowIndex, itA->getColumn() * sizeB + stateB, itA->getValue());
+                        ++itA;
+                    }
+
+                    // Then consider all target states of B
+                    while (itB != rowB.end()) {
+                        builder.addNextValue(rowIndex, stateA * sizeB + itB->getColumn(), itB->getValue());
+                        ++itB;
+                    }
+
+                    // Last consider all remaining target states of A > the current stateA
+                    while (itA != rowA.end()) {
+                        builder.addNextValue(rowIndex, itA->getColumn() * sizeB + stateB, itA->getValue());
+                        ++itA;
+                    }
+
+                    ++rowIndex;
+                }
+            }
+
+            storm::storage::SparseMatrix<ValueType> matrixComposed = builder.build();
+            STORM_LOG_ASSERT(matrixComposed.getRowCount() == size, "Row count is not correct");
+            STORM_LOG_ASSERT(matrixComposed.getColumnCount() == size, "Column count is not correct");
+
+            // Build labeling
+            storm::models::sparse::StateLabeling labeling = storm::models::sparse::StateLabeling(sizeA * sizeB);
+
+            if (labelAnd) {
+                for (std::string const& label : labelingA.getLabels()) {
+                    if (labelingB.containsLabel(label)) {
+                        // Only consider labels contained in both CTMCs
+                        storm::storage::BitVector labelStates(size, false);
+                        for (auto entryA : labelingA.getStates(label)) {
+                            for (auto entryB : labelingB.getStates(label)) {
+                                labelStates.set(entryA * sizeB + entryB);
+                            }
+                        }
+                        labeling.addLabel(label, labelStates);
+                    }
+                }
+            } else {
+                // Set labels from A
+                for (std::string const& label : labelingA.getLabels()) {
+                    if (label == "init") {
+                        // Initial states must be initial in both CTMCs
+                        STORM_LOG_ASSERT(labelingB.containsLabel(label), "B does not have init.");
+                        storm::storage::BitVector labelStates(size, false);
+                        for (auto entryA : labelingA.getStates(label)) {
+                            for (auto entryB : labelingB.getStates(label)) {
+                                labelStates.set(entryA * sizeB + entryB);
+                            }
+                        }
+                        labeling.addLabel(label, labelStates);
+                    } else {
+                        storm::storage::BitVector labelStates(size, false);
+                        for (auto entry : labelingA.getStates(label)) {
+                            for (size_t index = entry * sizeB; index < entry * sizeB + sizeB; ++index) {
+                                labelStates.set(index, true);
+                            }
+                        }
+                        labeling.addLabel(label, labelStates);
+                    }
+                }
+                // Set labels from B
+                for (std::string const& label : labelingB.getLabels()) {
+                    if (label == "init") {
+                        continue;
+                    }
+                    if (labeling.containsLabel(label)) {
+                        // Label is already there from A
+                        for (auto entry : labelingB.getStates(label)) {
+                            for (size_t index = 0; index < sizeA; ++index) {
+                                labeling.addLabelToState(label, index * sizeB + entry);
+                            }
+                        }
+                    } else {
+                        storm::storage::BitVector labelStates(size, false);
+                        for (auto entry : labelingB.getStates(label)) {
+                            for (size_t index = 0; index < sizeA; ++index) {
+                                labelStates.set(index * sizeB + entry, true);
+                            }
+                        }
+                        labeling.addLabel(label, labelStates);
+                    }
+                }
+            }
+
+
+            // Build CTMC
+            std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> composedCtmc = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(matrixComposed, labeling);
+
+            // Print for debugging
+            /*std::cout << "Matrix A:" << std::endl;
+            std::cout << matrixA << std::endl;
+            std::cout << "Matrix B:" << std::endl;
+            std::cout << matrixB << std::endl;
+            std::cout << "Composed matrix: " << std::endl << matrixComposed;
+            std::cout << "Labeling A" << std::endl;
+            labelingA.printLabelingInformationToStream(std::cout);
+            for (size_t stateA = 0; stateA < sizeA; ++stateA) {
+                std::cout << "State " << stateA << ": ";
+                for (auto label : labelingA.getLabelsOfState(stateA)) {
+                    std::cout << label << ", ";
+                }
+                std::cout << std::endl;
+            }
+            std::cout << "Labeling B" << std::endl;
+            labelingB.printLabelingInformationToStream(std::cout);
+            for (size_t stateB = 0; stateB < sizeB; ++stateB) {
+                std::cout << "State " << stateB << ": ";
+                for (auto label : labelingB.getLabelsOfState(stateB)) {
+                    std::cout << label << ", ";
+                }
+                std::cout << std::endl;
+            }
+            std::cout << "Labeling Composed" << std::endl;
+            labeling.printLabelingInformationToStream(std::cout);
+            for (size_t state = 0; state < size; ++state) {
+                std::cout << "State " << state << ": ";
+                for (auto label : labeling.getLabelsOfState(state)) {
+                    std::cout << label << ", ";
+                }
+                std::cout << std::endl;
+            }*/
+
+            return composedCtmc;
+        }
+
+
+        // Explicitly instantiate the class.
+        template class ParallelCompositionBuilder<double>;
+
+#ifdef STORM_HAVE_CARL
+        template class ParallelCompositionBuilder<storm::RationalFunction>;
+#endif
+        
+    } // namespace builder
+} // namespace storm
diff --git a/src/builder/ParallelCompositionBuilder.h b/src/builder/ParallelCompositionBuilder.h
new file mode 100644
index 000000000..3b0fab790
--- /dev/null
+++ b/src/builder/ParallelCompositionBuilder.h
@@ -0,0 +1,24 @@
+#ifndef PARALLELCOMPOSITIONBUILDER_H
+#define	PARALLELCOMPOSITIONBUILDER_H
+
+#include <src/models/sparse/Ctmc.h>
+
+namespace storm {
+    namespace builder {
+
+        /*!
+         * Build a parallel composition of Markov chains.
+         */
+        template<typename ValueType>
+        class ParallelCompositionBuilder {
+
+        public:
+
+            static std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> compose(std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> const& ctmcA, std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> const& ctmcB, bool labelAnd);
+
+        };
+
+    }
+}
+
+#endif	/* EXPLICITDFTMODELBUPARALLELCOMPOSITIONBUILDER_HILDERAPPROX_H */
diff --git a/src/modelchecker/dft/DFTModelChecker.cpp b/src/modelchecker/dft/DFTModelChecker.cpp
index be5ad6913..748abe188 100644
--- a/src/modelchecker/dft/DFTModelChecker.cpp
+++ b/src/modelchecker/dft/DFTModelChecker.cpp
@@ -2,6 +2,7 @@
 
 #include "src/builder/ExplicitDFTModelBuilder.h"
 #include "src/builder/ExplicitDFTModelBuilderApprox.h"
+#include "src/builder/ParallelCompositionBuilder.h"
 #include "src/storage/dft/DFTIsomorphism.h"
 #include "src/settings/modules/DFTSettings.h"
 #include "src/utility/bitoperations.h"
@@ -28,10 +29,19 @@ namespace storm {
             // Optimizing DFT
             storm::storage::DFT<ValueType> dft = origDft.optimize();
 
-            // TODO Matthias: check that all paths reach the target state!
+            // TODO Matthias: check that all paths reach the target state for approximation
 
             // Checking DFT
-            checkResult = checkHelper(dft, formula, symred, allowModularisation, enableDC, approximationError);
+            if (formula->isProbabilityOperatorFormula() || !allowModularisation) {
+                checkResult = checkHelper(dft, formula, symred, allowModularisation, enableDC, approximationError);
+            } else {
+                std::shared_ptr<storm::models::sparse::Model<ValueType>> model = buildModelComposition(dft, formula, symred, allowModularisation, enableDC);
+                // Model checking
+                std::unique_ptr<storm::modelchecker::CheckResult> result = checkModel(model, formula);
+                result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
+                checkResult = result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second;
+
+            }
             this->totalTime = std::chrono::high_resolution_clock::now() - totalStart;
         }
 
@@ -85,45 +95,44 @@ namespace storm {
 
                 if(modularisationPossible) {
                     STORM_LOG_TRACE("Recursive CHECK Call");
-                    // TODO Matthias: enable modularisation for approximation
-                    STORM_LOG_ASSERT(approximationError == 0.0, "Modularisation not possible for approximation.");
-
-                    // Recursively call model checking
-                    std::vector<ValueType> res;
-                    for(auto const ft : dfts) {
-                        dft_result ftResult = checkHelper(ft, formula, symred, true, enableDC, 0.0);
-                        res.push_back(boost::get<ValueType>(ftResult));
-                    }
+                    if (formula->isProbabilityOperatorFormula()) {
+                        // Recursively call model checking
+                        std::vector<ValueType> res;
+                        for(auto const ft : dfts) {
+                            dft_result ftResult = checkHelper(ft, formula, symred, true, enableDC, 0.0);
+                            res.push_back(boost::get<ValueType>(ftResult));
+                        }
 
-                    // Combine modularisation results
-                    STORM_LOG_TRACE("Combining all results... K=" << nrK << "; M=" << nrM << "; invResults=" << (invResults?"On":"Off"));
-                    ValueType result = storm::utility::zero<ValueType>();
-                    int limK = invResults ? -1 : nrM+1;
-                    int chK = invResults ? -1 : 1;
-                    // WARNING: there is a bug for computing permutations with more than 32 elements
-                    STORM_LOG_ASSERT(res.size() < 32, "Permutations work only for < 32 elements");
-                    for(int cK = nrK; cK != limK; cK += chK ) {
-                        STORM_LOG_ASSERT(cK >= 0, "ck negative.");
-                        size_t permutation = smallestIntWithNBitsSet(static_cast<size_t>(cK));
-                        do {
-                            STORM_LOG_TRACE("Permutation="<<permutation);
-                            ValueType permResult = storm::utility::one<ValueType>();
-                            for(size_t i = 0; i < res.size(); ++i) {
-                                if(permutation & (1 << i)) {
-                                    permResult *= res[i];
-                                } else {
-                                    permResult *= storm::utility::one<ValueType>() - res[i];
+                        // Combine modularisation results
+                        STORM_LOG_TRACE("Combining all results... K=" << nrK << "; M=" << nrM << "; invResults=" << (invResults?"On":"Off"));
+                        ValueType result = storm::utility::zero<ValueType>();
+                        int limK = invResults ? -1 : nrM+1;
+                        int chK = invResults ? -1 : 1;
+                        // WARNING: there is a bug for computing permutations with more than 32 elements
+                        STORM_LOG_ASSERT(res.size() < 32, "Permutations work only for < 32 elements");
+                        for(int cK = nrK; cK != limK; cK += chK ) {
+                            STORM_LOG_ASSERT(cK >= 0, "ck negative.");
+                            size_t permutation = smallestIntWithNBitsSet(static_cast<size_t>(cK));
+                            do {
+                                STORM_LOG_TRACE("Permutation="<<permutation);
+                                ValueType permResult = storm::utility::one<ValueType>();
+                                for(size_t i = 0; i < res.size(); ++i) {
+                                    if(permutation & (1 << i)) {
+                                        permResult *= res[i];
+                                    } else {
+                                        permResult *= storm::utility::one<ValueType>() - res[i];
+                                    }
                                 }
-                            }
-                            STORM_LOG_TRACE("Result for permutation:"<<permResult);
-                            permutation = nextBitPermutation(permutation);
-                            result += permResult;
-                        } while(permutation < (1 << nrM) && permutation != 0);
-                    }
-                    if(invResults) {
-                        result = storm::utility::one<ValueType>() - result;
+                                STORM_LOG_TRACE("Result for permutation:"<<permResult);
+                                permutation = nextBitPermutation(permutation);
+                                result += permResult;
+                            } while(permutation < (1 << nrM) && permutation != 0);
+                        }
+                        if(invResults) {
+                            result = storm::utility::one<ValueType>() - result;
+                        }
+                        return result;
                     }
-                    return result;
                 }
             }
 
@@ -132,6 +141,137 @@ namespace storm {
             return checkDFT(dft, formula, symred, enableDC, approximationError);
         }
 
+        template<typename ValueType>
+        std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> DFTModelChecker<ValueType>::buildModelComposition(storm::storage::DFT<ValueType> const& dft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool allowModularisation, bool enableDC)  {
+            STORM_LOG_TRACE("Build model via composition");
+            // Use parallel composition for CTMCs for expected time
+            STORM_LOG_ASSERT(formula->isTimeOperatorFormula(), "Formula is not a time operator formula");
+            bool modularisationPossible = allowModularisation;
+
+            // Try modularisation
+            if(modularisationPossible) {
+                std::vector<storm::storage::DFT<ValueType>> dfts;
+                bool isAnd = true;
+
+                switch (dft.topLevelType()) {
+                    case storm::storage::DFTElementType::AND:
+                        STORM_LOG_TRACE("top modularisation called AND");
+                        dfts = dft.topModularisation();
+                        STORM_LOG_TRACE("Modularisation into " << dfts.size() << " submodules.");
+                        modularisationPossible = dfts.size() > 1;
+                        isAnd = true;
+                        break;
+                    case storm::storage::DFTElementType::OR:
+                        STORM_LOG_TRACE("top modularisation called OR");
+                        dfts = dft.topModularisation();
+                        STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
+                        modularisationPossible = dfts.size() > 1;
+                        isAnd = false;
+                        break;
+                    case storm::storage::DFTElementType::VOT:
+                        /*STORM_LOG_TRACE("top modularisation called VOT");
+                        dfts = dft.topModularisation();
+                        STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
+                        std::static_pointer_cast<storm::storage::DFTVot<ValueType> const>(dft.getTopLevelGate())->threshold();
+                         */
+                        // TODO enable modularisation for voting gate
+                        modularisationPossible = false;
+                        break;
+                    default:
+                        // No static gate -> no modularisation applicable
+                        modularisationPossible = false;
+                        break;
+                }
+
+                if(modularisationPossible) {
+                    STORM_LOG_TRACE("Recursive CHECK Call");
+                    bool firstTime = true;
+                    std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> composedModel;
+                    for (auto const ft : dfts) {
+                        STORM_LOG_INFO("Building Model via parallel composition...");
+                        std::chrono::high_resolution_clock::time_point checkingStart = std::chrono::high_resolution_clock::now();
+
+                        // Find symmetries
+                        std::map<size_t, std::vector<std::vector<size_t>>> emptySymmetry;
+                        storm::storage::DFTIndependentSymmetries symmetries(emptySymmetry);
+                        if(symred) {
+                            auto colouring = ft.colourDFT();
+                            symmetries = ft.findSymmetries(colouring);
+                            STORM_LOG_INFO("Found " << symmetries.groups.size() << " symmetries.");
+                            STORM_LOG_TRACE("Symmetries: " << std::endl << symmetries);
+                        }
+
+                        // Build a single CTMC
+                        STORM_LOG_INFO("Building Model...");
+                        storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(ft, symmetries, enableDC);
+                        typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
+                        builder.buildModel(labeloptions, 0, 0.0);
+                        std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
+                        //model->printModelInformationToStream(std::cout);
+                        STORM_LOG_INFO("No. states (Explored): " << model->getNumberOfStates());
+                        STORM_LOG_INFO("No. transitions (Explored): " << model->getNumberOfTransitions());
+                        explorationTime += std::chrono::high_resolution_clock::now() - checkingStart;
+
+                        STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Ctmc), storm::exceptions::NotSupportedException, "Parallel composition only applicable for CTMCs");
+                        std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> ctmc = model->template as<storm::models::sparse::Ctmc<ValueType>>();
+
+                        ctmc =  storm::performDeterministicSparseBisimulationMinimization<storm::models::sparse::Ctmc<ValueType>>(ctmc, {formula}, storm::storage::BisimulationType::Weak)->template as<storm::models::sparse::Ctmc<ValueType>>();
+
+                        if (firstTime) {
+                            composedModel = ctmc;
+                            firstTime = false;
+                        } else {
+                            composedModel = storm::builder::ParallelCompositionBuilder<ValueType>::compose(composedModel, ctmc, isAnd);
+                        }
+
+                        // Apply bisimulation
+                        std::chrono::high_resolution_clock::time_point bisimulationStart = std::chrono::high_resolution_clock::now();
+                        composedModel =  storm::performDeterministicSparseBisimulationMinimization<storm::models::sparse::Ctmc<ValueType>>(composedModel, {formula}, storm::storage::BisimulationType::Weak)->template as<storm::models::sparse::Ctmc<ValueType>>();
+                        std::chrono::high_resolution_clock::time_point bisimulationEnd = std::chrono::high_resolution_clock::now();
+                        bisimulationTime += bisimulationEnd - bisimulationStart;
+
+                        STORM_LOG_INFO("No. states (Composed): " << composedModel->getNumberOfStates());
+                        STORM_LOG_INFO("No. transitions (Composed): " << composedModel->getNumberOfTransitions());
+                        if (composedModel->getNumberOfStates() <= 15) {
+                            STORM_LOG_TRACE("Transition matrix: " << std::endl << composedModel->getTransitionMatrix());
+                        } else {
+                            STORM_LOG_TRACE("Transition matrix: too big to print");
+                        }
+
+                    }
+                    return composedModel;
+                }
+            }
+
+            // If we are here, no composition was possible
+            STORM_LOG_ASSERT(!modularisationPossible, "Modularisation should not be possible.");
+            std::chrono::high_resolution_clock::time_point checkingStart = std::chrono::high_resolution_clock::now();
+            // Find symmetries
+            std::map<size_t, std::vector<std::vector<size_t>>> emptySymmetry;
+            storm::storage::DFTIndependentSymmetries symmetries(emptySymmetry);
+            if(symred) {
+                auto colouring = dft.colourDFT();
+                symmetries = dft.findSymmetries(colouring);
+                STORM_LOG_INFO("Found " << symmetries.groups.size() << " symmetries.");
+                STORM_LOG_TRACE("Symmetries: " << std::endl << symmetries);
+            }
+            // Build a single CTMC
+            STORM_LOG_INFO("Building Model...");
+
+
+            storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
+            typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
+            builder.buildModel(labeloptions, 0, 0.0);
+            std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
+            //model->printModelInformationToStream(std::cout);
+            STORM_LOG_INFO("No. states (Explored): " << model->getNumberOfStates());
+            STORM_LOG_INFO("No. transitions (Explored): " << model->getNumberOfTransitions());
+            explorationTime += std::chrono::high_resolution_clock::now() - checkingStart;
+            STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Ctmc), storm::exceptions::NotSupportedException, "Parallel composition only applicable for CTMCs");
+
+            return model->template as<storm::models::sparse::Ctmc<ValueType>>();
+        }
+
         template<typename ValueType>
         typename DFTModelChecker<ValueType>::dft_result DFTModelChecker<ValueType>::checkDFT(storm::storage::DFT<ValueType> const& dft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool enableDC, double approximationError) {
             std::chrono::high_resolution_clock::time_point checkingStart = std::chrono::high_resolution_clock::now();
@@ -213,7 +353,7 @@ namespace storm {
                 if (storm::settings::getModule<storm::settings::modules::DFTSettings>().isApproximationErrorSet()) {
                     storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
                     typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
-                    builder.buildModel(labeloptions, 0);
+                    builder.buildModel(labeloptions, 0, 0.0);
                     model = builder.getModel();
                 } else {
                     storm::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries, enableDC);
diff --git a/src/modelchecker/dft/DFTModelChecker.h b/src/modelchecker/dft/DFTModelChecker.h
index 543bf97fd..67deb2af0 100644
--- a/src/modelchecker/dft/DFTModelChecker.h
+++ b/src/modelchecker/dft/DFTModelChecker.h
@@ -83,6 +83,20 @@ namespace storm {
              */
             dft_result checkHelper(storm::storage::DFT<ValueType> const& dft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool allowModularisation, bool enableDC, double approximationError);
 
+            /*!
+             * Internal helper for building a CTMC from a DFT via parallel composition.
+             *
+             * @param dft                 DFT
+             * @param formula             Formula to check for
+             * @param symred              Flag indicating if symmetry reduction should be used
+             * @param allowModularisation Flag indication if modularisation is allowed
+             * @param enableDC            Flag indicating if dont care propagation should be used
+             * @param approximationError  Error allowed for approximation. Value 0 indicates no approximation
+             *
+             * @return CTMC representing the DFT
+             */
+            std::shared_ptr<storm::models::sparse::Ctmc<ValueType>> buildModelComposition(storm::storage::DFT<ValueType> const& dft, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool allowModularisation, bool enableDC);
+
             /*!
              * Check model generated from DFT.
              *
diff --git a/src/storage/dft/DFT.cpp b/src/storage/dft/DFT.cpp
index 101f3f962..88be1df73 100644
--- a/src/storage/dft/DFT.cpp
+++ b/src/storage/dft/DFT.cpp
@@ -244,7 +244,7 @@ namespace storm {
             for(auto const& child : children) {
                 std::vector<size_t> isubdft;
                 if(child->nrParents() > 1 || child->hasOutgoingDependencies() || child->hasRestrictions()) {
-                    STORM_LOG_TRACE("child " << child->name() << "does not allow modularisation.");
+                    STORM_LOG_TRACE("child " << child->name() << " does not allow modularisation.");
                     return {*this};
                 }
                 if (isGate(child->id())) {
diff --git a/src/storm-dyftee.cpp b/src/storm-dyftee.cpp
index 5b040a3b0..05e01c6d1 100644
--- a/src/storm-dyftee.cpp
+++ b/src/storm-dyftee.cpp
@@ -142,7 +142,6 @@ int main(const int argc, const char** argv) {
         
         // Construct pctlFormula
         std::string pctlFormula = "";
-        bool allowModular = true;
         std::string operatorType = "";
         std::string targetFormula = "";
         
@@ -153,7 +152,6 @@ int main(const int argc, const char** argv) {
             STORM_LOG_THROW(!dftSettings.usePropProbability() && !dftSettings.usePropTimebound(), storm::exceptions::InvalidSettingsException, "More than one property given.");
             operatorType = "T";
             targetFormula = "F \"failed\"";
-            allowModular = false;
         } else if (dftSettings.usePropProbability()) {
             STORM_LOG_THROW(!dftSettings.usePropTimebound(), storm::exceptions::InvalidSettingsException, "More than one property given.");
             operatorType = "P";;
@@ -180,9 +178,9 @@ int main(const int argc, const char** argv) {
 
         // From this point on we are ready to carry out the actual computations.
         if (parametric) {
-            analyzeDFT<storm::RationalFunction>(dftSettings.getDftFilename(), pctlFormula, dftSettings.useSymmetryReduction(), allowModular && dftSettings.useModularisation(), !dftSettings.isDisableDC(), approximationError);
+            analyzeDFT<storm::RationalFunction>(dftSettings.getDftFilename(), pctlFormula, dftSettings.useSymmetryReduction(), dftSettings.useModularisation(), !dftSettings.isDisableDC(), approximationError);
         } else {
-            analyzeDFT<double>(dftSettings.getDftFilename(), pctlFormula, dftSettings.useSymmetryReduction(), allowModular && dftSettings.useModularisation(), !dftSettings.isDisableDC(), approximationError);
+            analyzeDFT<double>(dftSettings.getDftFilename(), pctlFormula, dftSettings.useSymmetryReduction(), dftSettings.useModularisation(), !dftSettings.isDisableDC(), approximationError);
         }
         
         // All operations have now been performed, so we clean up everything and terminate.

From cd1aec77503944f42c00558763903479a5f352a1 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Sun, 30 Oct 2016 16:10:00 +0100
Subject: [PATCH 61/65] Heuristic using the difference between upper and lower
 bound

Former-commit-id: a514e33d6947fd25431ddf3b04a6a55984c189fe
---
 src/builder/DftExplorationHeuristic.cpp       | 22 +++++++++++++++-
 src/builder/DftExplorationHeuristic.h         | 11 ++++----
 src/builder/ExplicitDFTModelBuilderApprox.cpp | 25 ++++++++++++++++---
 src/builder/ExplicitDFTModelBuilderApprox.h   |  4 +--
 src/storage/BucketPriorityQueue.cpp           | 11 +++++++-
 src/storage/BucketPriorityQueue.h             |  2 +-
 6 files changed, 60 insertions(+), 15 deletions(-)

diff --git a/src/builder/DftExplorationHeuristic.cpp b/src/builder/DftExplorationHeuristic.cpp
index 40d00115f..527513134 100644
--- a/src/builder/DftExplorationHeuristic.cpp
+++ b/src/builder/DftExplorationHeuristic.cpp
@@ -47,9 +47,29 @@ namespace storm {
             STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work for rational functions.");
         }
 
+        template<>
+        bool DFTExplorationHeuristicBoundDifference<double>::updateHeuristicValues(DFTExplorationHeuristic<double> const& predecessor, double rate, double exitRate) {
+            STORM_LOG_ASSERT(exitRate > 0, "Exit rate is 0");
+            probability += predecessor.getProbability() * rate/exitRate;
+            return true;
+        }
+
+        template<>
+        bool DFTExplorationHeuristicBoundDifference<storm::RationalFunction>::updateHeuristicValues(DFTExplorationHeuristic<storm::RationalFunction> const& predecessor, storm::RationalFunction rate, storm::RationalFunction exitRate) {
+            STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work for rational functions.");
+            return false;
+        }
+
+        template<typename ValueType>
+        void DFTExplorationHeuristicBoundDifference<ValueType>::setBounds(ValueType lowerBound, ValueType upperBound) {
+            this->lowerBound = lowerBound;
+            this->upperBound = upperBound;
+            difference = (storm::utility::one<ValueType>() / upperBound) - (storm::utility::one<ValueType>() / lowerBound);
+        }
+
         template<>
         double DFTExplorationHeuristicBoundDifference<double>::getPriority() const {
-            return upperBound / lowerBound;
+            return probability * difference;
         }
 
         template<>
diff --git a/src/builder/DftExplorationHeuristic.h b/src/builder/DftExplorationHeuristic.h
index 8feb0fefa..44931dfbf 100644
--- a/src/builder/DftExplorationHeuristic.h
+++ b/src/builder/DftExplorationHeuristic.h
@@ -10,7 +10,7 @@ namespace storm {
         /*!
          * Enum representing the heuristic used for deciding which states to expand.
          */
-        enum class ApproximationHeuristic { NONE, DEPTH, PROBABILITY };
+        enum class ApproximationHeuristic { NONE, DEPTH, PROBABILITY, BOUNDDIFFERENCE };
 
 
         /*!
@@ -165,9 +165,9 @@ namespace storm {
                 // Intentionally left empty
             }
 
-            bool updateHeuristicValues(DFTExplorationHeuristic<ValueType> const& predecessor, ValueType rate, ValueType exitRate) override {
-                return false;
-            }
+            void setBounds(ValueType lowerBound, ValueType upperBound);
+
+            bool updateHeuristicValues(DFTExplorationHeuristic<ValueType> const& predecessor, ValueType rate, ValueType exitRate) override;
 
             double getPriority() const override;
 
@@ -180,8 +180,7 @@ namespace storm {
             }
 
         private:
-            ValueType lowerBound;
-            ValueType upperBound;
+            ValueType difference;
         };
 
 
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index c6c584e86..2f302b0db 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -28,7 +28,7 @@ namespace storm {
                 dft(dft),
                 stateGenerationInfo(std::make_shared<storm::storage::DFTStateGenerationInfo>(dft.buildStateGenerationInfo(symmetries))),
                 enableDC(enableDC),
-                heuristic(storm::settings::getModule<storm::settings::modules::DFTSettings>().getApproximationHeuristic()),
+                usedHeuristic(storm::settings::getModule<storm::settings::modules::DFTSettings>().getApproximationHeuristic()),
                 generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates),
                 matrixBuilder(!generator.isDeterministicModel()),
                 stateStorage(((dft.stateVectorSize() / 64) + 1) * 64),
@@ -38,7 +38,7 @@ namespace storm {
         {
             // Intentionally left empty.
             // TODO Matthias: remove again
-            heuristic = storm::builder::ApproximationHeuristic::PROBABILITY;
+            usedHeuristic = storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE;
 
             // Compute independent subtrees
             if (dft.topLevelType() == storm::storage::DFTElementType::OR) {
@@ -144,7 +144,7 @@ namespace storm {
             }
 
             if (approximationThreshold > 0) {
-                switch (heuristic) {
+                switch (usedHeuristic) {
                     case storm::builder::ApproximationHeuristic::NONE:
                         // Do not change anything
                         approximationThreshold = dft.nrElements()+10;
@@ -153,6 +153,7 @@ namespace storm {
                         approximationThreshold = iteration;
                         break;
                     case storm::builder::ApproximationHeuristic::PROBABILITY:
+                    case storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE:
                         approximationThreshold = 10 * std::pow(2, iteration);
                         break;
                 }
@@ -360,6 +361,20 @@ namespace storm {
                                         // Do not skip absorbing state or if reached by dependencies
                                         iter->second.second->markExpand();
                                     }
+                                    if (usedHeuristic == storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE) {
+                                        // Compute bounds for heuristic now
+                                        if (state->isPseudoState()) {
+                                            // Create concrete state from pseudo state
+                                            state->construct();
+                                        }
+                                        STORM_LOG_ASSERT(!currentState->isPseudoState(), "State is pseudo state.");
+
+                                        // Initialize bounds
+                                        ValueType lowerBound = getLowerBound(state);
+                                        ValueType upperBound = getUpperBound(state);
+                                        heuristic->setBounds(lowerBound, upperBound);
+                                    }
+
                                     explorationQueue.push(heuristic);
                                 } else if (!iter->second.second->isExpand()) {
                                     double oldPriority = iter->second.second->getPriority();
@@ -567,9 +582,11 @@ namespace storm {
                 for (size_t i = 0; i < rates.size(); ++i) {
                     // Cold BEs cannot fail in the first step
                     if (!coldBEs.get(i) && rateCount[i] > 0) {
+                        std::iter_swap(rates.begin() + i, rates.end() - 1);
                         // Compute AND MTTF of subtree without current rate and scale with current rate
                         upperBound += rates.back() * rateCount[i] * computeMTTFAnd(rates, rates.size() - 1);
-                        // Swap here to avoid swapping back
+                        // Swap back
+                        // TODO try to avoid swapping back
                         std::iter_swap(rates.begin() + i, rates.end() - 1);
                     }
                 }
diff --git a/src/builder/ExplicitDFTModelBuilderApprox.h b/src/builder/ExplicitDFTModelBuilderApprox.h
index 933cd3277..0e9b9dc57 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.h
+++ b/src/builder/ExplicitDFTModelBuilderApprox.h
@@ -28,7 +28,7 @@ namespace storm {
 
             using DFTStatePointer = std::shared_ptr<storm::storage::DFTState<ValueType>>;
             // TODO Matthias: make choosable
-            using ExplorationHeuristic = DFTExplorationHeuristicProbability<ValueType>;
+            using ExplorationHeuristic = DFTExplorationHeuristicBoundDifference<ValueType>;
             using ExplorationHeuristicPointer = std::shared_ptr<ExplorationHeuristic>;
 
 
@@ -289,7 +289,7 @@ namespace storm {
             const bool mergeFailedStates = true;
 
             // Heuristic used for approximation
-            storm::builder::ApproximationHeuristic heuristic;
+            storm::builder::ApproximationHeuristic usedHeuristic;
 
             // Current id for new state
             size_t newIndex = 0;
diff --git a/src/storage/BucketPriorityQueue.cpp b/src/storage/BucketPriorityQueue.cpp
index 224b14cf6..7870888f0 100644
--- a/src/storage/BucketPriorityQueue.cpp
+++ b/src/storage/BucketPriorityQueue.cpp
@@ -153,7 +153,16 @@ namespace storm {
         template<typename ValueType>
         size_t BucketPriorityQueue<ValueType>::getBucket(double priority) const {
             STORM_LOG_ASSERT(priority >= lowerValue, "Priority " << priority << " is too low");
-            size_t newBucket = std::log(priority - lowerValue) / logBase;
+
+            // For possible values greater 1
+            double tmpBucket = std::log(priority - lowerValue) / logBase;
+            tmpBucket += buckets.size() / 2;
+            if (tmpBucket < 0) {
+                tmpBucket = 0;
+            }
+            size_t newBucket = tmpBucket;
+            // For values ensured to be lower 1
+            //size_t newBucket = std::log(priority - lowerValue) / logBase;
             if (newBucket >= nrBuckets) {
                 newBucket = nrBuckets - 1;
             }
diff --git a/src/storage/BucketPriorityQueue.h b/src/storage/BucketPriorityQueue.h
index 1719c7124..75f065bdc 100644
--- a/src/storage/BucketPriorityQueue.h
+++ b/src/storage/BucketPriorityQueue.h
@@ -13,7 +13,7 @@ namespace storm {
         template<typename ValueType>
         class BucketPriorityQueue {
 
-            using HeuristicPointer = std::shared_ptr<storm::builder::DFTExplorationHeuristicProbability<ValueType>>;
+            using HeuristicPointer = std::shared_ptr<storm::builder::DFTExplorationHeuristicBoundDifference<ValueType>>;
 
         public:
             explicit BucketPriorityQueue(size_t nrBuckets, double lowerValue, double ratio);

From b044b2aca48946fefca0dd769b48d292a001a5e5 Mon Sep 17 00:00:00 2001
From: sjunges <sebastian.junges@rwth-aachen.de>
Date: Sun, 30 Oct 2016 23:02:55 +0100
Subject: [PATCH 62/65] ..

Former-commit-id: c06171dddc48e66053252bc826d468751d3ad2b2
---
 DFTASFChecker.cpp |  9 ---------
 DFTASFChecker.hpp | 14 --------------
 2 files changed, 23 deletions(-)
 delete mode 100644 DFTASFChecker.cpp
 delete mode 100644 DFTASFChecker.hpp

diff --git a/DFTASFChecker.cpp b/DFTASFChecker.cpp
deleted file mode 100644
index de7a59428..000000000
--- a/DFTASFChecker.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-//
-//  DFTASFChecker.cpp
-//  storm
-//
-//  Created by Sebastian Junges on 27/10/16.
-//
-//
-
-#include "DFTASFChecker.hpp"
diff --git a/DFTASFChecker.hpp b/DFTASFChecker.hpp
deleted file mode 100644
index 7920f026a..000000000
--- a/DFTASFChecker.hpp
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  DFTASFChecker.hpp
-//  storm
-//
-//  Created by Sebastian Junges on 27/10/16.
-//
-//
-
-#ifndef DFTASFChecker_hpp
-#define DFTASFChecker_hpp
-
-#include <stdio.h>
-
-#endif /* DFTASFChecker_hpp */

From ee4b6c96a893d608b1cb317ac7e64fbe0df56963 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Thu, 3 Nov 2016 17:58:23 +0100
Subject: [PATCH 63/65] Use operator<< from carl

Former-commit-id: 733c029ebe03f2bbd56323deb62913f1ff2da6d7
---
 src/builder/ExplicitDFTModelBuilderApprox.cpp |  8 ++--
 src/utility/logging.h                         | 10 +++++
 src/utility/vector.cpp                        | 43 -------------------
 src/utility/vector.h                          |  6 ---
 4 files changed, 14 insertions(+), 53 deletions(-)
 delete mode 100644 src/utility/vector.cpp

diff --git a/src/builder/ExplicitDFTModelBuilderApprox.cpp b/src/builder/ExplicitDFTModelBuilderApprox.cpp
index 9d802829b..2f302b0db 100644
--- a/src/builder/ExplicitDFTModelBuilderApprox.cpp
+++ b/src/builder/ExplicitDFTModelBuilderApprox.cpp
@@ -167,10 +167,10 @@ namespace storm {
             // Fix the entries in the transition matrix according to the mapping of ids to row group indices
             STORM_LOG_ASSERT(matrixBuilder.stateRemapping[initialStateIndex] == initialStateIndex, "Initial state should not be remapped.");
             // TODO Matthias: do not consider all rows?
-            //STORM_LOG_TRACE("Remap matrix: " << matrixBuilder.stateRemapping << ", offset: " << matrixBuilder.mappingOffset);
+            STORM_LOG_TRACE("Remap matrix: " << matrixBuilder.stateRemapping << ", offset: " << matrixBuilder.mappingOffset);
             matrixBuilder.remap();
 
-            //STORM_LOG_TRACE("State remapping: " << matrixBuilder.stateRemapping);
+            STORM_LOG_TRACE("State remapping: " << matrixBuilder.stateRemapping);
             STORM_LOG_TRACE("Markovian states: " << modelComponents.markovianStates);
             STORM_LOG_DEBUG("Model has " << stateSize << " states");
             STORM_LOG_DEBUG("Model is " << (generator.isDeterministicModel() ? "deterministic" : "non-deterministic"));
@@ -239,7 +239,7 @@ namespace storm {
                     matrixBuilder.stateRemapping[id] = indexRemapping[index];
                 }
             }
-            //STORM_LOG_TRACE("New state remapping: " << matrixBuilder.stateRemapping);
+            STORM_LOG_TRACE("New state remapping: " << matrixBuilder.stateRemapping);
             std::stringstream ss;
             ss << "Index remapping:" << std::endl;
             for (auto tmp : indexRemapping) {
@@ -477,7 +477,7 @@ namespace storm {
                         modelComponents.exitRates[stateIndex] = storm::utility::zero<ValueType>();
                     }
                 }
-                //STORM_LOG_TRACE("Exit rates: " << modelComponents.exitRates);
+                STORM_LOG_TRACE("Exit rates: " << modelComponents.exitRates);
 
                 std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma;
                 if (copy) {
diff --git a/src/utility/logging.h b/src/utility/logging.h
index 2fc58a008..951935e46 100644
--- a/src/utility/logging.h
+++ b/src/utility/logging.h
@@ -1,6 +1,16 @@
 #ifndef STORM_UTILITY_LOGGING_H_
 #define STORM_UTILITY_LOGGING_H_
 
+// Include config to know whether CARL is available or not.
+#include "storm-config.h"
+#ifdef STORM_HAVE_CARL
+// Load streaming operator from CARL
+#include <carl/io/streamingOperators.h>
+namespace l3pp {
+    using carl::operator<<;
+}
+#endif
+
 #include <l3pp.h>
 
 #if !defined(STORM_LOG_DISABLE_DEBUG) && !defined(STORM_LOG_DISABLE_TRACE)
diff --git a/src/utility/vector.cpp b/src/utility/vector.cpp
deleted file mode 100644
index 595af193e..000000000
--- a/src/utility/vector.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#include "src/utility/vector.h"
-
-// Template was causing problems as Carl has the same function
-/*
-template<typename ValueType>
-std::ostream& operator<<(std::ostream& out, std::vector<ValueType> const& vector) {
-    out << "vector (" << vector.size() << ") [ ";
-    for (uint_fast64_t i = 0; i < vector.size() - 1; ++i) {
-        out << vector[i] << ", ";
-    }
-    out << vector.back();
-    out << " ]";
-    return out;
-}
-
-// Explicitly instantiate functions.
-template std::ostream& operator<<(std::ostream& out, std::vector<double> const& vector);
-template std::ostream& operator<<(std::ostream& out, std::vector<uint_fast64_t> const& vector);
-*/
-
-std::ostream& operator<<(std::ostream& out, std::vector<double> const& vector) {
-    out << "vector (" << vector.size() << ") [ ";
-    for (size_t i = 0; i + 1 < vector.size(); ++i) {
-        out << vector[i] << ", ";
-    }
-    if (!vector.empty()) {
-        out << vector.back();
-    }
-    out << " ]";
-    return out;
-}
-
-std::ostream& operator<<(std::ostream& out, std::vector<uint_fast64_t> const& vector) {
-    out << "vector (" << vector.size() << ") [ ";
-    for (size_t i = 0; i + 1 < vector.size(); ++i) {
-        out << vector[i] << ", ";
-    }
-    if (!vector.empty()) {
-        out << vector.back();
-    }
-    out << " ]";
-    return out;
-}
diff --git a/src/utility/vector.h b/src/utility/vector.h
index 059bf46ac..3257c3516 100644
--- a/src/utility/vector.h
+++ b/src/utility/vector.h
@@ -16,12 +16,6 @@
 #include "src/utility/macros.h"
 #include "src/solver/OptimizationDirection.h"
 
-// Template was causing problems as Carl has the same function
-//template<typename ValueType>
-//std::ostream& operator<<(std::ostream& out, std::vector<ValueType> const& vector);
-std::ostream& operator<<(std::ostream& out, std::vector<double> const& vector);
-std::ostream& operator<<(std::ostream& out, std::vector<uint_fast64_t> const& vector);
-
 namespace storm {
     namespace utility {
         namespace vector {

From 35a76010b7517480361349afbbfadb2ed4490216 Mon Sep 17 00:00:00 2001
From: Mavo <matthias.volk@rwth-aachen.de>
Date: Wed, 9 Nov 2016 10:55:39 +0100
Subject: [PATCH 64/65] Redundant include

Former-commit-id: a6aa6c8dcf2a2e8d2b613618ab40f44c58384b68
---
 src/solver/AbstractEquationSolver.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/solver/AbstractEquationSolver.h b/src/solver/AbstractEquationSolver.h
index 6cc03d56d..491570637 100644
--- a/src/solver/AbstractEquationSolver.h
+++ b/src/solver/AbstractEquationSolver.h
@@ -1,7 +1,6 @@
 #ifndef STORM_SOLVER_ABSTRACTEQUATIONSOLVER_H_
 #define STORM_SOLVER_ABSTRACTEQUATIONSOLVER_H_
 
-#include <memory>
 #include "src/solver/TerminationCondition.h"
 #include <memory>
 

From 4d53dc49301608f68e6e6dc42273943dda9ee299 Mon Sep 17 00:00:00 2001
From: TimQu <tim.quatmann@rwth-aachen.de>
Date: Thu, 3 Nov 2016 14:11:48 +0100
Subject: [PATCH 65/65] Fix in SparseMatrix::swapRows

Former-commit-id: 40e2d890d4517fe8187200a8b71b6a9b462faa1e [formerly f46095e877109a553a1588c8916716c61622e976]
Former-commit-id: 61fcf545cb82952cbfd9b9e1eb04c829fa12e864
---
 src/storage/SparseMatrix.cpp | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/storage/SparseMatrix.cpp b/src/storage/SparseMatrix.cpp
index 401fc4082..1792ae5e9 100644
--- a/src/storage/SparseMatrix.cpp
+++ b/src/storage/SparseMatrix.cpp
@@ -688,6 +688,9 @@ namespace storm {
                         *writeIt = std::move(intermediateRowEntry);
                         ++writeIt;
                     }
+                } else {
+                    // skip the intermediate rows
+                    writeIt = getRow(smallerRow).begin();
                 }
                 
                 // Write the larger row to its new position.
@@ -720,6 +723,9 @@ namespace storm {
                         *writeIt = std::move(*intermediateRowEntryIt);
                         --writeIt;
                     }
+                } else {
+                    // skip the intermediate rows
+                    writeIt = getRow(smallerRow).end() - 1;
                 }
                 
                 // Write the larger row to its new position.