diff --git a/src/modelchecker/csl/helper/HybridCtmcCslHelper.cpp b/src/modelchecker/csl/helper/HybridCtmcCslHelper.cpp index 35e23184c..5f776fdc0 100644 --- a/src/modelchecker/csl/helper/HybridCtmcCslHelper.cpp +++ b/src/modelchecker/csl/helper/HybridCtmcCslHelper.cpp @@ -6,7 +6,6 @@ #include "src/storage/dd/DdManager.h" #include "src/storage/dd/Add.h" #include "src/storage/dd/Bdd.h" -#include "src/storage/dd/cudd/CuddOdd.h" #include "src/utility/macros.h" #include "src/utility/graph.h" @@ -80,7 +79,7 @@ namespace storm { storm::dd::Add<DdType, ValueType> b = (statesWithProbabilityGreater0NonPsi.template toAdd<ValueType>() * rateMatrix * psiStates.swapVariables(model.getRowColumnMetaVariablePairs()).template toAdd<ValueType>()).sumAbstract(model.getColumnVariables()) / model.getManager().getConstant(uniformizationRate); // Create an ODD for the translation to an explicit representation. - storm::dd::Odd<DdType> odd(statesWithProbabilityGreater0NonPsi); + storm::dd::Odd odd = statesWithProbabilityGreater0NonPsi.createOdd(); // Convert the symbolic parts to their explicit representation. storm::storage::SparseMatrix<ValueType> explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); @@ -107,7 +106,7 @@ namespace storm { unboundedResult->filter(SymbolicQualitativeCheckResult<DdType>(model.getReachableStates(), relevantStates)); // Build an ODD for the relevant states. - storm::dd::Odd<DdType> odd(relevantStates); + storm::dd::Odd odd = relevantStates.createOdd(); std::vector<ValueType> result; if (unboundedResult->isHybridQuantitativeCheckResult()) { @@ -146,7 +145,7 @@ namespace storm { storm::dd::Add<DdType, ValueType> b = (statesWithProbabilityGreater0NonPsi.template toAdd<ValueType>() * rateMatrix * psiStates.swapVariables(model.getRowColumnMetaVariablePairs()).template toAdd<ValueType>()).sumAbstract(model.getColumnVariables()) / model.getManager().getConstant(uniformizationRate); // Build an ODD for the relevant states and translate the symbolic parts to their explicit representation. - storm::dd::Odd<DdType> odd = storm::dd::Odd<DdType>(statesWithProbabilityGreater0NonPsi); + storm::dd::Odd odd = statesWithProbabilityGreater0NonPsi.createOdd(); storm::storage::SparseMatrix<ValueType> explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); std::vector<ValueType> explicitB = b.toVector(odd); @@ -166,7 +165,7 @@ namespace storm { hybridResult.filter(SymbolicQualitativeCheckResult<DdType>(model.getReachableStates(), relevantStates)); // Build an ODD for the relevant states. - odd = storm::dd::Odd<DdType>(relevantStates); + odd = relevantStates.createOdd(); std::unique_ptr<CheckResult> explicitResult = hybridResult.toExplicitQuantitativeCheckResult(); std::vector<ValueType> newSubresult = std::move(explicitResult->asExplicitQuantitativeCheckResult<ValueType>().getValueVector()); @@ -179,7 +178,7 @@ namespace storm { // If the lower and upper bounds coincide, we have only determined the relevant states at this // point, but we still need to construct the starting vector. if (lowerBound == upperBound) { - odd = storm::dd::Odd<DdType>(relevantStates); + odd = relevantStates.createOdd(); newSubresult = psiStates.template toAdd<ValueType>().toVector(odd); } @@ -194,7 +193,7 @@ namespace storm { // In this case, the interval is of the form [t, t] with t != 0, t != inf. // Build an ODD for the relevant states. - storm::dd::Odd<DdType> odd = storm::dd::Odd<DdType>(statesWithProbabilityGreater0); + storm::dd::Odd odd = statesWithProbabilityGreater0.createOdd(); std::vector<ValueType> newSubresult = psiStates.template toAdd<ValueType>().toVector(odd); @@ -225,7 +224,7 @@ namespace storm { STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); // Create ODD for the translation. - storm::dd::Odd<DdType> odd(model.getReachableStates()); + storm::dd::Odd odd =model.getReachableStates().createOdd(); // Initialize result to state rewards of the model. std::vector<ValueType> result = rewardModel.getStateRewardVector().toVector(odd); @@ -261,7 +260,7 @@ namespace storm { STORM_LOG_THROW(uniformizationRate > 0, storm::exceptions::InvalidStateException, "The uniformization rate must be positive."); // Create ODD for the translation. - storm::dd::Odd<DdType> odd(model.getReachableStates()); + storm::dd::Odd odd = model.getReachableStates().createOdd(); // Compute the uniformized matrix. storm::dd::Add<DdType, ValueType> uniformizedMatrix = computeUniformizedMatrix(model, rateMatrix, exitRateVector, model.getReachableStates(), uniformizationRate); @@ -281,7 +280,7 @@ namespace storm { storm::dd::Add<DdType, ValueType> probabilityMatrix = computeProbabilityMatrix(model, rateMatrix, exitRateVector); // Create ODD for the translation. - storm::dd::Odd<DdType> odd(model.getReachableStates()); + storm::dd::Odd odd = model.getReachableStates().createOdd(); storm::storage::SparseMatrix<ValueType> explicitProbabilityMatrix = probabilityMatrix.toMatrix(odd, odd); std::vector<ValueType> explicitExitRateVector = exitRateVector.toVector(odd); diff --git a/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp b/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp index 899d090e5..be420f5f5 100644 --- a/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp +++ b/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp @@ -3,7 +3,7 @@ #include "src/modelchecker/prctl/helper/HybridDtmcPrctlHelper.h" #include "src/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h" -#include "src/storage/dd/cudd/CuddOdd.h" +#include "src/storage/dd/Odd.h" #include "src/storage/dd/DdManager.h" #include "src/utility/macros.h" @@ -94,7 +94,7 @@ namespace storm { SymbolicQualitativeCheckResult<DdType> const& subResult = subResultPointer->asSymbolicQualitativeCheckResult<DdType>(); // Create ODD for the translation. - storm::dd::Odd<DdType> odd(this->getModel().getReachableStates()); + storm::dd::Odd odd = this->getModel().getReachableStates().createOdd(); storm::storage::SparseMatrix<ValueType> explicitProbabilityMatrix = this->getModel().getTransitionMatrix().toMatrix(odd, odd); diff --git a/src/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp b/src/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp index 71c858bdc..a30f88898 100644 --- a/src/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp +++ b/src/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp @@ -2,8 +2,6 @@ #include "src/modelchecker/prctl/helper/HybridMdpPrctlHelper.h" -#include "src/storage/dd/cudd/CuddOdd.h" - #include "src/models/symbolic/Mdp.h" #include "src/models/symbolic/StandardRewardModel.h" diff --git a/src/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp b/src/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp index 1263ee82e..757b0992d 100644 --- a/src/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp +++ b/src/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp @@ -6,7 +6,7 @@ #include "src/storage/dd/DdManager.h" #include "src/storage/dd/Add.h" #include "src/storage/dd/Bdd.h" -#include "src/storage/dd/cudd/CuddOdd.h" +#include "src/storage/dd/Odd.h" #include "src/utility/graph.h" #include "src/utility/constants.h" @@ -43,7 +43,7 @@ namespace storm { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd<DdType> odd(maybeStates); + storm::dd::Odd odd = maybeStates.createOdd(); // Create the matrix and the vector for the equation system. storm::dd::Add<DdType, ValueType> maybeStatesAdd = maybeStates.template toAdd<ValueType>(); @@ -98,7 +98,7 @@ namespace storm { // If there are maybe states, we need to perform matrix-vector multiplications. if (!maybeStates.isZero()) { // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd<DdType> odd(maybeStates); + storm::dd::Odd odd = maybeStates.createOdd(); // Create the matrix and the vector for the equation system. storm::dd::Add<DdType, ValueType> maybeStatesAdd = maybeStates.template toAdd<ValueType>(); @@ -139,7 +139,7 @@ namespace storm { STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd<DdType> odd(model.getReachableStates()); + storm::dd::Odd odd = model.getReachableStates().createOdd(); // Create the solution vector (and initialize it to the state rewards of the model). std::vector<ValueType> x = rewardModel.getStateRewardVector().toVector(odd); @@ -164,7 +164,7 @@ namespace storm { storm::dd::Add<DdType> totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix, model.getColumnVariables()); // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd<DdType> odd(model.getReachableStates()); + storm::dd::Odd odd = model.getReachableStates().createOdd(); // Create the solution vector. std::vector<ValueType> x(model.getNumberOfStates(), storm::utility::zero<ValueType>()); @@ -204,7 +204,7 @@ namespace storm { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd<DdType> odd(maybeStates); + storm::dd::Odd odd = maybeStates.createOdd(); // Create the matrix and the vector for the equation system. storm::dd::Add<DdType> maybeStatesAdd = maybeStates.template toAdd<ValueType>(); diff --git a/src/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp b/src/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp index c612998f6..22b104034 100644 --- a/src/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp +++ b/src/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp @@ -3,7 +3,7 @@ #include "src/storage/dd/DdManager.h" #include "src/storage/dd/Add.h" #include "src/storage/dd/Bdd.h" -#include "src/storage/dd/cudd/CuddOdd.h" +#include "src/storage/dd/Odd.h" #include "src/utility/graph.h" #include "src/utility/constants.h" @@ -47,7 +47,7 @@ namespace storm { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd<DdType> odd(maybeStates); + storm::dd::Odd odd = maybeStates.createOdd(); // Create the matrix and the vector for the equation system. storm::dd::Add<DdType, ValueType> maybeStatesAdd = maybeStates.template toAdd<ValueType>(); @@ -107,7 +107,7 @@ namespace storm { // If there are maybe states, we need to perform matrix-vector multiplications. if (!maybeStates.isZero()) { // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd<DdType> odd(maybeStates); + storm::dd::Odd odd = maybeStates.createOdd(); // Create the matrix and the vector for the equation system. storm::dd::Add<DdType, ValueType> maybeStatesAdd = maybeStates.template toAdd<ValueType>(); @@ -149,7 +149,7 @@ namespace storm { STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd<DdType> odd(model.getReachableStates()); + storm::dd::Odd odd =model.getReachableStates().createOdd(); // Translate the symbolic matrix to its explicit representations. storm::storage::SparseMatrix<ValueType> explicitMatrix = transitionMatrix.toMatrix(model.getNondeterminismVariables(), odd, odd); @@ -174,7 +174,7 @@ namespace storm { storm::dd::Add<DdType, ValueType> totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix, model.getColumnVariables()); // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd<DdType> odd(model.getReachableStates()); + storm::dd::Odd odd = model.getReachableStates().createOdd(); // Create the solution vector. std::vector<ValueType> x(model.getNumberOfStates(), storm::utility::zero<ValueType>()); @@ -220,7 +220,7 @@ namespace storm { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd<DdType> odd(maybeStates); + storm::dd::Odd odd = maybeStates.createOdd(); // Create the matrix and the vector for the equation system. storm::dd::Add<DdType, ValueType> maybeStatesAdd = maybeStates.template toAdd<ValueType>(); diff --git a/src/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp b/src/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp index 69092b13b..56530a78b 100644 --- a/src/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp +++ b/src/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp @@ -4,7 +4,6 @@ #include "src/storage/dd/DdManager.h" #include "src/storage/dd/Add.h" #include "src/storage/dd/Bdd.h" -#include "src/storage/dd/cudd/CuddOdd.h" #include "src/solver/SymbolicLinearEquationSolver.h" @@ -38,9 +37,6 @@ namespace storm { } else { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { - // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd<DdType> odd(maybeStates); - // Create the matrix and the vector for the equation system. storm::dd::Add<DdType, ValueType> maybeStatesAdd = maybeStates.template toAdd<ValueType>(); @@ -86,9 +82,6 @@ namespace storm { // If there are maybe states, we need to perform matrix-vector multiplications. if (!maybeStates.isZero()) { - // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd<DdType> odd(maybeStates); - // Create the matrix and the vector for the equation system. storm::dd::Add<DdType, ValueType> maybeStatesAdd = maybeStates.template toAdd<ValueType>(); @@ -159,9 +152,6 @@ namespace storm { } else { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { - // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd<DdType> odd(maybeStates); - // Create the matrix and the vector for the equation system. storm::dd::Add<DdType, ValueType> maybeStatesAdd = maybeStates.template toAdd<ValueType>(); diff --git a/src/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp b/src/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp index c2618fd41..a9ce5d7fb 100644 --- a/src/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp +++ b/src/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp @@ -5,7 +5,6 @@ #include "src/storage/dd/DdManager.h" #include "src/storage/dd/Add.h" #include "src/storage/dd/Bdd.h" -#include "src/storage/dd/cudd/CuddOdd.h" #include "src/utility/graph.h" #include "src/utility/constants.h" diff --git a/src/modelchecker/results/HybridQuantitativeCheckResult.cpp b/src/modelchecker/results/HybridQuantitativeCheckResult.cpp index 2e3d47a72..040379c42 100644 --- a/src/modelchecker/results/HybridQuantitativeCheckResult.cpp +++ b/src/modelchecker/results/HybridQuantitativeCheckResult.cpp @@ -11,7 +11,7 @@ namespace storm { namespace modelchecker { template<storm::dd::DdType Type, typename ValueType> - HybridQuantitativeCheckResult<Type, ValueType>::HybridQuantitativeCheckResult(storm::dd::Bdd<Type> const& reachableStates, storm::dd::Bdd<Type> const& symbolicStates, storm::dd::Add<Type, ValueType> const& symbolicValues, storm::dd::Bdd<Type> const& explicitStates, storm::dd::Odd<Type> const& odd, std::vector<ValueType> const& explicitValues) : reachableStates(reachableStates), symbolicStates(symbolicStates), symbolicValues(symbolicValues), explicitStates(explicitStates), odd(odd), explicitValues(explicitValues) { + HybridQuantitativeCheckResult<Type, ValueType>::HybridQuantitativeCheckResult(storm::dd::Bdd<Type> const& reachableStates, storm::dd::Bdd<Type> const& symbolicStates, storm::dd::Add<Type, ValueType> const& symbolicValues, storm::dd::Bdd<Type> const& explicitStates, storm::dd::Odd const& odd, std::vector<ValueType> const& explicitValues) : reachableStates(reachableStates), symbolicStates(symbolicStates), symbolicValues(symbolicValues), explicitStates(explicitStates), odd(odd), explicitValues(explicitValues) { // Intentionally left empty. } @@ -39,7 +39,7 @@ namespace storm { template<storm::dd::DdType Type, typename ValueType> std::unique_ptr<CheckResult> HybridQuantitativeCheckResult<Type, ValueType>::toExplicitQuantitativeCheckResult() const { storm::dd::Bdd<Type> allStates = symbolicStates || explicitStates; - storm::dd::Odd<Type> allStatesOdd(allStates); + storm::dd::Odd allStatesOdd = allStates.createOdd(); std::vector<ValueType> fullExplicitValues = symbolicValues.toVector(allStatesOdd); this->odd.expandExplicitVector(allStatesOdd, this->explicitValues, fullExplicitValues); @@ -77,7 +77,7 @@ namespace storm { } template<storm::dd::DdType Type, typename ValueType> - storm::dd::Odd<Type> const& HybridQuantitativeCheckResult<Type, ValueType>::getOdd() const { + storm::dd::Odd const& HybridQuantitativeCheckResult<Type, ValueType>::getOdd() const { return odd; } @@ -130,10 +130,10 @@ namespace storm { // Start by computing the new set of states that is stored explictly and the corresponding ODD. this->explicitStates = this->explicitStates && filter.asSymbolicQualitativeCheckResult<Type>().getTruthValuesVector(); - storm::dd::Odd<Type> newOdd(explicitStates); + storm::dd::Odd newOdd = explicitStates.createOdd(); // Then compute the new vector of explicit values and set the new data fields. - this->explicitValues = this->odd.filterExplicitVector(explicitStates, this->explicitValues); + this->explicitValues = explicitStates.filterExplicitVector(this->odd, explicitValues); this->odd = newOdd; } diff --git a/src/modelchecker/results/HybridQuantitativeCheckResult.h b/src/modelchecker/results/HybridQuantitativeCheckResult.h index fa5b0a62c..9e40ae29e 100644 --- a/src/modelchecker/results/HybridQuantitativeCheckResult.h +++ b/src/modelchecker/results/HybridQuantitativeCheckResult.h @@ -4,7 +4,7 @@ #include "src/storage/dd/DdType.h" #include "src/storage/dd/Add.h" #include "src/storage/dd/Bdd.h" -#include "src/storage/dd/cudd/CuddOdd.h" +#include "src/storage/dd/Odd.h" #include "src/modelchecker/results/QuantitativeCheckResult.h" #include "src/utility/OsDetection.h" @@ -14,7 +14,7 @@ namespace storm { class HybridQuantitativeCheckResult : public QuantitativeCheckResult { public: HybridQuantitativeCheckResult() = default; - HybridQuantitativeCheckResult(storm::dd::Bdd<Type> const& reachableStates, storm::dd::Bdd<Type> const& symbolicStates, storm::dd::Add<Type, ValueType> const& symbolicValues, storm::dd::Bdd<Type> const& explicitStates, storm::dd::Odd<Type> const& odd, std::vector<ValueType> const& explicitValues); + HybridQuantitativeCheckResult(storm::dd::Bdd<Type> const& reachableStates, storm::dd::Bdd<Type> const& symbolicStates, storm::dd::Add<Type, ValueType> const& symbolicValues, storm::dd::Bdd<Type> const& explicitStates, storm::dd::Odd const& odd, std::vector<ValueType> const& explicitValues); HybridQuantitativeCheckResult(HybridQuantitativeCheckResult const& other) = default; HybridQuantitativeCheckResult& operator=(HybridQuantitativeCheckResult const& other) = default; @@ -38,7 +38,7 @@ namespace storm { storm::dd::Bdd<Type> const& getExplicitStates() const; - storm::dd::Odd<Type> const& getOdd() const; + storm::dd::Odd const& getOdd() const; std::vector<ValueType> const& getExplicitValueVector() const; @@ -64,7 +64,7 @@ namespace storm { storm::dd::Bdd<Type> explicitStates; // The ODD that enables translation of the explicit values to a symbolic format. - storm::dd::Odd<Type> odd; + storm::dd::Odd odd; // The explicit value vector. std::vector<ValueType> explicitValues; diff --git a/src/storage/dd/Add.cpp b/src/storage/dd/Add.cpp index 22f0f9a29..8120ab953 100644 --- a/src/storage/dd/Add.cpp +++ b/src/storage/dd/Add.cpp @@ -4,7 +4,7 @@ #include "src/storage/dd/DdMetaVariable.h" #include "src/storage/dd/DdManager.h" -#include "src/storage/dd/cudd/CuddOdd.h" +#include "src/storage/dd/Odd.h" #include "src/storage/SparseMatrix.h" @@ -380,11 +380,11 @@ namespace storm { template<DdType LibraryType, typename ValueType> std::vector<ValueType> Add<LibraryType, ValueType>::toVector() const { - return this->toVector(Odd<LibraryType>(*this)); + return this->toVector(this->createOdd()); } template<DdType LibraryType, typename ValueType> - std::vector<ValueType> Add<LibraryType, ValueType>::toVector(Odd<LibraryType> const& rowOdd) const { + std::vector<ValueType> Add<LibraryType, ValueType>::toVector(Odd const& rowOdd) const { std::vector<ValueType> result(rowOdd.getTotalOffset()); std::vector<uint_fast64_t> ddVariableIndices = this->getSortedVariableIndices(); internalAdd.composeWithExplicitVector(rowOdd, ddVariableIndices, result, std::plus<ValueType>()); @@ -392,7 +392,7 @@ namespace storm { } template<DdType LibraryType, typename ValueType> - std::vector<ValueType> Add<LibraryType, ValueType>::toVector(std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd<LibraryType> const& rowOdd, std::vector<uint_fast64_t> const& groupOffsets) const { + std::vector<ValueType> Add<LibraryType, ValueType>::toVector(std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, std::vector<uint_fast64_t> const& groupOffsets) const { std::set<storm::expressions::Variable> rowMetaVariables; // Prepare the proper sets of meta variables. @@ -445,11 +445,11 @@ namespace storm { } } - return toMatrix(rowVariables, columnVariables, Odd<LibraryType>(this->sumAbstract(rowVariables)), Odd<LibraryType>(this->sumAbstract(columnVariables))); + return toMatrix(rowVariables, columnVariables, this->sumAbstract(rowVariables).createOdd(), this->sumAbstract(columnVariables).createOdd()); } template<DdType LibraryType, typename ValueType> - storm::storage::SparseMatrix<ValueType> Add<LibraryType, ValueType>::toMatrix(storm::dd::Odd<LibraryType> const& rowOdd, storm::dd::Odd<LibraryType> const& columnOdd) const { + storm::storage::SparseMatrix<ValueType> Add<LibraryType, ValueType>::toMatrix(storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const { std::set<storm::expressions::Variable> rowMetaVariables; std::set<storm::expressions::Variable> columnMetaVariables; @@ -465,7 +465,7 @@ namespace storm { } template<DdType LibraryType, typename ValueType> - storm::storage::SparseMatrix<ValueType> Add<LibraryType, ValueType>::toMatrix(std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, storm::dd::Odd<LibraryType> const& rowOdd, storm::dd::Odd<LibraryType> const& columnOdd) const { + storm::storage::SparseMatrix<ValueType> Add<LibraryType, ValueType>::toMatrix(std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const { std::vector<uint_fast64_t> ddRowVariableIndices; std::vector<uint_fast64_t> ddColumnVariableIndices; @@ -528,7 +528,7 @@ namespace storm { } template<DdType LibraryType, typename ValueType> - storm::storage::SparseMatrix<ValueType> Add<LibraryType, ValueType>::toMatrix(std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd<LibraryType> const& rowOdd, storm::dd::Odd<LibraryType> const& columnOdd) const { + storm::storage::SparseMatrix<ValueType> Add<LibraryType, ValueType>::toMatrix(std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const { std::set<storm::expressions::Variable> rowMetaVariables; std::set<storm::expressions::Variable> columnMetaVariables; @@ -550,7 +550,7 @@ namespace storm { } template<DdType LibraryType, typename ValueType> - storm::storage::SparseMatrix<ValueType> Add<LibraryType, ValueType>::toMatrix(std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd<LibraryType> const& rowOdd, storm::dd::Odd<LibraryType> const& columnOdd) const { + storm::storage::SparseMatrix<ValueType> Add<LibraryType, ValueType>::toMatrix(std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const { std::vector<uint_fast64_t> ddRowVariableIndices; std::vector<uint_fast64_t> ddColumnVariableIndices; std::vector<uint_fast64_t> ddGroupVariableIndices; @@ -652,7 +652,7 @@ namespace storm { } template<DdType LibraryType, typename ValueType> - std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> Add<LibraryType, ValueType>::toMatrixVector(storm::dd::Add<LibraryType, ValueType> const& vector, std::vector<uint_fast64_t>&& rowGroupSizes, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd<LibraryType> const& rowOdd, storm::dd::Odd<LibraryType> const& columnOdd) const { + std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> Add<LibraryType, ValueType>::toMatrixVector(storm::dd::Add<LibraryType, ValueType> const& vector, std::vector<uint_fast64_t>&& rowGroupSizes, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const { std::set<storm::expressions::Variable> rowMetaVariables; std::set<storm::expressions::Variable> columnMetaVariables; @@ -674,7 +674,7 @@ namespace storm { } template<DdType LibraryType, typename ValueType> - std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> Add<LibraryType, ValueType>::toMatrixVector(storm::dd::Add<LibraryType, ValueType> const& vector, std::vector<uint_fast64_t>&& rowGroupIndices, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd<LibraryType> const& rowOdd, storm::dd::Odd<LibraryType> const& columnOdd) const { + std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> Add<LibraryType, ValueType>::toMatrixVector(storm::dd::Add<LibraryType, ValueType> const& vector, std::vector<uint_fast64_t>&& rowGroupIndices, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const { std::vector<uint_fast64_t> ddRowVariableIndices; std::vector<uint_fast64_t> ddColumnVariableIndices; std::vector<uint_fast64_t> ddGroupVariableIndices; @@ -803,7 +803,7 @@ namespace storm { } template<DdType LibraryType, typename ValueType> - Add<LibraryType, ValueType> Add<LibraryType, ValueType>::fromVector(std::shared_ptr<DdManager<LibraryType> const> ddManager, std::vector<ValueType> const& values, Odd<LibraryType> const& odd, std::set<storm::expressions::Variable> const& metaVariables) { + Add<LibraryType, ValueType> Add<LibraryType, ValueType>::fromVector(std::shared_ptr<DdManager<LibraryType> const> ddManager, std::vector<ValueType> const& values, Odd const& odd, std::set<storm::expressions::Variable> const& metaVariables) { return Add<LibraryType, ValueType>(ddManager, InternalAdd<LibraryType, ValueType>::fromVector(ddManager->getInternalDdManagerPointer(), values, odd, ddManager->getSortedVariableIndices(metaVariables)), metaVariables); } @@ -811,6 +811,11 @@ namespace storm { Bdd<LibraryType> Add<LibraryType, ValueType>::toBdd() const { return Bdd<DdType::CUDD>(this->getDdManager(), internalAdd.toBdd(), this->getContainedMetaVariables()); } + + template<DdType LibraryType, typename ValueType> + Odd Add<LibraryType, ValueType>::createOdd() const { + return internalAdd.createOdd(this->getSortedVariableIndices()); + } template<DdType LibraryType, typename ValueType> Add<LibraryType, ValueType>::operator InternalAdd<LibraryType, ValueType>() const { diff --git a/src/storage/dd/Add.h b/src/storage/dd/Add.h index 295132840..6991a9dd6 100644 --- a/src/storage/dd/Add.h +++ b/src/storage/dd/Add.h @@ -8,15 +8,13 @@ #include "src/storage/dd/cudd/InternalCuddAdd.h" #include "src/storage/dd/cudd/CuddAddIterator.h" +#include "src/storage/dd/Odd.h" namespace storm { namespace dd { template<DdType LibraryType> class Bdd; - template<DdType LibraryType> - class Odd; - template<DdType LibraryType, typename ValueType> class AddIterator; @@ -25,7 +23,6 @@ namespace storm { public: friend class DdManager<LibraryType>; friend class Bdd<LibraryType>; - friend class Odd<LibraryType>; template<DdType LibraryTypePrime, typename ValueTypePrime> friend class Add; @@ -46,7 +43,7 @@ namespace storm { * @param metaVariables The meta variables used for the translation. * @return The resulting (CUDD) ADD. */ - static Add<LibraryType, ValueType> fromVector(std::shared_ptr<DdManager<LibraryType> const> ddManager, std::vector<ValueType> const& values, Odd<LibraryType> const& odd, std::set<storm::expressions::Variable> const& metaVariables); + static Add<LibraryType, ValueType> fromVector(std::shared_ptr<DdManager<LibraryType> const> ddManager, std::vector<ValueType> const& values, Odd const& odd, std::set<storm::expressions::Variable> const& metaVariables); /*! * Retrieves whether the two DDs represent the same function. @@ -525,7 +522,7 @@ namespace storm { * @param rowOdd The ODD used for determining the correct row. * @return The vector that is represented by this ADD. */ - std::vector<ValueType> toVector(storm::dd::Odd<LibraryType> const& rowOdd) const; + std::vector<ValueType> toVector(storm::dd::Odd const& rowOdd) const; /*! * Converts the ADD to a row-grouped vector. The given offset-labeled DD is used to determine the correct @@ -536,7 +533,7 @@ namespace storm { * @param rowOdd The ODD used for determining the correct row. * @return The vector that is represented by this ADD. */ - std::vector<ValueType> toVector(std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd<LibraryType> const& rowOdd, std::vector<uint_fast64_t> const& groupOffsets) const; + std::vector<ValueType> toVector(std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, std::vector<uint_fast64_t> const& groupOffsets) const; /*! * Converts the ADD to a (sparse) double matrix. All contained non-primed variables are assumed to encode the @@ -555,7 +552,7 @@ namespace storm { * @param columnOdd The ODD used for determining the correct column. * @return The matrix that is represented by this ADD. */ - storm::storage::SparseMatrix<ValueType> toMatrix(storm::dd::Odd<LibraryType> const& rowOdd, storm::dd::Odd<LibraryType> const& columnOdd) const; + storm::storage::SparseMatrix<ValueType> toMatrix(storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; /*! * Converts the ADD to a (sparse) double matrix. The given offset-labeled DDs are used to determine the @@ -567,7 +564,7 @@ namespace storm { * @param columnOdd The ODD used for determining the correct column. * @return The matrix that is represented by this ADD. */ - storm::storage::SparseMatrix<ValueType> toMatrix(std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, storm::dd::Odd<LibraryType> const& rowOdd, storm::dd::Odd<LibraryType> const& columnOdd) const; + storm::storage::SparseMatrix<ValueType> toMatrix(std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; /*! * Converts the ADD to a row-grouped (sparse) double matrix. The given offset-labeled DDs are used to @@ -579,7 +576,7 @@ namespace storm { * @param columnOdd The ODD used for determining the correct column. * @return The matrix that is represented by this ADD. */ - storm::storage::SparseMatrix<ValueType> toMatrix(std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd<LibraryType> const& rowOdd, storm::dd::Odd<LibraryType> const& columnOdd) const; + storm::storage::SparseMatrix<ValueType> toMatrix(std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; /*! * Converts the ADD to a row-grouped (sparse) double matrix and the given vector to a row-grouped vector. @@ -594,7 +591,7 @@ namespace storm { * @param columnOdd The ODD used for determining the correct column. * @return The matrix that is represented by this ADD. */ - std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> toMatrixVector(storm::dd::Add<LibraryType, ValueType> const& vector, std::vector<uint_fast64_t>&& rowGroupSizes, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd<LibraryType> const& rowOdd, storm::dd::Odd<LibraryType> const& columnOdd) const; + std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> toMatrixVector(storm::dd::Add<LibraryType, ValueType> const& vector, std::vector<uint_fast64_t>&& rowGroupSizes, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; /*! * Exports the DD to the given file in the dot format. @@ -631,6 +628,13 @@ namespace storm { */ Bdd<LibraryType> toBdd() const; + /*! + * Creates an ODD based on the current ADD. + * + * @return The corresponding ODD. + */ + Odd createOdd() const; + private: /*! * Creates a DD that encapsulates the given CUDD ADD. @@ -660,7 +664,7 @@ namespace storm { * @return The matrix that is represented by this ADD and and a vector corresponding to the symbolic vector * (if it was given). */ - storm::storage::SparseMatrix<ValueType> toMatrix(std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd<LibraryType> const& rowOdd, storm::dd::Odd<LibraryType> const& columnOdd) const; + storm::storage::SparseMatrix<ValueType> toMatrix(std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; /*! * Converts the ADD to a row-grouped (sparse) double matrix and the given vector to an equally row-grouped @@ -678,7 +682,7 @@ namespace storm { * @return The matrix that is represented by this ADD and and a vector corresponding to the symbolic vector * (if it was given). */ - std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> toMatrixVector(storm::dd::Add<LibraryType, ValueType> const& vector, std::vector<uint_fast64_t>&& rowGroupSizes, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd<LibraryType> const& rowOdd, storm::dd::Odd<LibraryType> const& columnOdd) const; + std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> toMatrixVector(storm::dd::Add<LibraryType, ValueType> const& vector, std::vector<uint_fast64_t>&& rowGroupSizes, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; // The internal ADD that depends on the chosen library. InternalAdd<LibraryType, ValueType> internalAdd; diff --git a/src/storage/dd/Bdd.cpp b/src/storage/dd/Bdd.cpp index e199ad58a..49c736e08 100644 --- a/src/storage/dd/Bdd.cpp +++ b/src/storage/dd/Bdd.cpp @@ -6,6 +6,7 @@ #include "src/storage/dd/DdMetaVariable.h" #include "src/storage/dd/DdManager.h" +#include "src/storage/dd/Odd.h" #include "src/storage/BitVector.h" @@ -21,7 +22,7 @@ namespace storm { } template<DdType LibraryType> - Bdd<LibraryType> Bdd<LibraryType>::fromVector(std::shared_ptr<DdManager<LibraryType> const> ddManager, std::vector<double> const& explicitValues, storm::dd::Odd<LibraryType> const& odd, std::set<storm::expressions::Variable> const& metaVariables, storm::logic::ComparisonType comparisonType, double value) { + Bdd<LibraryType> Bdd<LibraryType>::fromVector(std::shared_ptr<DdManager<LibraryType> const> ddManager, std::vector<double> const& explicitValues, storm::dd::Odd const& odd, std::set<storm::expressions::Variable> const& metaVariables, storm::logic::ComparisonType comparisonType, double value) { switch (comparisonType) { case storm::logic::ComparisonType::Less: return fromVector<double>(ddManager, explicitValues, odd, metaVariables, std::bind(std::greater<double>(), value, std::placeholders::_1)); @@ -36,7 +37,7 @@ namespace storm { template<DdType LibraryType> template<typename ValueType> - Bdd<LibraryType> Bdd<LibraryType>::fromVector(std::shared_ptr<DdManager<LibraryType> const> ddManager, std::vector<ValueType> const& values, Odd<LibraryType> const& odd, std::set<storm::expressions::Variable> const& metaVariables, std::function<bool (ValueType const&)> const& filter) { + Bdd<LibraryType> Bdd<LibraryType>::fromVector(std::shared_ptr<DdManager<LibraryType> const> ddManager, std::vector<ValueType> const& values, Odd const& odd, std::set<storm::expressions::Variable> const& metaVariables, std::function<bool (ValueType const&)> const& filter) { return Bdd<LibraryType>(ddManager, InternalBdd<LibraryType>::fromVector(&ddManager->internalDdManager, values, odd, ddManager->getSortedVariableIndices(metaVariables), filter), metaVariables); } @@ -175,7 +176,7 @@ namespace storm { } template<DdType LibraryType> - storm::storage::BitVector Bdd<LibraryType>::toVector(storm::dd::Odd<LibraryType> const& rowOdd) const { + storm::storage::BitVector Bdd<LibraryType>::toVector(storm::dd::Odd const& rowOdd) const { return internalBdd.toVector(rowOdd, this->getSortedVariableIndices()); } @@ -232,6 +233,19 @@ namespace storm { return cube; } + template<DdType LibraryType> + Odd Bdd<LibraryType>::createOdd() const { + return internalBdd.createOdd(this->getSortedVariableIndices()); + } + + template<DdType LibraryType> + template<typename ValueType> + std::vector<ValueType> Bdd<LibraryType>::filterExplicitVector(Odd const& odd, std::vector<ValueType> const& values) const { + std::vector<ValueType> result(this->getNonZeroCount()); + internalBdd.filterExplicitVector(odd, this->getSortedVariableIndices(), values, result); + return result; + } + template<DdType LibraryType> Bdd<LibraryType>::operator InternalBdd<LibraryType>() const { return internalBdd; @@ -239,10 +253,13 @@ namespace storm { template class Bdd<DdType::CUDD>; - template Bdd<DdType::CUDD> Bdd<DdType::CUDD>::fromVector(std::shared_ptr<DdManager<DdType::CUDD> const> ddManager, std::vector<double> const& values, Odd<DdType::CUDD> const& odd, std::set<storm::expressions::Variable> const& metaVariables, std::function<bool (double const&)> const& filter); - template Bdd<DdType::CUDD> Bdd<DdType::CUDD>::fromVector(std::shared_ptr<DdManager<DdType::CUDD> const> ddManager, std::vector<uint_fast64_t> const& values, Odd<DdType::CUDD> const& odd, std::set<storm::expressions::Variable> const& metaVariables, std::function<bool (uint_fast64_t const&)> const& filter); + template Bdd<DdType::CUDD> Bdd<DdType::CUDD>::fromVector(std::shared_ptr<DdManager<DdType::CUDD> const> ddManager, std::vector<double> const& values, Odd const& odd, std::set<storm::expressions::Variable> const& metaVariables, std::function<bool (double const&)> const& filter); + template Bdd<DdType::CUDD> Bdd<DdType::CUDD>::fromVector(std::shared_ptr<DdManager<DdType::CUDD> const> ddManager, std::vector<uint_fast64_t> const& values, Odd const& odd, std::set<storm::expressions::Variable> const& metaVariables, std::function<bool (uint_fast64_t const&)> const& filter); template Add<DdType::CUDD, double> Bdd<DdType::CUDD>::toAdd() const; template Add<DdType::CUDD, uint_fast64_t> Bdd<DdType::CUDD>::toAdd() const; + + template std::vector<double> Bdd<DdType::CUDD>::filterExplicitVector(Odd const& odd, std::vector<double> const& values) const; + template std::vector<uint_fast64_t> Bdd<DdType::CUDD>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& values) const; } } \ No newline at end of file diff --git a/src/storage/dd/Bdd.h b/src/storage/dd/Bdd.h index ecb1028e9..e5c0fe5b3 100644 --- a/src/storage/dd/Bdd.h +++ b/src/storage/dd/Bdd.h @@ -11,7 +11,6 @@ namespace storm { template<DdType LibraryType, typename ValueType> class Add; - template<DdType LibraryType> class Odd; template<DdType LibraryType> @@ -22,8 +21,6 @@ namespace storm { template<DdType LibraryTypePrime, typename ValueTypePrime> friend class Add; - friend class Odd<LibraryType>; - // Instantiate all copy/move constructors/assignments with the default implementation. Bdd() = default; Bdd(Bdd<LibraryType> const& other) = default; @@ -41,7 +38,7 @@ namespace storm { * @param comparisonType The relation that needs to hold for the values (wrt. to the given value). * @param value The value to compare with. */ - static Bdd<LibraryType> fromVector(std::shared_ptr<DdManager<LibraryType> const> ddManager, std::vector<double> const& explicitValues, storm::dd::Odd<LibraryType> const& odd, std::set<storm::expressions::Variable> const& metaVariables, storm::logic::ComparisonType comparisonType, double value); + static Bdd<LibraryType> fromVector(std::shared_ptr<DdManager<LibraryType> const> ddManager, std::vector<double> const& explicitValues, storm::dd::Odd const& odd, std::set<storm::expressions::Variable> const& metaVariables, storm::logic::ComparisonType comparisonType, double value); /*! * Retrieves whether the two BDDs represent the same function. @@ -222,7 +219,7 @@ namespace storm { * @param rowOdd The ODD used for determining the correct row. * @return The bit vector that is represented by this BDD. */ - storm::storage::BitVector toVector(storm::dd::Odd<LibraryType> const& rowOdd) const; + storm::storage::BitVector toVector(storm::dd::Odd const& rowOdd) const; virtual Bdd<LibraryType> getSupport() const override; @@ -244,6 +241,23 @@ namespace storm { */ static Bdd<LibraryType> getCube(DdManager<LibraryType> const& manager, std::set<storm::expressions::Variable> const& metaVariables); + /*! + * Creates an ODD based on the current BDD. + * + * @return The corresponding ODD. + */ + Odd createOdd() const; + + /*! + * Filters the given explicit vector using the symbolic representation of which values to select. + * + * @param selectedValues A symbolic representation of which values to select. + * @param values The value vector from which to select the values. + * @return The resulting vector. + */ + template<typename ValueType> + std::vector<ValueType> filterExplicitVector(Odd const& odd, std::vector<ValueType> const& values) const; + private: /*! * We provide a conversion operator from the BDD to its internal type to ease calling the internal functions. @@ -270,7 +284,7 @@ namespace storm { * @return The resulting (CUDD) BDD. */ template<typename ValueType> - static Bdd<LibraryType> fromVector(std::shared_ptr<DdManager<LibraryType> const> ddManager, std::vector<ValueType> const& values, Odd<LibraryType> const& odd, std::set<storm::expressions::Variable> const& metaVariables, std::function<bool (ValueType const&)> const& filter); + static Bdd<LibraryType> fromVector(std::shared_ptr<DdManager<LibraryType> const> ddManager, std::vector<ValueType> const& values, Odd const& odd, std::set<storm::expressions::Variable> const& metaVariables, std::function<bool (ValueType const&)> const& filter); // The internal BDD that depends on the chosen library. InternalBdd<LibraryType> internalBdd; diff --git a/src/storage/dd/Dd.h b/src/storage/dd/Dd.h index e347f1021..d91989d6a 100644 --- a/src/storage/dd/Dd.h +++ b/src/storage/dd/Dd.h @@ -17,15 +17,11 @@ namespace storm { template<DdType LibraryType> class Bdd; - template<DdType LibraryType> - class Odd; - template<DdType LibraryType> class Dd { public: // Declare the DdManager so it can access the internals of a DD. friend class DdManager<LibraryType>; - friend class Odd<LibraryType>; // Instantiate all copy/move constructors/assignments with the default implementation. Dd() = default; diff --git a/src/storage/dd/DdManager.h b/src/storage/dd/DdManager.h index c6b238905..fa7e5d3ea 100644 --- a/src/storage/dd/DdManager.h +++ b/src/storage/dd/DdManager.h @@ -16,15 +16,11 @@ namespace storm { namespace dd { - template<DdType LibraryType> - class Odd; - // Declare DdManager class so we can then specialize it for the different DD types. template<DdType LibraryType> class DdManager : public std::enable_shared_from_this<DdManager<LibraryType>> { public: friend class Bdd<LibraryType>; - friend class Odd<LibraryType>; template<DdType LibraryTypePrime, typename ValueType> friend class Add; diff --git a/src/storage/dd/Odd.cpp b/src/storage/dd/Odd.cpp index 23e855253..7bf0f18ab 100644 --- a/src/storage/dd/Odd.cpp +++ b/src/storage/dd/Odd.cpp @@ -1 +1,143 @@ -#include "src/storage/dd/Odd.h" \ No newline at end of file +#include "src/storage/dd/Odd.h" + +#include <set> +#include <fstream> +#include <boost/algorithm/string/join.hpp> + +#include "src/utility/macros.h" +#include "src/exceptions/InvalidArgumentException.h" + +namespace storm { + namespace dd { + Odd::Odd(std::shared_ptr<Odd> elseNode, uint_fast64_t elseOffset, std::shared_ptr<Odd> thenNode, uint_fast64_t thenOffset) : elseNode(elseNode), thenNode(thenNode), elseOffset(elseOffset), thenOffset(thenOffset) { + // Intentionally left empty. + } + + Odd const& Odd::getThenSuccessor() const { + return *this->thenNode; + } + + Odd const& Odd::getElseSuccessor() const { + return *this->elseNode; + } + + uint_fast64_t Odd::getElseOffset() const { + return this->elseOffset; + } + + void Odd::setElseOffset(uint_fast64_t newOffset) { + this->elseOffset = newOffset; + } + + uint_fast64_t Odd::getThenOffset() const { + return this->thenOffset; + } + + void Odd::setThenOffset(uint_fast64_t newOffset) { + this->thenOffset = newOffset; + } + + uint_fast64_t Odd::getTotalOffset() const { + return this->elseOffset + this->thenOffset; + } + + uint_fast64_t Odd::getNodeCount() const { + // If the ODD contains a constant (and thus has no children), the size is 1. + if (this->elseNode == nullptr && this->thenNode == nullptr) { + return 1; + } + + // If the two successors are actually the same, we need to count the subnodes only once. + if (this->elseNode == this->thenNode) { + return this->elseNode->getNodeCount(); + } else { + return this->elseNode->getNodeCount() + this->thenNode->getNodeCount(); + } + } + + uint_fast64_t Odd::getHeight() const { + if (this->isTerminalNode()) { + return 1; + } else { + return 1 + this->getElseSuccessor().getHeight(); + } + } + + bool Odd::isTerminalNode() const { + return this->elseNode == nullptr && this->thenNode == nullptr; + } + + void Odd::expandExplicitVector(storm::dd::Odd const& newOdd, std::vector<double> const& oldValues, std::vector<double>& newValues) const { + expandValuesToVectorRec(0, *this, oldValues, 0, newOdd, newValues); + } + + void Odd::expandValuesToVectorRec(uint_fast64_t oldOffset, storm::dd::Odd const& oldOdd, std::vector<double> const& oldValues, uint_fast64_t newOffset, storm::dd::Odd const& newOdd, std::vector<double>& newValues) { + if (oldOdd.isTerminalNode()) { + STORM_LOG_THROW(newOdd.isTerminalNode(), storm::exceptions::InvalidArgumentException, "The ODDs for the translation must have the same height."); + if (oldOdd.getThenOffset() != 0) { + newValues[newOffset] += oldValues[oldOffset]; + } + } else { + expandValuesToVectorRec(oldOffset, oldOdd.getElseSuccessor(), oldValues, newOffset, newOdd.getElseSuccessor(), newValues); + expandValuesToVectorRec(oldOffset + oldOdd.getElseOffset(), oldOdd.getThenSuccessor(), oldValues, newOffset + newOdd.getElseOffset(), newOdd.getThenSuccessor(), newValues); + } + } + + void Odd::exportToDot(std::string const& filename) const { + std::ofstream dotFile; + dotFile.open (filename); + + // Print header. + dotFile << "digraph \"ODD\" {" << std::endl << "center=true;" << std::endl << "edge [dir = none];" << std::endl; + + // Print levels as ranks. + dotFile << "{ node [shape = plaintext];" << std::endl << "edge [style = invis];" << std::endl; + std::vector<std::string> levelNames; + for (uint_fast64_t level = 0; level < this->getHeight(); ++level) { + levelNames.push_back("\"" + std::to_string(level) + "\""); + } + dotFile << boost::join(levelNames, " -> ") << ";"; + dotFile << "}" << std::endl; + + std::map<uint_fast64_t, std::vector<std::reference_wrapper<storm::dd::Odd const>>> levelToOddNodesMap; + this->addToLevelToOddNodesMap(levelToOddNodesMap); + + for (auto const& levelNodes : levelToOddNodesMap) { + dotFile << "{ rank = same; \"" << levelNodes.first << "\"" << std::endl;; + for (auto const& node : levelNodes.second) { + dotFile << "\"" << &node.get() << "\";" << std::endl; + } + dotFile << "}" << std::endl; + } + + std::set<storm::dd::Odd const*> printedNodes; + for (auto const& levelNodes : levelToOddNodesMap) { + for (auto const& node : levelNodes.second) { + if (printedNodes.find(&node.get()) != printedNodes.end()) { + continue; + } else { + printedNodes.insert(&node.get()); + } + + dotFile << "\"" << &node.get() << "\" [label=\"" << levelNodes.first << "\"];" << std::endl; + if (!node.get().isTerminalNode()) { + dotFile << "\"" << &node.get() << "\" -> \"" << &node.get().getElseSuccessor() << "\" [style=dashed, label=\"0\"];" << std::endl; + dotFile << "\"" << &node.get() << "\" -> \"" << &node.get().getThenSuccessor() << "\" [style=solid, label=\"" << node.get().getElseOffset() << "\"];" << std::endl; + } + } + } + + dotFile << "}" << std::endl; + + dotFile.close(); + } + + void Odd::addToLevelToOddNodesMap(std::map<uint_fast64_t, std::vector<std::reference_wrapper<storm::dd::Odd const>>>& levelToOddNodesMap, uint_fast64_t level) const { + levelToOddNodesMap[level].push_back(*this); + if (!this->isTerminalNode()) { + this->getElseSuccessor().addToLevelToOddNodesMap(levelToOddNodesMap, level + 1); + this->getThenSuccessor().addToLevelToOddNodesMap(levelToOddNodesMap, level + 1); + } + } + } +} \ No newline at end of file diff --git a/src/storage/dd/Odd.h b/src/storage/dd/Odd.h index a4c0a62a3..131785adf 100644 --- a/src/storage/dd/Odd.h +++ b/src/storage/dd/Odd.h @@ -1,12 +1,151 @@ #ifndef STORM_STORAGE_DD_ODD_H_ #define STORM_STORAGE_DD_ODD_H_ -#include "src/storage/dd/DdType.h" +#include <vector> +#include <map> namespace storm { namespace dd { - template<DdType Type> - class Odd; + class Odd { + public: + /*! + * Constructs an offset-labeled DD with the given topmost DD node, else- and then-successor. + * + * @param dd The DD node associated with this ODD node. + * @param elseNode The else-successor of thie ODD node. + * @param elseOffset The offset of the else-successor. + * @param thenNode The then-successor of thie ODD node. + * @param thenOffset The offset of the then-successor. + */ + Odd(std::shared_ptr<Odd> elseNode, uint_fast64_t elseOffset, std::shared_ptr<Odd> thenNode, uint_fast64_t thenOffset); + + // Instantiate all copy/move constructors/assignments with the default implementation. + Odd() = default; + Odd(Odd const& other) = default; + Odd& operator=(Odd const& other) = default; +#ifndef WINDOWS + Odd(Odd&& other) = default; + Odd& operator=(Odd&& other) = default; +#endif + + /*! + * Retrieves the then-successor of this ODD node. + * + * @return The then-successor of this ODD node. + */ + Odd const& getThenSuccessor() const; + + /*! + * Retrieves the else-successor of this ODD node. + * + * @return The else-successor of this ODD node. + */ + Odd const& getElseSuccessor() const; + + /*! + * Retrieves the else-offset of this ODD node. + * + * @return The else-offset of this ODD node. + */ + uint_fast64_t getElseOffset() const; + + /*! + * Sets the else-offset of this ODD node. + * + * @param newOffset The new else-offset of this ODD node. + */ + void setElseOffset(uint_fast64_t newOffset); + + /*! + * Retrieves the then-offset of this ODD node. + * + * @return The then-offset of this ODD node. + */ + uint_fast64_t getThenOffset() const; + + /*! + * Sets the then-offset of this ODD node. + * + * @param newOffset The new then-offset of this ODD node. + */ + void setThenOffset(uint_fast64_t newOffset); + + /*! + * Retrieves the total offset, i.e., the sum of the then- and else-offset. + * + * @return The total offset of this ODD. + */ + uint_fast64_t getTotalOffset() const; + + /*! + * Retrieves the size of the ODD. Note: the size is computed by a traversal, so this may be costlier than + * expected. + * + * @return The size (in nodes) of this ODD. + */ + uint_fast64_t getNodeCount() const; + + /*! + * Retrieves the height of the ODD. + * + * @return The height of the ODD. + */ + uint_fast64_t getHeight() const; + + /*! + * Checks whether the given ODD node is a terminal node, i.e. has no successors. + * + * @return True iff the node is terminal. + */ + bool isTerminalNode() const; + + /*! + * Adds the old values to the new values. It does so by writing the old values at their correct positions + * wrt. to the new ODD. + * + * @param newOdd The new ODD to use. + * @param oldValues The old vector of values (which is being read). + * @param newValues The new vector of values (which is being written). + */ + void expandExplicitVector(storm::dd::Odd const& newOdd, std::vector<double> const& oldValues, std::vector<double>& newValues) const; + + /*! + * Exports the ODD in the dot format to the given file. + * + * @param filename The name of the file to which to write the dot output. + */ + void exportToDot(std::string const& filename) const; + + private: + /*! + * Adds all nodes below the current one to the given mapping. + * + * @param levelToOddNodesMap A mapping of the level to the ODD node. + * @param The level of the current node. + */ + void addToLevelToOddNodesMap(std::map<uint_fast64_t, std::vector<std::reference_wrapper<storm::dd::Odd const>>>& levelToOddNodesMap, uint_fast64_t level = 0) const; + + /*! + * Adds the values of the old explicit values to the new explicit values where the positions in the old vector + * are given by the current old ODD and the positions in the new vector are given by the new ODD. + * + * @param oldOffset The offset in the old explicit values. + * @param oldOdd The ODD to use for the old explicit values. + * @param oldValues The vector of old values. + * @param newOffset The offset in the new explicit values. + * @param newOdd The ODD to use for the new explicit values. + * @param newValues The vector of new values. + */ + static void expandValuesToVectorRec(uint_fast64_t oldOffset, storm::dd::Odd const& oldOdd, std::vector<double> const& oldValues, uint_fast64_t newOffset, storm::dd::Odd const& newOdd, std::vector<double>& newValues); + + // The then- and else-nodes. + std::shared_ptr<Odd> elseNode; + std::shared_ptr<Odd> thenNode; + + // The offsets that need to be added if the then- or else-successor is taken, respectively. + uint_fast64_t elseOffset; + uint_fast64_t thenOffset; + }; } } diff --git a/src/storage/dd/cudd/CuddOdd.cpp b/src/storage/dd/cudd/CuddOdd.cpp deleted file mode 100644 index 96e4a339f..000000000 --- a/src/storage/dd/cudd/CuddOdd.cpp +++ /dev/null @@ -1,332 +0,0 @@ -#include "src/storage/dd/cudd/CuddOdd.h" - -#include <fstream> -#include <algorithm> -#include <boost/functional/hash.hpp> -#include <boost/algorithm/string/join.hpp> - -#include "src/exceptions/InvalidArgumentException.h" -#include "src/utility/macros.h" - -#include "src/storage/dd/DdManager.h" -#include "src/storage/dd/DdMetaVariable.h" - -namespace storm { - namespace dd { - template<typename ValueType> - Odd<DdType::CUDD>::Odd(Add<DdType::CUDD, ValueType> const& add) { - std::shared_ptr<DdManager<DdType::CUDD> const> manager = add.getDdManager(); - - // First, we need to determine the involved DD variables indices. - std::vector<uint_fast64_t> ddVariableIndices = add.getSortedVariableIndices(); - - // Prepare a unique table for each level that keeps the constructed ODD nodes unique. - std::vector<std::unordered_map<DdNode*, std::shared_ptr<Odd<DdType::CUDD>>>> uniqueTableForLevels(ddVariableIndices.size() + 1); - - // Now construct the ODD structure from the ADD. - std::shared_ptr<Odd<DdType::CUDD>> rootOdd = buildOddFromAddRec(add.internalAdd.getCuddDdNode(), manager->internalDdManager.getCuddManager(), 0, ddVariableIndices.size(), ddVariableIndices, uniqueTableForLevels); - - // Finally, move the children of the root ODD into this ODD. - this->elseNode = std::move(rootOdd->elseNode); - this->thenNode = std::move(rootOdd->thenNode); - this->elseOffset = rootOdd->elseOffset; - this->thenOffset = rootOdd->thenOffset; - } - - Odd<DdType::CUDD>::Odd(Bdd<DdType::CUDD> const& bdd) { - std::shared_ptr<DdManager<DdType::CUDD> const> manager = bdd.getDdManager(); - - // First, we need to determine the involved DD variables indices. - std::vector<uint_fast64_t> ddVariableIndices = bdd.getSortedVariableIndices(); - - // Prepare a unique table for each level that keeps the constructed ODD nodes unique. - std::vector<std::unordered_map<std::pair<DdNode*, bool>, std::shared_ptr<Odd<DdType::CUDD>>, HashFunctor>> uniqueTableForLevels(ddVariableIndices.size() + 1); - - // Now construct the ODD structure from the BDD. - std::shared_ptr<Odd<DdType::CUDD>> rootOdd = buildOddFromBddRec(Cudd_Regular(bdd.internalBdd.getCuddDdNode()), manager->internalDdManager.getCuddManager(), 0, Cudd_IsComplement(bdd.internalBdd.getCuddDdNode()), ddVariableIndices.size(), ddVariableIndices, uniqueTableForLevels); - - // Finally, move the children of the root ODD into this ODD. - this->elseNode = std::move(rootOdd->elseNode); - this->thenNode = std::move(rootOdd->thenNode); - this->elseOffset = rootOdd->elseOffset; - this->thenOffset = rootOdd->thenOffset; - } - - Odd<DdType::CUDD>::Odd(std::shared_ptr<Odd<DdType::CUDD>> elseNode, uint_fast64_t elseOffset, std::shared_ptr<Odd<DdType::CUDD>> thenNode, uint_fast64_t thenOffset) : elseNode(elseNode), thenNode(thenNode), elseOffset(elseOffset), thenOffset(thenOffset) { - // Intentionally left empty. - } - - Odd<DdType::CUDD> const& Odd<DdType::CUDD>::getThenSuccessor() const { - return *this->thenNode; - } - - Odd<DdType::CUDD> const& Odd<DdType::CUDD>::getElseSuccessor() const { - return *this->elseNode; - } - - uint_fast64_t Odd<DdType::CUDD>::getElseOffset() const { - return this->elseOffset; - } - - void Odd<DdType::CUDD>::setElseOffset(uint_fast64_t newOffset) { - this->elseOffset = newOffset; - } - - uint_fast64_t Odd<DdType::CUDD>::getThenOffset() const { - return this->thenOffset; - } - - void Odd<DdType::CUDD>::setThenOffset(uint_fast64_t newOffset) { - this->thenOffset = newOffset; - } - - uint_fast64_t Odd<DdType::CUDD>::getTotalOffset() const { - return this->elseOffset + this->thenOffset; - } - - uint_fast64_t Odd<DdType::CUDD>::getNodeCount() const { - // If the ODD contains a constant (and thus has no children), the size is 1. - if (this->elseNode == nullptr && this->thenNode == nullptr) { - return 1; - } - - // If the two successors are actually the same, we need to count the subnodes only once. - if (this->elseNode == this->thenNode) { - return this->elseNode->getNodeCount(); - } else { - return this->elseNode->getNodeCount() + this->thenNode->getNodeCount(); - } - } - - uint_fast64_t Odd<DdType::CUDD>::getHeight() const { - if (this->isTerminalNode()) { - return 1; - } else { - return 1 + this->getElseSuccessor().getHeight(); - } - } - - bool Odd<DdType::CUDD>::isTerminalNode() const { - return this->elseNode == nullptr && this->thenNode == nullptr; - } - - std::vector<double> Odd<DdType::CUDD>::filterExplicitVector(storm::dd::Bdd<DdType::CUDD> const& selectedValues, std::vector<double> const& values) const { - std::vector<double> result(selectedValues.getNonZeroCount()); - - // First, we need to determine the involved DD variables indices. - std::vector<uint_fast64_t> ddVariableIndices = selectedValues.getSortedVariableIndices(); - - uint_fast64_t currentIndex = 0; - addSelectedValuesToVectorRec(selectedValues.internalBdd.getCuddDdNode(), selectedValues.getDdManager()->internalDdManager.getCuddManager(), 0, Cudd_IsComplement(selectedValues.internalBdd.getCuddDdNode()), ddVariableIndices.size(), ddVariableIndices, 0, *this, result, currentIndex, values); - return result; - } - - void Odd<DdType::CUDD>::expandExplicitVector(storm::dd::Odd<DdType::CUDD> const& newOdd, std::vector<double> const& oldValues, std::vector<double>& newValues) const { - expandValuesToVectorRec(0, *this, oldValues, 0, newOdd, newValues); - } - - void Odd<DdType::CUDD>::expandValuesToVectorRec(uint_fast64_t oldOffset, storm::dd::Odd<DdType::CUDD> const& oldOdd, std::vector<double> const& oldValues, uint_fast64_t newOffset, storm::dd::Odd<DdType::CUDD> const& newOdd, std::vector<double>& newValues) { - if (oldOdd.isTerminalNode()) { - STORM_LOG_THROW(newOdd.isTerminalNode(), storm::exceptions::InvalidArgumentException, "The ODDs for the translation must have the same height."); - if (oldOdd.getThenOffset() != 0) { - newValues[newOffset] += oldValues[oldOffset]; - } - } else { - expandValuesToVectorRec(oldOffset, oldOdd.getElseSuccessor(), oldValues, newOffset, newOdd.getElseSuccessor(), newValues); - expandValuesToVectorRec(oldOffset + oldOdd.getElseOffset(), oldOdd.getThenSuccessor(), oldValues, newOffset + newOdd.getElseOffset(), newOdd.getThenSuccessor(), newValues); - } - } - - void Odd<DdType::CUDD>::addSelectedValuesToVectorRec(DdNode* dd, Cudd const& manager, uint_fast64_t currentLevel, bool complement, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices, uint_fast64_t currentOffset, storm::dd::Odd<DdType::CUDD> const& odd, std::vector<double>& result, uint_fast64_t& currentIndex, std::vector<double> const& values) { - // If there are no more values to select, we can directly return. - if (dd == Cudd_ReadLogicZero(manager.getManager()) && !complement) { - return; - } else if (dd == Cudd_ReadOne(manager.getManager()) && complement) { - return; - } - - if (currentLevel == maxLevel) { - // If the DD is not the zero leaf, then the then-offset is 1. - bool selected = false; - if (dd != Cudd_ReadLogicZero(manager.getManager())) { - selected = !complement; - } - - if (selected) { - result[currentIndex++] = values[currentOffset]; - } - } else if (ddVariableIndices[currentLevel] < dd->index) { - // If we skipped a level, we need to enumerate the explicit entries for the case in which the bit is set - // and for the one in which it is not set. - addSelectedValuesToVectorRec(dd, manager, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset, odd.getElseSuccessor(), result, currentIndex, values); - addSelectedValuesToVectorRec(dd, manager, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), result, currentIndex, values); - } else { - // Otherwise, we compute the ODDs for both the then- and else successors. - DdNode* thenDdNode = Cudd_T(dd); - DdNode* elseDdNode = Cudd_E(dd); - - // Determine whether we have to evaluate the successors as if they were complemented. - bool elseComplemented = Cudd_IsComplement(elseDdNode) ^ complement; - bool thenComplemented = Cudd_IsComplement(thenDdNode) ^ complement; - - addSelectedValuesToVectorRec(Cudd_Regular(elseDdNode), manager, currentLevel + 1, elseComplemented, maxLevel, ddVariableIndices, currentOffset, odd.getElseSuccessor(), result, currentIndex, values); - addSelectedValuesToVectorRec(Cudd_Regular(thenDdNode), manager, currentLevel + 1, thenComplemented, maxLevel, ddVariableIndices, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), result, currentIndex, values); - } - } - - void Odd<DdType::CUDD>::exportToDot(std::string const& filename) const { - std::ofstream dotFile; - dotFile.open (filename); - - // Print header. - dotFile << "digraph \"ODD\" {" << std::endl << "center=true;" << std::endl << "edge [dir = none];" << std::endl; - - // Print levels as ranks. - dotFile << "{ node [shape = plaintext];" << std::endl << "edge [style = invis];" << std::endl; - std::vector<std::string> levelNames; - for (uint_fast64_t level = 0; level < this->getHeight(); ++level) { - levelNames.push_back("\"" + std::to_string(level) + "\""); - } - dotFile << boost::join(levelNames, " -> ") << ";"; - dotFile << "}" << std::endl; - - std::map<uint_fast64_t, std::vector<std::reference_wrapper<storm::dd::Odd<DdType::CUDD> const>>> levelToOddNodesMap; - this->addToLevelToOddNodesMap(levelToOddNodesMap); - - for (auto const& levelNodes : levelToOddNodesMap) { - dotFile << "{ rank = same; \"" << levelNodes.first << "\"" << std::endl;; - for (auto const& node : levelNodes.second) { - dotFile << "\"" << &node.get() << "\";" << std::endl; - } - dotFile << "}" << std::endl; - } - - std::set<storm::dd::Odd<DdType::CUDD> const*> printedNodes; - for (auto const& levelNodes : levelToOddNodesMap) { - for (auto const& node : levelNodes.second) { - if (printedNodes.find(&node.get()) != printedNodes.end()) { - continue; - } else { - printedNodes.insert(&node.get()); - } - - dotFile << "\"" << &node.get() << "\" [label=\"" << levelNodes.first << "\"];" << std::endl; - if (!node.get().isTerminalNode()) { - dotFile << "\"" << &node.get() << "\" -> \"" << &node.get().getElseSuccessor() << "\" [style=dashed, label=\"0\"];" << std::endl; - dotFile << "\"" << &node.get() << "\" -> \"" << &node.get().getThenSuccessor() << "\" [style=solid, label=\"" << node.get().getElseOffset() << "\"];" << std::endl; - } - } - } - - dotFile << "}" << std::endl; - - dotFile.close(); - } - - void Odd<DdType::CUDD>::addToLevelToOddNodesMap(std::map<uint_fast64_t, std::vector<std::reference_wrapper<storm::dd::Odd<DdType::CUDD> const>>>& levelToOddNodesMap, uint_fast64_t level) const { - levelToOddNodesMap[level].push_back(*this); - if (!this->isTerminalNode()) { - this->getElseSuccessor().addToLevelToOddNodesMap(levelToOddNodesMap, level + 1); - this->getThenSuccessor().addToLevelToOddNodesMap(levelToOddNodesMap, level + 1); - } - } - - std::shared_ptr<Odd<DdType::CUDD>> Odd<DdType::CUDD>::buildOddFromAddRec(DdNode* dd, Cudd const& manager, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<std::unordered_map<DdNode*, std::shared_ptr<Odd<DdType::CUDD>>>>& uniqueTableForLevels) { - // Check whether the ODD for this node has already been computed (for this level) and if so, return this instead. - auto const& iterator = uniqueTableForLevels[currentLevel].find(dd); - if (iterator != uniqueTableForLevels[currentLevel].end()) { - return iterator->second; - } else { - // Otherwise, we need to recursively compute the ODD. - - // If we are already past the maximal level that is to be considered, we can simply create an Odd without - // successors - if (currentLevel == maxLevel) { - uint_fast64_t elseOffset = 0; - uint_fast64_t thenOffset = 0; - - // If the DD is not the zero leaf, then the then-offset is 1. - if (dd != Cudd_ReadZero(manager.getManager())) { - thenOffset = 1; - } - - return std::shared_ptr<Odd<DdType::CUDD>>(new Odd<DdType::CUDD>(nullptr, elseOffset, nullptr, thenOffset)); - } else if (ddVariableIndices[currentLevel] < static_cast<uint_fast64_t>(dd->index)) { - // If we skipped the level in the DD, we compute the ODD just for the else-successor and use the same - // node for the then-successor as well. - std::shared_ptr<Odd<DdType::CUDD>> elseNode = buildOddFromAddRec(dd, manager, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels); - std::shared_ptr<Odd<DdType::CUDD>> thenNode = elseNode; - return std::shared_ptr<Odd<DdType::CUDD>>(new Odd<DdType::CUDD>(elseNode, elseNode->getElseOffset() + elseNode->getThenOffset(), thenNode, thenNode->getElseOffset() + thenNode->getThenOffset())); - } else { - // Otherwise, we compute the ODDs for both the then- and else successors. - bool elseComplemented = Cudd_IsComplement(Cudd_E(dd)); - bool thenComplemented = Cudd_IsComplement(Cudd_T(dd)); - std::shared_ptr<Odd<DdType::CUDD>> elseNode = buildOddFromAddRec(Cudd_E(dd), manager, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels); - std::shared_ptr<Odd<DdType::CUDD>> thenNode = buildOddFromAddRec(Cudd_T(dd), manager, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels); - uint_fast64_t totalElseOffset = elseNode->getElseOffset() + elseNode->getThenOffset(); - uint_fast64_t totalThenOffset = thenNode->getElseOffset() + thenNode->getThenOffset(); - return std::shared_ptr<Odd<DdType::CUDD>>(new Odd<DdType::CUDD>(elseNode, elseComplemented ? (1ull << (maxLevel - currentLevel - 1)) - totalElseOffset : totalElseOffset, thenNode, thenComplemented ? (1ull << (maxLevel - currentLevel - 1)) - totalThenOffset : totalThenOffset)); - } - } - } - - std::size_t Odd<DdType::CUDD>::HashFunctor::operator()(std::pair<DdNode*, bool> const& key) const { - std::size_t result = 0; - boost::hash_combine(result, key.first); - boost::hash_combine(result, key.second); - return result; - } - - std::shared_ptr<Odd<DdType::CUDD>> Odd<DdType::CUDD>::buildOddFromBddRec(DdNode* dd, Cudd const& manager, uint_fast64_t currentLevel, bool complement, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<std::unordered_map<std::pair<DdNode*, bool>, std::shared_ptr<Odd<DdType::CUDD>>, HashFunctor>>& uniqueTableForLevels) { - // Check whether the ODD for this node has already been computed (for this level) and if so, return this instead. - auto const& iterator = uniqueTableForLevels[currentLevel].find(std::make_pair(dd, complement)); - if (iterator != uniqueTableForLevels[currentLevel].end()) { - return iterator->second; - } else { - // Otherwise, we need to recursively compute the ODD. - - // If we are already past the maximal level that is to be considered, we can simply create an Odd without - // successors - if (currentLevel == maxLevel) { - uint_fast64_t elseOffset = 0; - uint_fast64_t thenOffset = 0; - - // If the DD is not the zero leaf, then the then-offset is 1. - if (dd != Cudd_ReadZero(manager.getManager())) { - thenOffset = 1; - } - - // If we need to complement the 'terminal' node, we need to negate its offset. - if (complement) { - thenOffset = 1 - thenOffset; - } - - return std::shared_ptr<Odd<DdType::CUDD>>(new Odd<DdType::CUDD>(nullptr, elseOffset, nullptr, thenOffset)); - } else if (ddVariableIndices[currentLevel] < static_cast<uint_fast64_t>(dd->index)) { - // If we skipped the level in the DD, we compute the ODD just for the else-successor and use the same - // node for the then-successor as well. - std::shared_ptr<Odd<DdType::CUDD>> elseNode = buildOddFromBddRec(dd, manager, currentLevel + 1, complement, maxLevel, ddVariableIndices, uniqueTableForLevels); - std::shared_ptr<Odd<DdType::CUDD>> thenNode = elseNode; - uint_fast64_t totalOffset = elseNode->getElseOffset() + elseNode->getThenOffset(); - return std::shared_ptr<Odd<DdType::CUDD>>(new Odd<DdType::CUDD>(elseNode, totalOffset, thenNode, totalOffset)); - } else { - // Otherwise, we compute the ODDs for both the then- and else successors. - DdNode* thenDdNode = Cudd_T(dd); - DdNode* elseDdNode = Cudd_E(dd); - - // Determine whether we have to evaluate the successors as if they were complemented. - bool elseComplemented = Cudd_IsComplement(elseDdNode) ^ complement; - bool thenComplemented = Cudd_IsComplement(thenDdNode) ^ complement; - - std::shared_ptr<Odd<DdType::CUDD>> elseNode = buildOddFromBddRec(Cudd_Regular(elseDdNode), manager, currentLevel + 1, elseComplemented, maxLevel, ddVariableIndices, uniqueTableForLevels); - std::shared_ptr<Odd<DdType::CUDD>> thenNode = buildOddFromBddRec(Cudd_Regular(thenDdNode), manager, currentLevel + 1, thenComplemented, maxLevel, ddVariableIndices, uniqueTableForLevels); - - return std::shared_ptr<Odd<DdType::CUDD>>(new Odd<DdType::CUDD>(elseNode, elseNode->getElseOffset() + elseNode->getThenOffset(), thenNode, thenNode->getElseOffset() + thenNode->getThenOffset())); - } - } - } - - template Odd<DdType::CUDD>::Odd(Add<DdType::CUDD, double> const& add); - template Odd<DdType::CUDD>::Odd(Add<DdType::CUDD, uint_fast64_t> const& add); - } -} \ No newline at end of file diff --git a/src/storage/dd/cudd/CuddOdd.h b/src/storage/dd/cudd/CuddOdd.h deleted file mode 100644 index 79be50332..000000000 --- a/src/storage/dd/cudd/CuddOdd.h +++ /dev/null @@ -1,235 +0,0 @@ -#ifndef STORM_STORAGE_DD_CUDDODD_H_ -#define STORM_STORAGE_DD_CUDDODD_H_ - -#include <memory> -#include <unordered_map> - -#include "src/storage/dd/Odd.h" -#include "src/storage/dd/Add.h" -#include "src/utility/OsDetection.h" - -// Include the C++-interface of CUDD. -#include "cuddObj.hh" - -namespace storm { - namespace dd { - template<> - class Odd<DdType::CUDD> { - public: - /*! - * Constructs an offset-labeled DD from the given ADD. - * - * @param add The ADD for which to build the offset-labeled ADD. - */ - template<typename ValueType> - Odd(Add<DdType::CUDD, ValueType> const& add); - - /*! - * Constructs an offset-labeled DD from the given BDD. - * - * @param bdd The BDD for which to build the offset-labeled ADD. - */ - Odd(Bdd<DdType::CUDD> const& bdd); - - // Instantiate all copy/move constructors/assignments with the default implementation. - Odd() = default; - Odd(Odd<DdType::CUDD> const& other) = default; - Odd& operator=(Odd<DdType::CUDD> const& other) = default; -#ifndef WINDOWS - Odd(Odd<DdType::CUDD>&& other) = default; - Odd& operator=(Odd<DdType::CUDD>&& other) = default; -#endif - - /*! - * Retrieves the then-successor of this ODD node. - * - * @return The then-successor of this ODD node. - */ - Odd<DdType::CUDD> const& getThenSuccessor() const; - - /*! - * Retrieves the else-successor of this ODD node. - * - * @return The else-successor of this ODD node. - */ - Odd<DdType::CUDD> const& getElseSuccessor() const; - - /*! - * Retrieves the else-offset of this ODD node. - * - * @return The else-offset of this ODD node. - */ - uint_fast64_t getElseOffset() const; - - /*! - * Sets the else-offset of this ODD node. - * - * @param newOffset The new else-offset of this ODD node. - */ - void setElseOffset(uint_fast64_t newOffset); - - /*! - * Retrieves the then-offset of this ODD node. - * - * @return The then-offset of this ODD node. - */ - uint_fast64_t getThenOffset() const; - - /*! - * Sets the then-offset of this ODD node. - * - * @param newOffset The new then-offset of this ODD node. - */ - void setThenOffset(uint_fast64_t newOffset); - - /*! - * Retrieves the total offset, i.e., the sum of the then- and else-offset. - * - * @return The total offset of this ODD. - */ - uint_fast64_t getTotalOffset() const; - - /*! - * Retrieves the size of the ODD. Note: the size is computed by a traversal, so this may be costlier than - * expected. - * - * @return The size (in nodes) of this ODD. - */ - uint_fast64_t getNodeCount() const; - - /*! - * Retrieves the height of the ODD. - * - * @return The height of the ODD. - */ - uint_fast64_t getHeight() const; - - /*! - * Checks whether the given ODD node is a terminal node, i.e. has no successors. - * - * @return True iff the node is terminal. - */ - bool isTerminalNode() const; - - /*! - * Filters the given explicit vector using the symbolic representation of which values to select. - * - * @param selectedValues A symbolic representation of which values to select. - * @param values The value vector from which to select the values. - * @return The resulting vector. - */ - std::vector<double> filterExplicitVector(storm::dd::Bdd<DdType::CUDD> const& selectedValues, std::vector<double> const& values) const; - - /*! - * Adds the old values to the new values. It does so by writing the old values at their correct positions - * wrt. to the new ODD. - * - * @param newOdd The new ODD to use. - * @param oldValues The old vector of values (which is being read). - * @param newValues The new vector of values (which is being written). - */ - void expandExplicitVector(storm::dd::Odd<DdType::CUDD> const& newOdd, std::vector<double> const& oldValues, std::vector<double>& newValues) const; - - /*! - * Exports the ODD in the dot format to the given file. - * - * @param filename The name of the file to which to write the dot output. - */ - void exportToDot(std::string const& filename) const; - - private: - // Declare a hash functor that is used for the unique tables in the construction process. - class HashFunctor { - public: - std::size_t operator()(std::pair<DdNode*, bool> const& key) const; - }; - - /*! - * Adds all nodes below the current one to the given mapping. - * - * @param levelToOddNodesMap A mapping of the level to the ODD node. - * @param The level of the current node. - */ - void addToLevelToOddNodesMap(std::map<uint_fast64_t, std::vector<std::reference_wrapper<storm::dd::Odd<DdType::CUDD> const>>>& levelToOddNodesMap, uint_fast64_t level = 0) const; - - /*! - * Constructs an offset-labeled DD with the given topmost DD node, else- and then-successor. - * - * @param dd The DD node associated with this ODD node. - * @param elseNode The else-successor of thie ODD node. - * @param elseOffset The offset of the else-successor. - * @param thenNode The then-successor of thie ODD node. - * @param thenOffset The offset of the then-successor. - */ - Odd(std::shared_ptr<Odd<DdType::CUDD>> elseNode, uint_fast64_t elseOffset, std::shared_ptr<Odd<DdType::CUDD>> thenNode, uint_fast64_t thenOffset); - - /*! - * Recursively builds the ODD from an ADD (that has no complement edges). - * - * @param dd The DD for which to build the ODD. - * @param manager The manager responsible for the DD. - * @param currentLevel The currently considered level in the DD. - * @param maxLevel The number of levels that need to be considered. - * @param ddVariableIndices The (sorted) indices of all DD variables that need to be considered. - * @param uniqueTableForLevels A vector of unique tables, one for each level to be considered, that keeps - * ODD nodes for the same DD and level unique. - * @return A pointer to the constructed ODD for the given arguments. - */ - static std::shared_ptr<Odd<DdType::CUDD>> buildOddFromAddRec(DdNode* dd, Cudd const& manager, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<std::unordered_map<DdNode*, std::shared_ptr<Odd<DdType::CUDD>>>>& uniqueTableForLevels); - - /*! - * Recursively builds the ODD from a BDD (that potentially has complement edges). - * - * @param dd The DD for which to build the ODD. - * @param manager The manager responsible for the DD. - * @param currentLevel The currently considered level in the DD. - * @param complement A flag indicating whether or not the given node is to be considered as complemented. - * @param maxLevel The number of levels that need to be considered. - * @param ddVariableIndices The (sorted) indices of all DD variables that need to be considered. - * @param uniqueTableForLevels A vector of unique tables, one for each level to be considered, that keeps - * ODD nodes for the same DD and level unique. - * @return A pointer to the constructed ODD for the given arguments. - */ - static std::shared_ptr<Odd<DdType::CUDD>> buildOddFromBddRec(DdNode* dd, Cudd const& manager, uint_fast64_t currentLevel, bool complement, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<std::unordered_map<std::pair<DdNode*, bool>, std::shared_ptr<Odd<DdType::CUDD>>, HashFunctor>>& uniqueTableForLevels); - - /*! - * Adds the selected values the target vector. - * - * @param dd The current node of the DD representing the selected values. - * @param manager The manager responsible for the DD. - * @param currentLevel The currently considered level in the DD. - * @param maxLevel The number of levels that need to be considered. - * @param ddVariableIndices The sorted list of variable indices to use. - * @param currentOffset The offset along the path taken in the DD representing the selected values. - * @param odd The current ODD node. - * @param result The target vector to which to write the values. - * @param currentIndex The index at which the next element is to be written. - * @param values The value vector from which to select the values. - */ - static void addSelectedValuesToVectorRec(DdNode* dd, Cudd const& manager, uint_fast64_t currentLevel, bool complement, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices, uint_fast64_t currentOffset, storm::dd::Odd<DdType::CUDD> const& odd, std::vector<double>& result, uint_fast64_t& currentIndex, std::vector<double> const& values); - - /*! - * Adds the values of the old explicit values to the new explicit values where the positions in the old vector - * are given by the current old ODD and the positions in the new vector are given by the new ODD. - * - * @param oldOffset The offset in the old explicit values. - * @param oldOdd The ODD to use for the old explicit values. - * @param oldValues The vector of old values. - * @param newOffset The offset in the new explicit values. - * @param newOdd The ODD to use for the new explicit values. - * @param newValues The vector of new values. - */ - static void expandValuesToVectorRec(uint_fast64_t oldOffset, storm::dd::Odd<DdType::CUDD> const& oldOdd, std::vector<double> const& oldValues, uint_fast64_t newOffset, storm::dd::Odd<DdType::CUDD> const& newOdd, std::vector<double>& newValues); - - // The then- and else-nodes. - std::shared_ptr<Odd<DdType::CUDD>> elseNode; - std::shared_ptr<Odd<DdType::CUDD>> thenNode; - - // The offsets that need to be added if the then- or else-successor is taken, respectively. - uint_fast64_t elseOffset; - uint_fast64_t thenOffset; - }; - } -} - -#endif /* STORM_STORAGE_DD_CUDDODD_H_ */ \ No newline at end of file diff --git a/src/storage/dd/cudd/InternalCuddAdd.cpp b/src/storage/dd/cudd/InternalCuddAdd.cpp index fd7fb87bc..15a1706d8 100644 --- a/src/storage/dd/cudd/InternalCuddAdd.cpp +++ b/src/storage/dd/cudd/InternalCuddAdd.cpp @@ -1,9 +1,9 @@ #include "src/storage/dd/cudd/InternalCuddAdd.h" -#include "src/storage/dd/cudd/CuddOdd.h" - #include "src/storage/dd/cudd/InternalCuddDdManager.h" #include "src/storage/dd/cudd/InternalCuddBdd.h" +#include "src/storage/dd/cudd/CuddAddIterator.h" +#include "src/storage/dd/Odd.h" #include "src/storage/SparseMatrix.h" @@ -350,17 +350,69 @@ namespace storm { } template<typename ValueType> - void InternalAdd<DdType::CUDD, ValueType>::composeWithExplicitVector(storm::dd::Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<ValueType>& targetVector, std::function<ValueType (ValueType const&, ValueType const&)> const& function) const { + Odd InternalAdd<DdType::CUDD, ValueType>::createOdd(std::vector<uint_fast64_t> const& ddVariableIndices) const { + // Prepare a unique table for each level that keeps the constructed ODD nodes unique. + std::vector<std::unordered_map<DdNode*, std::shared_ptr<Odd>>> uniqueTableForLevels(ddVariableIndices.size() + 1); + + // Now construct the ODD structure from the ADD. + std::shared_ptr<Odd> rootOdd = createOddRec(this->getCuddDdNode(), ddManager->getCuddManager(), 0, ddVariableIndices.size(), ddVariableIndices, uniqueTableForLevels); + + // Return a copy of the root node to remove the shared_ptr encapsulation. + return Odd(*rootOdd); + } + + template<typename ValueType> + std::shared_ptr<Odd> InternalAdd<DdType::CUDD, ValueType>::createOddRec(DdNode* dd, Cudd const& manager, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<std::unordered_map<DdNode*, std::shared_ptr<Odd>>>& uniqueTableForLevels) { + // Check whether the ODD for this node has already been computed (for this level) and if so, return this instead. + auto const& iterator = uniqueTableForLevels[currentLevel].find(dd); + if (iterator != uniqueTableForLevels[currentLevel].end()) { + return iterator->second; + } else { + // Otherwise, we need to recursively compute the ODD. + + // If we are already past the maximal level that is to be considered, we can simply create an Odd without + // successors + if (currentLevel == maxLevel) { + uint_fast64_t elseOffset = 0; + uint_fast64_t thenOffset = 0; + + // If the DD is not the zero leaf, then the then-offset is 1. + if (dd != Cudd_ReadZero(manager.getManager())) { + thenOffset = 1; + } + + return std::make_shared<Odd>(nullptr, elseOffset, nullptr, thenOffset); + } else if (ddVariableIndices[currentLevel] < static_cast<uint_fast64_t>(dd->index)) { + // If we skipped the level in the DD, we compute the ODD just for the else-successor and use the same + // node for the then-successor as well. + std::shared_ptr<Odd> elseNode = createOddRec(dd, manager, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels); + std::shared_ptr<Odd> thenNode = elseNode; + return std::make_shared<Odd>(elseNode, elseNode->getElseOffset() + elseNode->getThenOffset(), thenNode, thenNode->getElseOffset() + thenNode->getThenOffset()); + } else { + // Otherwise, we compute the ODDs for both the then- and else successors. + bool elseComplemented = Cudd_IsComplement(Cudd_E(dd)); + bool thenComplemented = Cudd_IsComplement(Cudd_T(dd)); + std::shared_ptr<Odd> elseNode = createOddRec(Cudd_E(dd), manager, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels); + std::shared_ptr<Odd> thenNode = createOddRec(Cudd_T(dd), manager, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels); + uint_fast64_t totalElseOffset = elseNode->getElseOffset() + elseNode->getThenOffset(); + uint_fast64_t totalThenOffset = thenNode->getElseOffset() + thenNode->getThenOffset(); + return std::make_shared<Odd>(elseNode, elseComplemented ? (1ull << (maxLevel - currentLevel - 1)) - totalElseOffset : totalElseOffset, thenNode, thenComplemented ? (1ull << (maxLevel - currentLevel - 1)) - totalThenOffset : totalThenOffset); + } + } + } + + template<typename ValueType> + void InternalAdd<DdType::CUDD, ValueType>::composeWithExplicitVector(storm::dd::Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<ValueType>& targetVector, std::function<ValueType (ValueType const&, ValueType const&)> const& function) const { composeWithExplicitVectorRec(this->getCuddDdNode(), nullptr, 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, targetVector, function); } template<typename ValueType> - void InternalAdd<DdType::CUDD, ValueType>::composeWithExplicitVector(storm::dd::Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<uint_fast64_t> const& offsets, std::vector<ValueType>& targetVector, std::function<ValueType (ValueType const&, ValueType const&)> const& function) const { + void InternalAdd<DdType::CUDD, ValueType>::composeWithExplicitVector(storm::dd::Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<uint_fast64_t> const& offsets, std::vector<ValueType>& targetVector, std::function<ValueType (ValueType const&, ValueType const&)> const& function) const { composeWithExplicitVectorRec(this->getCuddDdNode(), &offsets, 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, targetVector, function); } template<typename ValueType> - void InternalAdd<DdType::CUDD, ValueType>::composeWithExplicitVectorRec(DdNode const* dd, std::vector<uint_fast64_t> const* offsets, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<ValueType>& targetVector, std::function<ValueType (ValueType const&, ValueType const&)> const& function) const { + void InternalAdd<DdType::CUDD, ValueType>::composeWithExplicitVectorRec(DdNode const* dd, std::vector<uint_fast64_t> const* offsets, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<ValueType>& targetVector, std::function<ValueType (ValueType const&, ValueType const&)> const& function) const { // For the empty DD, we do not need to add any entries. if (dd == Cudd_ReadZero(ddManager->getCuddManager().getManager())) { return; @@ -441,12 +493,12 @@ namespace storm { } template<typename ValueType> - void InternalAdd<DdType::CUDD, ValueType>::toMatrixComponents(std::vector<uint_fast64_t> const& rowGroupIndices, std::vector<uint_fast64_t>& rowIndications, std::vector<storm::storage::MatrixEntry<uint_fast64_t, ValueType>>& columnsAndValues, Odd<DdType::CUDD> const& rowOdd, Odd<DdType::CUDD> const& columnOdd, std::vector<uint_fast64_t> const& ddRowVariableIndices, std::vector<uint_fast64_t> const& ddColumnVariableIndices, bool writeValues) const { + void InternalAdd<DdType::CUDD, ValueType>::toMatrixComponents(std::vector<uint_fast64_t> const& rowGroupIndices, std::vector<uint_fast64_t>& rowIndications, std::vector<storm::storage::MatrixEntry<uint_fast64_t, ValueType>>& columnsAndValues, Odd const& rowOdd, Odd const& columnOdd, std::vector<uint_fast64_t> const& ddRowVariableIndices, std::vector<uint_fast64_t> const& ddColumnVariableIndices, bool writeValues) const { return toMatrixComponentsRec(this->getCuddDdNode(), rowGroupIndices, rowIndications, columnsAndValues, rowOdd, columnOdd, 0, 0, ddRowVariableIndices.size() + ddColumnVariableIndices.size(), 0, 0, ddRowVariableIndices, ddColumnVariableIndices, writeValues); } template<typename ValueType> - void InternalAdd<DdType::CUDD, ValueType>::toMatrixComponentsRec(DdNode const* dd, std::vector<uint_fast64_t> const& rowGroupOffsets, std::vector<uint_fast64_t>& rowIndications, std::vector<storm::storage::MatrixEntry<uint_fast64_t, ValueType>>& columnsAndValues, Odd<DdType::CUDD> const& rowOdd, Odd<DdType::CUDD> const& columnOdd, uint_fast64_t currentRowLevel, uint_fast64_t currentColumnLevel, uint_fast64_t maxLevel, uint_fast64_t currentRowOffset, uint_fast64_t currentColumnOffset, std::vector<uint_fast64_t> const& ddRowVariableIndices, std::vector<uint_fast64_t> const& ddColumnVariableIndices, bool generateValues) const { + void InternalAdd<DdType::CUDD, ValueType>::toMatrixComponentsRec(DdNode const* dd, std::vector<uint_fast64_t> const& rowGroupOffsets, std::vector<uint_fast64_t>& rowIndications, std::vector<storm::storage::MatrixEntry<uint_fast64_t, ValueType>>& columnsAndValues, Odd const& rowOdd, Odd const& columnOdd, uint_fast64_t currentRowLevel, uint_fast64_t currentColumnLevel, uint_fast64_t maxLevel, uint_fast64_t currentRowOffset, uint_fast64_t currentColumnOffset, std::vector<uint_fast64_t> const& ddRowVariableIndices, std::vector<uint_fast64_t> const& ddColumnVariableIndices, bool generateValues) const { // For the empty DD, we do not need to add any entries. if (dd == Cudd_ReadZero(ddManager->getCuddManager().getManager())) { return; @@ -498,233 +550,14 @@ namespace storm { } } - -// template<typename ValueType> -// storm::storage::SparseMatrix<ValueType> InternalAdd<DdType::CUDD, ValueType>::toMatrix(uint_fast64_t numberOfDdVariables, storm::dd::Odd<DdType::CUDD> const& rowOdd, std::vector<uint_fast64_t> const& ddRowVariableIndices, storm::dd::Odd<DdType::CUDD> const& columnOdd, std::vector<uint_fast64_t> const& ddColumnVariableIndices) const { -// // Prepare the vectors that represent the matrix. -// std::vector<uint_fast64_t> rowIndications(rowOdd.getTotalOffset() + 1); -// std::vector<storm::storage::MatrixEntry<uint_fast64_t, double>> columnsAndValues(this->getNonZeroCount(numberOfDdVariables)); -// -// // Create a trivial row grouping. -// std::vector<uint_fast64_t> trivialRowGroupIndices(rowIndications.size()); -// uint_fast64_t i = 0; -// for (auto& entry : trivialRowGroupIndices) { -// entry = i; -// ++i; -// } -// -// // Use the toMatrixRec function to compute the number of elements in each row. Using the flag, we prevent -// // it from actually generating the entries in the entry vector. -// toMatrixRec(this->getCuddDdNode(), rowIndications, columnsAndValues, trivialRowGroupIndices, rowOdd, columnOdd, 0, 0, ddRowVariableIndices.size() + ddColumnVariableIndices.size(), 0, 0, ddRowVariableIndices, ddColumnVariableIndices, false); -// -// // TODO: counting might be faster by just summing over the primed variables and then using the ODD to convert -// // the resulting (DD) vector to an explicit vector. -// -// // Now that we computed the number of entries in each row, compute the corresponding offsets in the entry vector. -// uint_fast64_t tmp = 0; -// uint_fast64_t tmp2 = 0; -// for (uint_fast64_t i = 1; i < rowIndications.size(); ++i) { -// tmp2 = rowIndications[i]; -// rowIndications[i] = rowIndications[i - 1] + tmp; -// std::swap(tmp, tmp2); -// } -// rowIndications[0] = 0; -// -// // Now actually fill the entry vector. -// toMatrixRec(this->getCuddDdNode(), rowIndications, columnsAndValues, trivialRowGroupIndices, rowOdd, columnOdd, 0, 0, ddRowVariableIndices.size() + ddColumnVariableIndices.size(), 0, 0, ddRowVariableIndices, ddColumnVariableIndices, true); -// -// // Since the last call to toMatrixRec modified the rowIndications, we need to restore the correct values. -// for (uint_fast64_t i = rowIndications.size() - 1; i > 0; --i) { -// rowIndications[i] = rowIndications[i - 1]; -// } -// rowIndications[0] = 0; -// -// // Construct matrix and return result. -// return storm::storage::SparseMatrix<double>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(trivialRowGroupIndices), false); -// } -// -// template<typename ValueType> -// storm::storage::SparseMatrix<ValueType> InternalAdd<DdType::CUDD, ValueType>::toMatrix(std::vector<uint_fast64_t> const& ddGroupVariableIndices, InternalBdd<DdType::CUDD> const& groupVariableCube, storm::dd::Odd<DdType::CUDD> const& rowOdd, std::vector<uint_fast64_t> const& ddRowVariableIndices, storm::dd::Odd<DdType::CUDD> const& columnOdd, std::vector<uint_fast64_t> const& ddColumnVariableIndices, InternalBdd<DdType::CUDD> const& columnVariableCube) const { -// // Start by computing the offsets (in terms of rows) for each row group. -// InternalAdd<DdType::CUDD, uint_fast64_t> stateToNumberOfChoices = this->notZero().existsAbstract(columnVariableCube).template toAdd<uint_fast64_t>().sumAbstract(groupVariableCube); -// std::vector<ValueType> rowGroupIndices = stateToNumberOfChoices.toVector(rowOdd); -// rowGroupIndices.resize(rowGroupIndices.size() + 1); -// uint_fast64_t tmp = 0; -// uint_fast64_t tmp2 = 0; -// for (uint_fast64_t i = 1; i < rowGroupIndices.size(); ++i) { -// tmp2 = rowGroupIndices[i]; -// rowGroupIndices[i] = rowGroupIndices[i - 1] + tmp; -// std::swap(tmp, tmp2); -// } -// rowGroupIndices[0] = 0; -// -// // Next, we split the matrix into one for each group. This only works if the group variables are at the very -// // top. -// std::vector<InternalAdd<DdType::CUDD, ValueType>> groups; -// splitGroupsRec(this->getCuddDdNode(), groups, ddGroupVariableIndices, 0, ddGroupVariableIndices.size()); -// -// // Create the actual storage for the non-zero entries. -// std::vector<storm::storage::MatrixEntry<uint_fast64_t, double>> columnsAndValues(this->getNonZeroCount()); -// -// // Now compute the indices at which the individual rows start. -// std::vector<uint_fast64_t> rowIndications(rowGroupIndices.back() + 1); -// -// std::vector<InternalAdd<DdType::CUDD, ValueType>> statesWithGroupEnabled(groups.size()); -// InternalAdd<DdType::CUDD, ValueType> stateToRowGroupCount = this->getDdManager()->getAddZero(); -// for (uint_fast64_t i = 0; i < groups.size(); ++i) { -// auto const& dd = groups[i]; -// -// toMatrixRec(dd.getCuddDdNode(), rowIndications, columnsAndValues, rowGroupIndices, rowOdd, columnOdd, 0, 0, ddRowVariableIndices.size() + ddColumnVariableIndices.size(), 0, 0, ddRowVariableIndices, ddColumnVariableIndices, false); -// -// statesWithGroupEnabled[i] = dd.notZero().existsAbstract(columnVariableCube).toAdd(); -// stateToRowGroupCount += statesWithGroupEnabled[i]; -// statesWithGroupEnabled[i].addToVector(rowOdd, ddRowVariableIndices, rowGroupIndices); -// } -// -// // Since we modified the rowGroupIndices, we need to restore the correct values. -// std::function<uint_fast64_t (uint_fast64_t const&, uint_fast64_t const&)> fct = [] (uint_fast64_t const& a, double const& b) -> uint_fast64_t { return a - static_cast<uint_fast64_t>(b); }; -// composeVectorRec(stateToRowGroupCount.getCuddDdNode(), 0, ddRowVariableIndices.size(), 0, rowOdd, ddRowVariableIndices, rowGroupIndices, fct); -// -// // Now that we computed the number of entries in each row, compute the corresponding offsets in the entry vector. -// tmp = 0; -// tmp2 = 0; -// for (uint_fast64_t i = 1; i < rowIndications.size(); ++i) { -// tmp2 = rowIndications[i]; -// rowIndications[i] = rowIndications[i - 1] + tmp; -// std::swap(tmp, tmp2); -// } -// rowIndications[0] = 0; -// -// // Now actually fill the entry vector. -// for (uint_fast64_t i = 0; i < groups.size(); ++i) { -// auto const& dd = groups[i]; -// -// toMatrixRec(dd.getCuddDdNode(), rowIndications, columnsAndValues, rowGroupIndices, rowOdd, columnOdd, 0, 0, ddRowVariableIndices.size() + ddColumnVariableIndices.size(), 0, 0, ddRowVariableIndices, ddColumnVariableIndices, true); -// -// statesWithGroupEnabled[i].addToVector(rowOdd, ddRowVariableIndices, rowGroupIndices); -// } -// -// // Since we modified the rowGroupIndices, we need to restore the correct values. -// composeVectorRec(stateToRowGroupCount.getCuddDdNode(), 0, ddRowVariableIndices.size(), 0, rowOdd, ddRowVariableIndices, rowGroupIndices, fct); -// -// // Since the last call to toMatrixRec modified the rowIndications, we need to restore the correct values. -// for (uint_fast64_t i = rowIndications.size() - 1; i > 0; --i) { -// rowIndications[i] = rowIndications[i - 1]; -// } -// rowIndications[0] = 0; -// -// return storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), true); -// } -// -// template<typename ValueType> -// std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> InternalAdd<DdType::CUDD, ValueType>::toMatrixVector(InternalAdd<DdType::CUDD, ValueType> const& vector, std::vector<uint_fast64_t> const& ddGroupVariableIndices, std::vector<uint_fast64_t>&& rowGroupIndices, storm::dd::Odd<DdType::CUDD> const& rowOdd, std::vector<uint_fast64_t> const& ddRowVariableIndices, storm::dd::Odd<DdType::CUDD> const& columnOdd, std::vector<uint_fast64_t> const& ddColumnVariableIndices, InternalBdd<DdType::CUDD> const& columnVariableCube) const { -// // Transform the row group sizes to the actual row group indices. -// rowGroupIndices.resize(rowGroupIndices.size() + 1); -// uint_fast64_t tmp = 0; -// uint_fast64_t tmp2 = 0; -// for (uint_fast64_t i = 1; i < rowGroupIndices.size(); ++i) { -// tmp2 = rowGroupIndices[i]; -// rowGroupIndices[i] = rowGroupIndices[i - 1] + tmp; -// std::swap(tmp, tmp2); -// } -// rowGroupIndices[0] = 0; -// -// // Create the explicit vector we need to fill later. -// std::vector<double> explicitVector(rowGroupIndices.back()); -// -// // Next, we split the matrix into one for each group. This only works if the group variables are at the very top. -// std::vector<std::pair<InternalAdd<DdType::CUDD, ValueType>, InternalAdd<DdType::CUDD, ValueType>>> groups; -// splitGroupsRec(this->getCuddDdNode(), vector.getCuddDdNode(), groups, ddGroupVariableIndices, 0, ddGroupVariableIndices.size()); -// -// // Create the actual storage for the non-zero entries. -// std::vector<storm::storage::MatrixEntry<uint_fast64_t, double>> columnsAndValues(this->getNonZeroCount()); -// -// // Now compute the indices at which the individual rows start. -// std::vector<uint_fast64_t> rowIndications(rowGroupIndices.back() + 1); -// -// std::vector<storm::dd::InternalAdd<DdType::CUDD, ValueType>> statesWithGroupEnabled(groups.size()); -// storm::dd::InternalAdd<storm::dd::DdType::CUDD, ValueType> stateToRowGroupCount = this->getDdManager()->getAddZero(); -// for (uint_fast64_t i = 0; i < groups.size(); ++i) { -// std::pair<storm::dd::InternalAdd<DdType::CUDD, ValueType>, storm::dd::InternalAdd<DdType::CUDD, ValueType>> ddPair = groups[i]; -// -// toMatrixRec(ddPair.first.getCuddDdNode(), rowIndications, columnsAndValues, rowGroupIndices, rowOdd, columnOdd, 0, 0, ddRowVariableIndices.size() + ddColumnVariableIndices.size(), 0, 0, ddRowVariableIndices, ddColumnVariableIndices, false); -// toVectorRec(ddPair.second.getCuddDdNode(), explicitVector, rowGroupIndices, rowOdd, 0, ddRowVariableIndices.size(), 0, ddRowVariableIndices); -// -// statesWithGroupEnabled[i] = (ddPair.first.notZero().existsAbstract(columnVariableCube) || ddPair.second.notZero()).toAdd(); -// stateToRowGroupCount += statesWithGroupEnabled[i]; -// statesWithGroupEnabled[i].addToVector(rowOdd, ddRowVariableIndices, rowGroupIndices); -// } -// -// // Since we modified the rowGroupIndices, we need to restore the correct values. -// std::function<uint_fast64_t (uint_fast64_t const&, double const&)> fct = [] (uint_fast64_t const& a, double const& b) -> uint_fast64_t { return a - static_cast<uint_fast64_t>(b); }; -// composeVectorRec(stateToRowGroupCount.getCuddDdNode(), 0, ddRowVariableIndices.size(), 0, rowOdd, ddRowVariableIndices, rowGroupIndices, fct); -// -// // Now that we computed the number of entries in each row, compute the corresponding offsets in the entry vector. -// tmp = 0; -// tmp2 = 0; -// for (uint_fast64_t i = 1; i < rowIndications.size(); ++i) { -// tmp2 = rowIndications[i]; -// rowIndications[i] = rowIndications[i - 1] + tmp; -// std::swap(tmp, tmp2); -// } -// rowIndications[0] = 0; -// -// // Now actually fill the entry vector. -// for (uint_fast64_t i = 0; i < groups.size(); ++i) { -// auto const& dd = groups[i].first; -// -// toMatrixRec(dd.getCuddDdNode(), rowIndications, columnsAndValues, rowGroupIndices, rowOdd, columnOdd, 0, 0, ddRowVariableIndices.size() + ddColumnVariableIndices.size(), 0, 0, ddRowVariableIndices, ddColumnVariableIndices, true); -// -// statesWithGroupEnabled[i].addToVector(rowOdd, ddRowVariableIndices, rowGroupIndices); -// } -// -// // Since we modified the rowGroupIndices, we need to restore the correct values. -// composeVectorRec(stateToRowGroupCount.getCuddDdNode(), 0, ddRowVariableIndices.size(), 0, rowOdd, ddRowVariableIndices, rowGroupIndices, fct); -// -// // Since the last call to toMatrixRec modified the rowIndications, we need to restore the correct values. -// for (uint_fast64_t i = rowIndications.size() - 1; i > 0; --i) { -// rowIndications[i] = rowIndications[i - 1]; -// } -// rowIndications[0] = 0; -// -// return std::make_pair(storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), true), std::move(explicitVector)); -// } -// -// template<typename ValueType> -// void InternalAdd<DdType::CUDD, ValueType>::splitGroupsRec(DdNode* dd1, DdNode* dd2, std::vector<std::pair<InternalAdd<DdType::CUDD, ValueType>, InternalAdd<DdType::CUDD, ValueType>>>& groups, std::vector<uint_fast64_t> const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const { -// // For the empty DD, we do not need to create a group. -// if (dd1 == Cudd_ReadZero(ddManager->getCuddManager().getManager()) && dd2 == Cudd_ReadZero(ddManager->getCuddManager().getManager())) { -// return; -// } -// -// if (currentLevel == maxLevel) { -// groups.push_back(std::make_pair(InternalAdd<DdType::CUDD, ValueType>(ddManager, ADD(ddManager->getCuddManager(), dd1)), -// InternalAdd<DdType::CUDD, ValueType>(ddManager, ADD(ddManager->getCuddManager(), dd2)))); -// } else if (ddGroupVariableIndices[currentLevel] < dd1->index) { -// if (ddGroupVariableIndices[currentLevel] < dd2->index) { -// splitGroupsRec(dd1, dd2, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); -// splitGroupsRec(dd1, dd2, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); -// } else { -// splitGroupsRec(dd1, Cudd_T(dd2), groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); -// splitGroupsRec(dd1, Cudd_E(dd2), groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); -// } -// } else if (ddGroupVariableIndices[currentLevel] < dd2->index) { -// splitGroupsRec(Cudd_T(dd1), dd2, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); -// splitGroupsRec(Cudd_E(dd1), dd2, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); -// } else { -// splitGroupsRec(Cudd_T(dd1), Cudd_T(dd2), groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); -// splitGroupsRec(Cudd_E(dd1), Cudd_E(dd2), groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); -// } -// } - - template<typename ValueType> - InternalAdd<DdType::CUDD, ValueType> InternalAdd<DdType::CUDD, ValueType>::fromVector(InternalDdManager<DdType::CUDD> const* ddManager, std::vector<ValueType> const& values, storm::dd::Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& ddVariableIndices) { + template<typename ValueType> + InternalAdd<DdType::CUDD, ValueType> InternalAdd<DdType::CUDD, ValueType>::fromVector(InternalDdManager<DdType::CUDD> const* ddManager, std::vector<ValueType> const& values, storm::dd::Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices) { uint_fast64_t offset = 0; return InternalAdd<DdType::CUDD, ValueType>(ddManager, ADD(ddManager->getCuddManager(), fromVectorRec(ddManager->getCuddManager().getManager(), offset, 0, ddVariableIndices.size(), values, odd, ddVariableIndices))); } template<typename ValueType> - DdNode* InternalAdd<DdType::CUDD, ValueType>::fromVectorRec(::DdManager* manager, uint_fast64_t& currentOffset, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector<ValueType> const& values, Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& ddVariableIndices) { + DdNode* InternalAdd<DdType::CUDD, ValueType>::fromVectorRec(::DdManager* manager, uint_fast64_t& currentOffset, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector<ValueType> const& values, Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices) { if (currentLevel == maxLevel) { // If we are in a terminal node of the ODD, we need to check whether the then-offset of the ODD is one // (meaning the encoding is a valid one) or zero (meaning the encoding is not valid). Consequently, we diff --git a/src/storage/dd/cudd/InternalCuddAdd.h b/src/storage/dd/cudd/InternalCuddAdd.h index 2643912d0..fab7cbef6 100644 --- a/src/storage/dd/cudd/InternalCuddAdd.h +++ b/src/storage/dd/cudd/InternalCuddAdd.h @@ -2,9 +2,11 @@ #define STORM_STORAGE_DD_CUDD_INTERNALCUDDADD_H_ #include <set> +#include <unordered_map> #include "src/storage/dd/DdType.h" #include "src/storage/dd/InternalAdd.h" +#include "src/storage/dd/Odd.h" #include "src/storage/expressions/Variable.h" @@ -25,24 +27,19 @@ namespace storm { namespace dd { template<DdType LibraryType> class DdManager; - + template<DdType LibraryType> class InternalDdManager; template<DdType LibraryType> class InternalBdd; - + template<DdType LibraryType, typename ValueType> class AddIterator; - template<DdType LibraryType> - class Odd; - template<typename ValueType> class InternalAdd<DdType::CUDD, ValueType> { public: - friend class Odd<DdType::CUDD>; - /*! * Creates an ADD that encapsulates the given CUDD ADD. * @@ -500,19 +497,26 @@ namespace storm { * if a meta variable does not at all influence the the function value. * @return An iterator that points past the end of the container. */ - AddIterator<DdType::CUDD, ValueType> end(std::shared_ptr<DdManager<DdType::CUDD> const> fullDdManager, bool enumerateDontCareMetaVariables = true) const; + AddIterator<DdType::CUDD, ValueType> end(std::shared_ptr<DdManager<DdType::CUDD> const> fullDdManager, bool enumerateDontCareMetaVariables = true) const; - void composeWithExplicitVector(Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<ValueType>& targetVector, std::function<ValueType (ValueType const&, ValueType const&)> const& function) const; + void composeWithExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<ValueType>& targetVector, std::function<ValueType (ValueType const&, ValueType const&)> const& function) const; - void composeWithExplicitVector(Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<uint_fast64_t> const& offsets, std::vector<ValueType>& targetVector, std::function<ValueType (ValueType const&, ValueType const&)> const& function) const; + void composeWithExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<uint_fast64_t> const& offsets, std::vector<ValueType>& targetVector, std::function<ValueType (ValueType const&, ValueType const&)> const& function) const; std::vector<InternalAdd<DdType::CUDD, ValueType>> splitIntoGroups(std::vector<uint_fast64_t> const& ddGroupVariableIndices) const; - void toMatrixComponents(std::vector<uint_fast64_t> const& rowGroupIndices, std::vector<uint_fast64_t>& rowIndications, std::vector<storm::storage::MatrixEntry<uint_fast64_t, ValueType>>& columnsAndValues, Odd<DdType::CUDD> const& rowOdd, Odd<DdType::CUDD> const& columnOdd, std::vector<uint_fast64_t> const& ddRowVariableIndices, std::vector<uint_fast64_t> const& ddColumnVariableIndices, bool writeValues) const; + void toMatrixComponents(std::vector<uint_fast64_t> const& rowGroupIndices, std::vector<uint_fast64_t>& rowIndications, std::vector<storm::storage::MatrixEntry<uint_fast64_t, ValueType>>& columnsAndValues, Odd const& rowOdd, Odd const& columnOdd, std::vector<uint_fast64_t> const& ddRowVariableIndices, std::vector<uint_fast64_t> const& ddColumnVariableIndices, bool writeValues) const; std::vector<std::pair<InternalAdd<DdType::CUDD, ValueType>, InternalAdd<DdType::CUDD, ValueType>>> splitIntoGroups(InternalAdd<DdType::CUDD, ValueType> vector, std::vector<uint_fast64_t> const& ddGroupVariableIndices) const; - static InternalAdd<DdType::CUDD, ValueType> fromVector(InternalDdManager<DdType::CUDD> const* ddManager, std::vector<ValueType> const& values, storm::dd::Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& ddVariableIndices); + static InternalAdd<DdType::CUDD, ValueType> fromVector(InternalDdManager<DdType::CUDD> const* ddManager, std::vector<ValueType> const& values, storm::dd::Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices); + + /*! + * Creates an ODD based on the current ADD. + * + * @return The corresponding ODD. + */ + Odd createOdd(std::vector<uint_fast64_t> const& ddVariableIndices) const; private: /*! @@ -541,7 +545,7 @@ namespace storm { * @param ddVariableIndices The (sorted) indices of all DD variables that need to be considered. * @param targetVector The vector to which the translated DD-based vector is to be added. */ - void composeWithExplicitVectorRec(DdNode const* dd, std::vector<uint_fast64_t> const* offsets, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<ValueType>& targetVector, std::function<ValueType (ValueType const&, ValueType const&)> const& function) const; + void composeWithExplicitVectorRec(DdNode const* dd, std::vector<uint_fast64_t> const* offsets, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<ValueType>& targetVector, std::function<ValueType (ValueType const&, ValueType const&)> const& function) const; /*! * Splits the given matrix DD into the groups using the given group variables. @@ -582,7 +586,7 @@ namespace storm { * only works if the offsets given in rowIndications are already correct. If they need to be computed first, * this flag needs to be false. */ - void toMatrixComponentsRec(DdNode const* dd, std::vector<uint_fast64_t> const& rowGroupOffsets, std::vector<uint_fast64_t>& rowIndications, std::vector<storm::storage::MatrixEntry<uint_fast64_t, ValueType>>& columnsAndValues, Odd<DdType::CUDD> const& rowOdd, Odd<DdType::CUDD> const& columnOdd, uint_fast64_t currentRowLevel, uint_fast64_t currentColumnLevel, uint_fast64_t maxLevel, uint_fast64_t currentRowOffset, uint_fast64_t currentColumnOffset, std::vector<uint_fast64_t> const& ddRowVariableIndices, std::vector<uint_fast64_t> const& ddColumnVariableIndices, bool writeValues) const; + void toMatrixComponentsRec(DdNode const* dd, std::vector<uint_fast64_t> const& rowGroupOffsets, std::vector<uint_fast64_t>& rowIndications, std::vector<storm::storage::MatrixEntry<uint_fast64_t, ValueType>>& columnsAndValues, Odd const& rowOdd, Odd const& columnOdd, uint_fast64_t currentRowLevel, uint_fast64_t currentColumnLevel, uint_fast64_t maxLevel, uint_fast64_t currentRowOffset, uint_fast64_t currentColumnOffset, std::vector<uint_fast64_t> const& ddRowVariableIndices, std::vector<uint_fast64_t> const& ddColumnVariableIndices, bool writeValues) const; /*! * Builds an ADD representing the given vector. @@ -596,7 +600,21 @@ namespace storm { * @param ddVariableIndices The (sorted) list of DD variable indices to use. * @return The resulting (CUDD) ADD node. */ - static DdNode* fromVectorRec(::DdManager* manager, uint_fast64_t& currentOffset, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector<ValueType> const& values, Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& ddVariableIndices); + static DdNode* fromVectorRec(::DdManager* manager, uint_fast64_t& currentOffset, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector<ValueType> const& values, Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices); + + /*! + * Recursively builds the ODD from an ADD (that has no complement edges). + * + * @param dd The DD for which to build the ODD. + * @param manager The manager responsible for the DD. + * @param currentLevel The currently considered level in the DD. + * @param maxLevel The number of levels that need to be considered. + * @param ddVariableIndices The (sorted) indices of all DD variables that need to be considered. + * @param uniqueTableForLevels A vector of unique tables, one for each level to be considered, that keeps + * ODD nodes for the same DD and level unique. + * @return A pointer to the constructed ODD for the given arguments. + */ + static std::shared_ptr<Odd> createOddRec(DdNode* dd, Cudd const& manager, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<std::unordered_map<DdNode*, std::shared_ptr<Odd>>>& uniqueTableForLevels); InternalDdManager<DdType::CUDD> const* ddManager; diff --git a/src/storage/dd/cudd/InternalCuddBdd.cpp b/src/storage/dd/cudd/InternalCuddBdd.cpp index 72d12d6ae..3bfb98c5c 100644 --- a/src/storage/dd/cudd/InternalCuddBdd.cpp +++ b/src/storage/dd/cudd/InternalCuddBdd.cpp @@ -1,7 +1,9 @@ #include "src/storage/dd/cudd/InternalCuddBdd.h" +#include <boost/functional/hash.hpp> + #include "src/storage/dd/cudd/InternalCuddDdManager.h" -#include "src/storage/dd/cudd/CuddOdd.h" +#include "src/storage/dd/Odd.h" #include "src/storage/BitVector.h" @@ -12,7 +14,7 @@ namespace storm { } template<typename ValueType> - InternalBdd<DdType::CUDD> InternalBdd<DdType::CUDD>::fromVector(InternalDdManager<DdType::CUDD> const* ddManager, std::vector<ValueType> const& values, Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& sortedDdVariableIndices, std::function<bool (ValueType const&)> const& filter) { + InternalBdd<DdType::CUDD> InternalBdd<DdType::CUDD>::fromVector(InternalDdManager<DdType::CUDD> const* ddManager, std::vector<ValueType> const& values, Odd const& odd, std::vector<uint_fast64_t> const& sortedDdVariableIndices, std::function<bool (ValueType const&)> const& filter) { uint_fast64_t offset = 0; return InternalBdd<DdType::CUDD>(ddManager, BDD(ddManager->getCuddManager(), fromVectorRec(ddManager->getCuddManager().getManager(), offset, 0, sortedDdVariableIndices.size(), values, odd, sortedDdVariableIndices, filter))); } @@ -175,7 +177,7 @@ namespace storm { } template<typename ValueType> - DdNode* InternalBdd<DdType::CUDD>::fromVectorRec(::DdManager* manager, uint_fast64_t& currentOffset, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector<ValueType> const& values, Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::function<bool (ValueType const&)> const& filter) { + DdNode* InternalBdd<DdType::CUDD>::fromVectorRec(::DdManager* manager, uint_fast64_t& currentOffset, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector<ValueType> const& values, Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::function<bool (ValueType const&)> const& filter) { if (currentLevel == maxLevel) { // If we are in a terminal node of the ODD, we need to check whether the then-offset of the ODD is one // (meaning the encoding is a valid one) or zero (meaning the encoding is not valid). Consequently, we @@ -231,13 +233,13 @@ namespace storm { } } - storm::storage::BitVector InternalBdd<DdType::CUDD>::toVector(storm::dd::Odd<DdType::CUDD> const& rowOdd, std::vector<uint_fast64_t> const& ddVariableIndices) const { + storm::storage::BitVector InternalBdd<DdType::CUDD>::toVector(storm::dd::Odd const& rowOdd, std::vector<uint_fast64_t> const& ddVariableIndices) const { storm::storage::BitVector result(rowOdd.getTotalOffset()); this->toVectorRec(this->getCuddDdNode(), ddManager->getCuddManager(), result, rowOdd, Cudd_IsComplement(this->getCuddDdNode()), 0, ddVariableIndices.size(), 0, ddVariableIndices); return result; } - void InternalBdd<DdType::CUDD>::toVectorRec(DdNode const* dd, Cudd const& manager, storm::storage::BitVector& result, Odd<DdType::CUDD> const& rowOdd, bool complement, uint_fast64_t currentRowLevel, uint_fast64_t maxLevel, uint_fast64_t currentRowOffset, std::vector<uint_fast64_t> const& ddRowVariableIndices) const { + void InternalBdd<DdType::CUDD>::toVectorRec(DdNode const* dd, Cudd const& manager, storm::storage::BitVector& result, Odd const& rowOdd, bool complement, uint_fast64_t currentRowLevel, uint_fast64_t maxLevel, uint_fast64_t currentRowOffset, std::vector<uint_fast64_t> const& ddRowVariableIndices) const { // If there are no more values to select, we can directly return. if (dd == Cudd_ReadLogicZero(manager.getManager()) && !complement) { return; @@ -265,10 +267,127 @@ namespace storm { } } - template InternalBdd<DdType::CUDD> InternalBdd<DdType::CUDD>::fromVector(InternalDdManager<DdType::CUDD> const* ddManager, std::vector<double> const& values, Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& sortedDdVariableIndices, std::function<bool (double const&)> const& filter); - template InternalBdd<DdType::CUDD> InternalBdd<DdType::CUDD>::fromVector(InternalDdManager<DdType::CUDD> const* ddManager, std::vector<uint_fast64_t> const& values, Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& sortedDdVariableIndices, std::function<bool (uint_fast64_t const&)> const& filter); + Odd InternalBdd<DdType::CUDD>::createOdd(std::vector<uint_fast64_t> const& ddVariableIndices) const { + // Prepare a unique table for each level that keeps the constructed ODD nodes unique. + std::vector<std::unordered_map<std::pair<DdNode*, bool>, std::shared_ptr<Odd>, HashFunctor>> uniqueTableForLevels(ddVariableIndices.size() + 1); + + // Now construct the ODD structure from the BDD. + std::shared_ptr<Odd> rootOdd = createOddRec(Cudd_Regular(this->getCuddDdNode()), ddManager->getCuddManager(), 0, Cudd_IsComplement(this->getCuddDdNode()), ddVariableIndices.size(), ddVariableIndices, uniqueTableForLevels); + + // Return a copy of the root node to remove the shared_ptr encapsulation. + return Odd(*rootOdd); + } + + std::size_t InternalBdd<DdType::CUDD>::HashFunctor::operator()(std::pair<DdNode*, bool> const& key) const { + std::size_t result = 0; + boost::hash_combine(result, key.first); + boost::hash_combine(result, key.second); + return result; + } + + std::shared_ptr<Odd> InternalBdd<DdType::CUDD>::createOddRec(DdNode* dd, Cudd const& manager, uint_fast64_t currentLevel, bool complement, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<std::unordered_map<std::pair<DdNode*, bool>, std::shared_ptr<Odd>, HashFunctor>>& uniqueTableForLevels) { + // Check whether the ODD for this node has already been computed (for this level) and if so, return this instead. + auto const& iterator = uniqueTableForLevels[currentLevel].find(std::make_pair(dd, complement)); + if (iterator != uniqueTableForLevels[currentLevel].end()) { + return iterator->second; + } else { + // Otherwise, we need to recursively compute the ODD. + + // If we are already past the maximal level that is to be considered, we can simply create an Odd without + // successors + if (currentLevel == maxLevel) { + uint_fast64_t elseOffset = 0; + uint_fast64_t thenOffset = 0; + + // If the DD is not the zero leaf, then the then-offset is 1. + if (dd != Cudd_ReadZero(manager.getManager())) { + thenOffset = 1; + } + + // If we need to complement the 'terminal' node, we need to negate its offset. + if (complement) { + thenOffset = 1 - thenOffset; + } + + return std::make_shared<Odd>(nullptr, elseOffset, nullptr, thenOffset); + } else if (ddVariableIndices[currentLevel] < static_cast<uint_fast64_t>(dd->index)) { + // If we skipped the level in the DD, we compute the ODD just for the else-successor and use the same + // node for the then-successor as well. + std::shared_ptr<Odd> elseNode = createOddRec(dd, manager, currentLevel + 1, complement, maxLevel, ddVariableIndices, uniqueTableForLevels); + std::shared_ptr<Odd> thenNode = elseNode; + uint_fast64_t totalOffset = elseNode->getElseOffset() + elseNode->getThenOffset(); + return std::make_shared<Odd>(elseNode, totalOffset, thenNode, totalOffset); + } else { + // Otherwise, we compute the ODDs for both the then- and else successors. + DdNode* thenDdNode = Cudd_T(dd); + DdNode* elseDdNode = Cudd_E(dd); + + // Determine whether we have to evaluate the successors as if they were complemented. + bool elseComplemented = Cudd_IsComplement(elseDdNode) ^ complement; + bool thenComplemented = Cudd_IsComplement(thenDdNode) ^ complement; + + std::shared_ptr<Odd> elseNode = createOddRec(Cudd_Regular(elseDdNode), manager, currentLevel + 1, elseComplemented, maxLevel, ddVariableIndices, uniqueTableForLevels); + std::shared_ptr<Odd> thenNode = createOddRec(Cudd_Regular(thenDdNode), manager, currentLevel + 1, thenComplemented, maxLevel, ddVariableIndices, uniqueTableForLevels); + + return std::make_shared<Odd>(elseNode, elseNode->getElseOffset() + elseNode->getThenOffset(), thenNode, thenNode->getElseOffset() + thenNode->getThenOffset()); + } + } + } + + template<typename ValueType> + void InternalBdd<DdType::CUDD>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<ValueType> const& sourceValues, std::vector<ValueType>& targetValues) const { + uint_fast64_t currentIndex = 0; + filterExplicitVectorRec(this->getCuddDdNode(), ddManager->getCuddManager(), 0, Cudd_IsComplement(this->getCuddDdNode()), ddVariableIndices.size(), ddVariableIndices, 0, odd, targetValues, currentIndex, sourceValues); + } + + template<typename ValueType> + void InternalBdd<DdType::CUDD>::filterExplicitVectorRec(DdNode* dd, Cudd const& manager, uint_fast64_t currentLevel, bool complement, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices, uint_fast64_t currentOffset, storm::dd::Odd const& odd, std::vector<ValueType>& result, uint_fast64_t& currentIndex, std::vector<ValueType> const& values) { + // If there are no more values to select, we can directly return. + if (dd == Cudd_ReadLogicZero(manager.getManager()) && !complement) { + return; + } else if (dd == Cudd_ReadOne(manager.getManager()) && complement) { + return; + } + + if (currentLevel == maxLevel) { + // If the DD is not the zero leaf, then the then-offset is 1. + bool selected = false; + if (dd != Cudd_ReadLogicZero(manager.getManager())) { + selected = !complement; + } + + if (selected) { + result[currentIndex++] = values[currentOffset]; + } + } else if (ddVariableIndices[currentLevel] < dd->index) { + // If we skipped a level, we need to enumerate the explicit entries for the case in which the bit is set + // and for the one in which it is not set. + filterExplicitVectorRec(dd, manager, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset, odd.getElseSuccessor(), result, currentIndex, values); + filterExplicitVectorRec(dd, manager, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), result, currentIndex, values); + } else { + // Otherwise, we compute the ODDs for both the then- and else successors. + DdNode* thenDdNode = Cudd_T(dd); + DdNode* elseDdNode = Cudd_E(dd); + + // Determine whether we have to evaluate the successors as if they were complemented. + bool elseComplemented = Cudd_IsComplement(elseDdNode) ^ complement; + bool thenComplemented = Cudd_IsComplement(thenDdNode) ^ complement; + + filterExplicitVectorRec(Cudd_Regular(elseDdNode), manager, currentLevel + 1, elseComplemented, maxLevel, ddVariableIndices, currentOffset, odd.getElseSuccessor(), result, currentIndex, values); + filterExplicitVectorRec(Cudd_Regular(thenDdNode), manager, currentLevel + 1, thenComplemented, maxLevel, ddVariableIndices, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), result, currentIndex, values); + } + } + + template InternalBdd<DdType::CUDD> InternalBdd<DdType::CUDD>::fromVector(InternalDdManager<DdType::CUDD> const* ddManager, std::vector<double> const& values, Odd const& odd, std::vector<uint_fast64_t> const& sortedDdVariableIndices, std::function<bool (double const&)> const& filter); + template InternalBdd<DdType::CUDD> InternalBdd<DdType::CUDD>::fromVector(InternalDdManager<DdType::CUDD> const* ddManager, std::vector<uint_fast64_t> const& values, Odd const& odd, std::vector<uint_fast64_t> const& sortedDdVariableIndices, std::function<bool (uint_fast64_t const&)> const& filter); template InternalAdd<DdType::CUDD, double> InternalBdd<DdType::CUDD>::toAdd() const; template InternalAdd<DdType::CUDD, uint_fast64_t> InternalBdd<DdType::CUDD>::toAdd() const; + + template void InternalBdd<DdType::CUDD>::filterExplicitVectorRec<double>(DdNode* dd, Cudd const& manager, uint_fast64_t currentLevel, bool complement, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices, uint_fast64_t currentOffset, storm::dd::Odd const& odd, std::vector<double>& result, uint_fast64_t& currentIndex, std::vector<double> const& values); + template void InternalBdd<DdType::CUDD>::filterExplicitVectorRec<uint_fast64_t>(DdNode* dd, Cudd const& manager, uint_fast64_t currentLevel, bool complement, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices, uint_fast64_t currentOffset, storm::dd::Odd const& odd, std::vector<uint_fast64_t>& result, uint_fast64_t& currentIndex, std::vector<uint_fast64_t> const& values); + + template void InternalBdd<DdType::CUDD>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<double> const& sourceValues, std::vector<double>& targetValues) const; + template void InternalBdd<DdType::CUDD>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<uint_fast64_t> const& sourceValues, std::vector<uint_fast64_t>& targetValues) const; } } \ No newline at end of file diff --git a/src/storage/dd/cudd/InternalCuddBdd.h b/src/storage/dd/cudd/InternalCuddBdd.h index daf77db9b..7f74f0b79 100644 --- a/src/storage/dd/cudd/InternalCuddBdd.h +++ b/src/storage/dd/cudd/InternalCuddBdd.h @@ -2,6 +2,7 @@ #define STORM_STORAGE_DD_CUDD_INTERNALCUDDBDD_H_ #include <set> +#include <unordered_map> #include "src/storage/dd/DdType.h" #include "src/storage/dd/InternalBdd.h" @@ -30,14 +31,12 @@ namespace storm { template<DdType LibraryType, typename ValueType> class InternalAdd; - template<storm::dd::DdType LibraryType> class Odd; template<> class InternalBdd<DdType::CUDD> { public: friend class InternalAdd<DdType::CUDD, double>; - friend class Odd<DdType::CUDD>; /*! * Creates a DD that encapsulates the given CUDD ADD. @@ -66,7 +65,7 @@ namespace storm { * @return The resulting BDD. */ template<typename ValueType> - static InternalBdd<storm::dd::DdType::CUDD> fromVector(InternalDdManager<DdType::CUDD> const* ddManager, std::vector<ValueType> const& values, Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& sortedDdVariableIndices, std::function<bool (ValueType const&)> const& filter); + static InternalBdd<storm::dd::DdType::CUDD> fromVector(InternalDdManager<DdType::CUDD> const* ddManager, std::vector<ValueType> const& values, Odd const& odd, std::vector<uint_fast64_t> const& sortedDdVariableIndices, std::function<bool (ValueType const&)> const& filter); /*! * Retrieves whether the two BDDs represent the same function. @@ -289,7 +288,17 @@ namespace storm { * @param rowOdd The ODD used for determining the correct row. * @return The bit vector that is represented by this BDD. */ - storm::storage::BitVector toVector(storm::dd::Odd<DdType::CUDD> const& rowOdd, std::vector<uint_fast64_t> const& ddVariableIndices) const; + storm::storage::BitVector toVector(storm::dd::Odd const& rowOdd, std::vector<uint_fast64_t> const& ddVariableIndices) const; + + /*! + * Creates an ODD based on the current BDD. + * + * @return The corresponding ODD. + */ + Odd createOdd(std::vector<uint_fast64_t> const& ddVariableIndices) const; + + template<typename ValueType> + void filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<ValueType> const& sourceValues, std::vector<ValueType>& targetValues) const; private: /*! @@ -305,7 +314,7 @@ namespace storm { * @return The resulting (CUDD) BDD node. */ template<typename ValueType> - static DdNode* fromVectorRec(::DdManager* manager, uint_fast64_t& currentOffset, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector<ValueType> const& values, Odd<DdType::CUDD> const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::function<bool (ValueType const&)> const& filter); + static DdNode* fromVectorRec(::DdManager* manager, uint_fast64_t& currentOffset, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector<ValueType> const& values, Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices, std::function<bool (ValueType const&)> const& filter); /*! * Helper function to convert the DD into a bit vector. @@ -320,7 +329,45 @@ namespace storm { * @param currentRowOffset The current row offset. * @param ddRowVariableIndices The (sorted) indices of all DD row variables that need to be considered. */ - void toVectorRec(DdNode const* dd, Cudd const& manager, storm::storage::BitVector& result, Odd<DdType::CUDD> const& rowOdd, bool complement, uint_fast64_t currentRowLevel, uint_fast64_t maxLevel, uint_fast64_t currentRowOffset, std::vector<uint_fast64_t> const& ddRowVariableIndices) const; + void toVectorRec(DdNode const* dd, Cudd const& manager, storm::storage::BitVector& result, Odd const& rowOdd, bool complement, uint_fast64_t currentRowLevel, uint_fast64_t maxLevel, uint_fast64_t currentRowOffset, std::vector<uint_fast64_t> const& ddRowVariableIndices) const; + + // Declare a hash functor that is used for the unique tables in the construction process of ODDs. + class HashFunctor { + public: + std::size_t operator()(std::pair<DdNode*, bool> const& key) const; + }; + + /*! + * Recursively builds the ODD from a BDD (that potentially has complement edges). + * + * @param dd The DD for which to build the ODD. + * @param manager The manager responsible for the DD. + * @param currentLevel The currently considered level in the DD. + * @param complement A flag indicating whether or not the given node is to be considered as complemented. + * @param maxLevel The number of levels that need to be considered. + * @param ddVariableIndices The (sorted) indices of all DD variables that need to be considered. + * @param uniqueTableForLevels A vector of unique tables, one for each level to be considered, that keeps + * ODD nodes for the same DD and level unique. + * @return A pointer to the constructed ODD for the given arguments. + */ + static std::shared_ptr<Odd> createOddRec(DdNode* dd, Cudd const& manager, uint_fast64_t currentLevel, bool complement, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices, std::vector<std::unordered_map<std::pair<DdNode*, bool>, std::shared_ptr<Odd>, HashFunctor>>& uniqueTableForLevels); + + /*! + * Adds the selected values the target vector. + * + * @param dd The current node of the DD representing the selected values. + * @param manager The manager responsible for the DD. + * @param currentLevel The currently considered level in the DD. + * @param maxLevel The number of levels that need to be considered. + * @param ddVariableIndices The sorted list of variable indices to use. + * @param currentOffset The offset along the path taken in the DD representing the selected values. + * @param odd The current ODD node. + * @param result The target vector to which to write the values. + * @param currentIndex The index at which the next element is to be written. + * @param values The value vector from which to select the values. + */ + template<typename ValueType> + static void filterExplicitVectorRec(DdNode* dd, Cudd const& manager, uint_fast64_t currentLevel, bool complement, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices, uint_fast64_t currentOffset, storm::dd::Odd const& odd, std::vector<ValueType>& result, uint_fast64_t& currentIndex, std::vector<ValueType> const& values); /*! * Retrieves the CUDD BDD object associated with this DD. diff --git a/src/storage/dd/cudd/InternalCuddDdManager.h b/src/storage/dd/cudd/InternalCuddDdManager.h index 7e3b2e655..e56bad54d 100644 --- a/src/storage/dd/cudd/InternalCuddDdManager.h +++ b/src/storage/dd/cudd/InternalCuddDdManager.h @@ -17,14 +17,10 @@ namespace storm { template<DdType LibraryType> class InternalBdd; - template<DdType LibraryType> - class Odd; - template<> class InternalDdManager<DdType::CUDD> { public: friend class InternalBdd<DdType::CUDD>; - friend class Odd<DdType::CUDD>; template<DdType LibraryType, typename ValueType> friend class InternalAdd; diff --git a/test/functional/storage/CuddDdTest.cpp b/test/functional/storage/CuddDdTest.cpp index d4b578664..03ef4f304 100644 --- a/test/functional/storage/CuddDdTest.cpp +++ b/test/functional/storage/CuddDdTest.cpp @@ -3,7 +3,7 @@ #include "src/exceptions/InvalidArgumentException.h" #include "src/storage/dd/DdManager.h" #include "src/storage/dd/Add.h" -#include "src/storage/dd/cudd/CuddOdd.h" +#include "src/storage/dd/Odd.h" #include "src/storage/dd/DdMetaVariable.h" #include "src/settings/SettingsManager.h" @@ -323,8 +323,8 @@ TEST(CuddDd, AddOddTest) { std::pair<storm::expressions::Variable, storm::expressions::Variable> x = manager->addMetaVariable("x", 1, 9); storm::dd::Add<storm::dd::DdType::CUDD, double> dd = manager->template getIdentity<double>(x.first); - storm::dd::Odd<storm::dd::DdType::CUDD> odd; - ASSERT_NO_THROW(odd = storm::dd::Odd<storm::dd::DdType::CUDD>(dd)); + storm::dd::Odd odd; + ASSERT_NO_THROW(odd = dd.createOdd()); EXPECT_EQ(9ul, odd.getTotalOffset()); EXPECT_EQ(12ul, odd.getNodeCount()); @@ -340,10 +340,10 @@ TEST(CuddDd, AddOddTest) { dd += manager->getEncoding(x.first, 1).template toAdd<double>() * manager->getRange(x.second).template toAdd<double>() + manager->getEncoding(x.second, 1).template toAdd<double>() * manager->getRange(x.first).template toAdd<double>(); // Create the ODDs. - storm::dd::Odd<storm::dd::DdType::CUDD> rowOdd; - ASSERT_NO_THROW(rowOdd = storm::dd::Odd<storm::dd::DdType::CUDD>(manager->getRange(x.first).template toAdd<double>())); - storm::dd::Odd<storm::dd::DdType::CUDD> columnOdd; - ASSERT_NO_THROW(columnOdd = storm::dd::Odd<storm::dd::DdType::CUDD>(manager->getRange(x.second).template toAdd<double>())); + storm::dd::Odd rowOdd; + ASSERT_NO_THROW(rowOdd = manager->getRange(x.first).template toAdd<double>().createOdd()); + storm::dd::Odd columnOdd; + ASSERT_NO_THROW(columnOdd = manager->getRange(x.second).template toAdd<double>().createOdd()); // Try to translate the matrix. storm::storage::SparseMatrix<double> matrix; @@ -367,8 +367,8 @@ TEST(CuddDd, BddOddTest) { std::pair<storm::expressions::Variable, storm::expressions::Variable> x = manager->addMetaVariable("x", 1, 9); storm::dd::Add<storm::dd::DdType::CUDD, double> dd = manager->template getIdentity<double>(x.first); - storm::dd::Odd<storm::dd::DdType::CUDD> odd; - ASSERT_NO_THROW(odd = storm::dd::Odd<storm::dd::DdType::CUDD>(dd)); + storm::dd::Odd odd; + ASSERT_NO_THROW(odd = dd.createOdd()); EXPECT_EQ(9ul, odd.getTotalOffset()); EXPECT_EQ(12ul, odd.getNodeCount()); @@ -386,10 +386,10 @@ TEST(CuddDd, BddOddTest) { dd += manager->getEncoding(x.first, 1).template toAdd<double>() * manager->getRange(x.second).template toAdd<double>() + manager->getEncoding(x.second, 1).template toAdd<double>() * manager->getRange(x.first).template toAdd<double>(); // Create the ODDs. - storm::dd::Odd<storm::dd::DdType::CUDD> rowOdd; - ASSERT_NO_THROW(rowOdd = storm::dd::Odd<storm::dd::DdType::CUDD>(manager->getRange(x.first))); - storm::dd::Odd<storm::dd::DdType::CUDD> columnOdd; - ASSERT_NO_THROW(columnOdd = storm::dd::Odd<storm::dd::DdType::CUDD>(manager->getRange(x.second))); + storm::dd::Odd rowOdd; + ASSERT_NO_THROW(rowOdd = manager->getRange(x.first).createOdd()); + storm::dd::Odd columnOdd; + ASSERT_NO_THROW(columnOdd = manager->getRange(x.second).createOdd()); // Try to translate the matrix. storm::storage::SparseMatrix<double> matrix;