Browse Source

restructured ODD to be independent of the DD library being used

Former-commit-id: 83f08ba203
main
dehnert 10 years ago
parent
commit
a258d1ab48
  1. 19
      src/modelchecker/csl/helper/HybridCtmcCslHelper.cpp
  2. 4
      src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp
  3. 2
      src/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp
  4. 12
      src/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp
  5. 12
      src/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp
  6. 10
      src/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp
  7. 1
      src/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp
  8. 10
      src/modelchecker/results/HybridQuantitativeCheckResult.cpp
  9. 8
      src/modelchecker/results/HybridQuantitativeCheckResult.h
  10. 29
      src/storage/dd/Add.cpp
  11. 30
      src/storage/dd/Add.h
  12. 27
      src/storage/dd/Bdd.cpp
  13. 26
      src/storage/dd/Bdd.h
  14. 4
      src/storage/dd/Dd.h
  15. 4
      src/storage/dd/DdManager.h
  16. 144
      src/storage/dd/Odd.cpp
  17. 145
      src/storage/dd/Odd.h
  18. 332
      src/storage/dd/cudd/CuddOdd.cpp
  19. 235
      src/storage/dd/cudd/CuddOdd.h
  20. 291
      src/storage/dd/cudd/InternalCuddAdd.cpp
  21. 48
      src/storage/dd/cudd/InternalCuddAdd.h
  22. 133
      src/storage/dd/cudd/InternalCuddBdd.cpp
  23. 59
      src/storage/dd/cudd/InternalCuddBdd.h
  24. 4
      src/storage/dd/cudd/InternalCuddDdManager.h
  25. 26
      test/functional/storage/CuddDdTest.cpp

19
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);

4
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);

2
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"

12
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>();

12
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>();

10
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>();

1
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"

10
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;
}

8
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;

29
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 {

30
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;

27
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;
}
}

26
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;

4
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;

4
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;

144
src/storage/dd/Odd.cpp

@ -1 +1,143 @@
#include "src/storage/dd/Odd.h"
#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);
}
}
}
}

145
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;
};
}
}

332
src/storage/dd/cudd/CuddOdd.cpp

@ -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);
}
}

235
src/storage/dd/cudd/CuddOdd.h

@ -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_ */

291
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

48
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;

133
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;
}
}

59
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.

4
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;

26
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;

|||||||
100:0
Loading…
Cancel
Save