You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

545 lines
29 KiB

#include "storm/storage/dd/DdManager.h"
#include "storm/storage/expressions/ExpressionManager.h"
#include "storm/utility/macros.h"
#include "storm/utility/constants.h"
#include "storm/exceptions/InvalidArgumentException.h"
#include "storm/exceptions/NotSupportedException.h"
#include "storm/exceptions/InvalidOperationException.h"
#include "storm-config.h"
#include "storm/adapters/RationalFunctionAdapter.h"
#include <cmath>
#include <iostream>
namespace storm {
namespace dd {
template<DdType LibraryType>
DdManager<LibraryType>::DdManager() : internalDdManager(), metaVariableMap(), manager(new storm::expressions::ExpressionManager()) {
// Intentionally left empty.
}
template<DdType LibraryType>
std::shared_ptr<DdManager<LibraryType>> DdManager<LibraryType>::asSharedPointer() {
return this->shared_from_this();
}
template<DdType LibraryType>
std::shared_ptr<DdManager<LibraryType> const> DdManager<LibraryType>::asSharedPointer() const {
return this->shared_from_this();
}
template<DdType LibraryType>
Bdd<LibraryType> DdManager<LibraryType>::getBddOne() const {
return Bdd<LibraryType>(*this, internalDdManager.getBddOne());
}
template<DdType LibraryType>
template<typename ValueType>
Add<LibraryType, ValueType> DdManager<LibraryType>::getAddOne() const {
return Add<LibraryType, ValueType>(*this, internalDdManager.template getAddOne<ValueType>());
}
template<DdType LibraryType>
Bdd<LibraryType> DdManager<LibraryType>::getBddZero() const {
return Bdd<LibraryType>(*this, internalDdManager.getBddZero());
}
template<DdType LibraryType>
template<typename ValueType>
Add<LibraryType, ValueType> DdManager<LibraryType>::getAddZero() const {
return Add<LibraryType, ValueType>(*this, internalDdManager.template getAddZero<ValueType>());
}
template<DdType LibraryType>
template<typename ValueType>
Add<LibraryType, ValueType> DdManager<LibraryType>::getAddUndefined() const {
return Add<LibraryType, ValueType>(*this, internalDdManager.template getAddUndefined<ValueType>());
}
template<DdType LibraryType>
template<typename ValueType>
Add<LibraryType, ValueType> DdManager<LibraryType>::getInfinity() const {
return getConstant(storm::utility::infinity<ValueType>());
}
template<DdType LibraryType>
template<typename ValueType>
Add<LibraryType, ValueType> DdManager<LibraryType>::getConstant(ValueType const& value) const {
return Add<LibraryType, ValueType>(*this, internalDdManager.getConstant(value));
}
template<DdType LibraryType>
Bdd<LibraryType> DdManager<LibraryType>::getEncoding(storm::expressions::Variable const& variable, int_fast64_t value, bool mostSignificantBitAtTop) const {
DdMetaVariable<LibraryType> const& metaVariable = this->getMetaVariable(variable);
STORM_LOG_THROW(metaVariable.canRepresent(value), storm::exceptions::InvalidArgumentException, "Illegal value " << value << " for meta variable '" << variable.getName() << "'.");
// Now compute the encoding relative to the low value of the meta variable.
value -= metaVariable.getLow();
std::vector<Bdd<LibraryType>> const& ddVariables = metaVariable.getDdVariables();
Bdd<LibraryType> result;
if (mostSignificantBitAtTop) {
if (value & (1ull << (ddVariables.size() - 1))) {
result = ddVariables[0];
} else {
result = !ddVariables[0];
}
for (std::size_t i = 1; i < ddVariables.size(); ++i) {
if (value & (1ull << (ddVariables.size() - i - 1))) {
result &= ddVariables[i];
} else {
result &= !ddVariables[i];
}
}
} else {
if (value & 1ull) {
result = ddVariables[0];
} else {
result = !ddVariables[0];
}
value >>= 1;
for (std::size_t i = 1; i < ddVariables.size(); ++i) {
if (value & 1ull) {
result &= ddVariables[i];
} else {
result &= !ddVariables[i];
}
value >>= 1;
}
}
return result;
}
template<DdType LibraryType>
Bdd<LibraryType> DdManager<LibraryType>::getRange(storm::expressions::Variable const& variable) const {
storm::dd::DdMetaVariable<LibraryType> const& metaVariable = this->getMetaVariable(variable);
if (metaVariable.hasHigh()) {
return Bdd<LibraryType>(*this, internalDdManager.getBddEncodingLessOrEqualThan(static_cast<uint64_t>(metaVariable.getHigh() - metaVariable.getLow()), metaVariable.getCube().getInternalBdd(), metaVariable.getNumberOfDdVariables()), {variable});
// Bdd<LibraryType> result = this->getBddZero();
// for (int_fast64_t value = metaVariable.getLow(); value <= metaVariable.getHigh(); ++value) {
// result |= this->getEncoding(variable, value);
// }
// return result;
} else {
// If there is no upper bound on this variable, the whole range is valid.
Bdd<LibraryType> result = this->getBddOne();
result.addMetaVariable(variable);
return result;
}
}
template<DdType LibraryType>
template<typename ValueType>
Add<LibraryType, ValueType> DdManager<LibraryType>::getIdentity(storm::expressions::Variable const& variable) const {
storm::dd::DdMetaVariable<LibraryType> const& metaVariable = this->getMetaVariable(variable);
STORM_LOG_THROW(metaVariable.hasHigh(), storm::exceptions::InvalidOperationException, "Cannot create identity for meta variable.");
Add<LibraryType, ValueType> result = this->getAddZero<ValueType>();
for (int_fast64_t value = metaVariable.getLow(); value <= metaVariable.getHigh(); ++value) {
result += this->getEncoding(variable, value).template toAdd<ValueType>() * this->getConstant(storm::utility::convertNumber<ValueType>(value));
}
return result;
}
template<DdType LibraryType>
Bdd<LibraryType> DdManager<LibraryType>::getIdentity(std::vector<std::pair<storm::expressions::Variable, storm::expressions::Variable>> const& variablePairs, bool restrictToFirstRange) const {
auto result = this->getBddOne();
for (auto const& pair : variablePairs) {
result &= this->getIdentity(pair.first, pair.second, restrictToFirstRange);
}
return result;
}
template<DdType LibraryType>
Bdd<LibraryType> DdManager<LibraryType>::getIdentity(storm::expressions::Variable const& first, storm::expressions::Variable const& second, bool restrictToFirstRange) const {
auto const& firstMetaVariable = this->getMetaVariable(first);
auto const& secondMetaVariable = this->getMetaVariable(second);
STORM_LOG_THROW(firstMetaVariable.getNumberOfDdVariables() == secondMetaVariable.getNumberOfDdVariables(), storm::exceptions::InvalidOperationException, "Mismatching sizes of meta variables.");
auto const& firstDdVariables = firstMetaVariable.getDdVariables();
auto const& secondDdVariables = secondMetaVariable.getDdVariables();
auto result = restrictToFirstRange ? this->getRange(first) : this->getBddOne();
for (auto it1 = firstDdVariables.begin(), it2 = secondDdVariables.begin(), ite1 = firstDdVariables.end(); it1 != ite1; ++it1, ++it2) {
result &= it1->iff(*it2);
}
return result;
}
template<DdType LibraryType>
Bdd<LibraryType> DdManager<LibraryType>::getCube(storm::expressions::Variable const& variable) const {
return getCube({variable});
}
template<DdType LibraryType>
Bdd<LibraryType> DdManager<LibraryType>::getCube(std::set<storm::expressions::Variable> const& variables) const {
Bdd<LibraryType> result = this->getBddOne();
for (auto const& variable : variables) {
storm::dd::DdMetaVariable<LibraryType> const& metaVariable = this->getMetaVariable(variable);
result &= metaVariable.getCube();
}
return result;
}
template<DdType LibraryType>
std::vector<storm::expressions::Variable> DdManager<LibraryType>::cloneVariable(storm::expressions::Variable const& variable, std::string const& newMetaVariableName, boost::optional<uint64_t> const& numberOfLayers) {
std::vector<storm::expressions::Variable> newMetaVariables;
auto const& ddMetaVariable = this->getMetaVariable(variable);
if (ddMetaVariable.getType() == storm::dd::MetaVariableType::Bool) {
newMetaVariables = this->addMetaVariable(newMetaVariableName, 3);
} else if (ddMetaVariable.getType() == storm::dd::MetaVariableType::Int) {
newMetaVariables = this->addMetaVariable(newMetaVariableName, ddMetaVariable.getLow(), ddMetaVariable.getHigh(), 3);
} else if (ddMetaVariable.getType() == storm::dd::MetaVariableType::BitVector) {
newMetaVariables = this->addBitVectorMetaVariable(newMetaVariableName, ddMetaVariable.getNumberOfDdVariables(), 3);
}
return newMetaVariables;
}
template<DdType LibraryType>
std::pair<storm::expressions::Variable, storm::expressions::Variable> DdManager<LibraryType>::addMetaVariable(std::string const& name, int_fast64_t low, int_fast64_t high, boost::optional<std::pair<MetaVariablePosition, storm::expressions::Variable>> const& position) {
std::vector<storm::expressions::Variable> result = addMetaVariable(name, low, high, 2, position);
return std::make_pair(result[0], result[1]);
}
template<DdType LibraryType>
std::vector<storm::expressions::Variable> DdManager<LibraryType>::addMetaVariable(std::string const& name, int_fast64_t low, int_fast64_t high, uint64_t numberOfLayers, boost::optional<std::pair<MetaVariablePosition, storm::expressions::Variable>> const& position) {
return this->addMetaVariableHelper(MetaVariableType::Int, name, std::max(static_cast<uint64_t>(std::ceil(std::log2(high - low + 1))), 1ull), numberOfLayers, position, std::make_pair(low, high));
}
template<DdType LibraryType>
std::vector<storm::expressions::Variable> DdManager<LibraryType>::addBitVectorMetaVariable(std::string const& variableName, uint64_t bits, uint64_t numberOfLayers, boost::optional<std::pair<MetaVariablePosition, storm::expressions::Variable>> const& position) {
return this->addMetaVariableHelper(MetaVariableType::BitVector, variableName, bits, numberOfLayers, position);
}
template<DdType LibraryType>
std::pair<storm::expressions::Variable, storm::expressions::Variable> DdManager<LibraryType>::addMetaVariable(std::string const& name, boost::optional<std::pair<MetaVariablePosition, storm::expressions::Variable>> const& position) {
std::vector<storm::expressions::Variable> result = this->addMetaVariableHelper(MetaVariableType::Bool, name, 1, 2, position);
return std::make_pair(result[0], result[1]);
}
template<DdType LibraryType>
std::vector<storm::expressions::Variable> DdManager<LibraryType>::addMetaVariable(std::string const& name, uint64_t numberOfLayers, boost::optional<std::pair<MetaVariablePosition, storm::expressions::Variable>> const& position) {
return this->addMetaVariableHelper(MetaVariableType::Bool, name, 1, numberOfLayers, position);
}
template<DdType LibraryType>
std::vector<storm::expressions::Variable> DdManager<LibraryType>::addMetaVariableHelper(MetaVariableType const& type, std::string const& name, uint64_t numberOfDdVariables, uint64_t numberOfLayers, boost::optional<std::pair<MetaVariablePosition, storm::expressions::Variable>> const& position, boost::optional<std::pair<int_fast64_t, int_fast64_t>> const& bounds) {
// Check whether number of layers is legal.
STORM_LOG_THROW(numberOfLayers >= 1, storm::exceptions::InvalidArgumentException, "Layers must be at least 1.");
// Check that the number of DD variables is legal.
STORM_LOG_THROW(numberOfDdVariables >= 1, storm::exceptions::InvalidArgumentException, "Illegal number of DD variables.");
// Check whether the variable name is legal.
STORM_LOG_THROW(name != "" && name.back() != '\'', storm::exceptions::InvalidArgumentException, "Illegal name of meta variable: '" << name << "'.");
// Check whether a meta variable already exists.
STORM_LOG_THROW(!this->hasMetaVariable(name), storm::exceptions::InvalidArgumentException, "A meta variable '" << name << "' already exists.");
// If a specific position was requested, we compute it now.
boost::optional<uint_fast64_t> level;
if (position) {
storm::dd::DdMetaVariable<LibraryType> beforeVariable = this->getMetaVariable(position.get().second);
level = position.get().first == MetaVariablePosition::Above ? std::numeric_limits<uint_fast64_t>::max() : std::numeric_limits<uint_fast64_t>::min();
for (auto const& ddVariable : beforeVariable.getDdVariables()) {
level = position.get().first == MetaVariablePosition::Above ? std::min(level.get(), ddVariable.getLevel()) : std::max(level.get(), ddVariable.getLevel());
}
if (position.get().first == MetaVariablePosition::Below) {
++level.get();
}
}
STORM_LOG_TRACE("Creating meta variable with " << numberOfDdVariables << " bit(s) and " << numberOfLayers << " layer(s).");
std::stringstream tmp1;
std::vector<storm::expressions::Variable> result;
for (uint64 layer = 0; layer < numberOfLayers; ++layer) {
if (type == MetaVariableType::Int) {
result.emplace_back(manager->declareIntegerVariable(name + tmp1.str()));
} else if (type == MetaVariableType::Bool) {
result.emplace_back(manager->declareBooleanVariable(name + tmp1.str()));
} else if (type == MetaVariableType::BitVector) {
result.emplace_back(manager->declareBitVectorVariable(name + tmp1.str(), numberOfDdVariables));
}
tmp1 << "'";
}
std::vector<std::vector<Bdd<LibraryType>>> variables(numberOfLayers);
for (std::size_t i = 0; i < numberOfDdVariables; ++i) {
std::vector<InternalBdd<LibraryType>> ddVariables = internalDdManager.createDdVariables(numberOfLayers, level);
for (uint64 layer = 0; layer < numberOfLayers; ++layer) {
variables[layer].emplace_back(Bdd<LibraryType>(*this, ddVariables[layer], {result[layer]}));
}
// If we are inserting the variable at a specific level, we need to prepare the level for the next pair
// of variables.
if (level) {
level.get() += numberOfLayers;
}
}
std::stringstream tmp2;
for (uint64_t layer = 0; layer < numberOfLayers; ++layer) {
if (bounds) {
metaVariableMap.emplace(result[layer], DdMetaVariable<LibraryType>(name + tmp2.str(), bounds.get().first, bounds.get().second, variables[layer]));
} else {
metaVariableMap.emplace(result[layer], DdMetaVariable<LibraryType>(type, name + tmp2.str(), variables[layer]));
}
tmp2 << "'";
}
return result;
}
template<DdType LibraryType>
DdMetaVariable<LibraryType> const& DdManager<LibraryType>::getMetaVariable(storm::expressions::Variable const& variable) const {
auto const& variablePair = metaVariableMap.find(variable);
// Check whether the meta variable exists.
STORM_LOG_THROW(variablePair != metaVariableMap.end(), storm::exceptions::InvalidArgumentException, "Unknown meta variable name '" << variable.getName() << "'.");
return variablePair->second;
}
template<DdType LibraryType>
std::set<std::string> DdManager<LibraryType>::getAllMetaVariableNames() const {
std::set<std::string> result;
for (auto const& variablePair : metaVariableMap) {
result.insert(variablePair.first.getName());
}
return result;
}
template<DdType LibraryType>
std::size_t DdManager<LibraryType>::getNumberOfMetaVariables() const {
return this->metaVariableMap.size();
}
template<DdType LibraryType>
bool DdManager<LibraryType>::hasMetaVariable(std::string const& metaVariableName) const {
return manager->hasVariable(metaVariableName);
}
template<DdType LibraryType>
storm::expressions::Variable DdManager<LibraryType>::getMetaVariable(std::string const& metaVariableName) const {
// Check whether the meta variable exists.
STORM_LOG_THROW(hasMetaVariable(metaVariableName), storm::exceptions::InvalidArgumentException, "Unknown meta variable name '" << metaVariableName << "'.");
return manager->getVariable(metaVariableName);
}
template<DdType LibraryType>
bool DdManager<LibraryType>::supportsOrderedInsertion() const {
return internalDdManager.supportsOrderedInsertion();
}
template<DdType LibraryType>
storm::expressions::ExpressionManager const& DdManager<LibraryType>::getExpressionManager() const {
return *manager;
}
template<DdType LibraryType>
storm::expressions::ExpressionManager& DdManager<LibraryType>::getExpressionManager() {
return *manager;
}
template<DdType LibraryType>
std::vector<std::string> DdManager<LibraryType>::getDdVariableNames() const {
// First, we initialize a list DD variables and their names.
std::vector<std::pair<uint_fast64_t, std::string>> variablePairs;
for (auto const& variablePair : this->metaVariableMap) {
DdMetaVariable<LibraryType> const& metaVariable = variablePair.second;
// If the meta variable is of type bool, we don't need to suffix it with the bit number.
if (metaVariable.getType() == MetaVariableType::Bool) {
variablePairs.emplace_back(metaVariable.getDdVariables().front().getIndex(), variablePair.first.getName());
} else {
// For integer-valued meta variables, we, however, have to add the suffix.
for (uint_fast64_t variableIndex = 0; variableIndex < metaVariable.getNumberOfDdVariables(); ++variableIndex) {
variablePairs.emplace_back(metaVariable.getDdVariables()[variableIndex].getIndex(), variablePair.first.getName() + '.' + std::to_string(variableIndex));
}
}
}
// Then, we sort this list according to the indices of the ADDs.
std::sort(variablePairs.begin(), variablePairs.end(), [](std::pair<uint_fast64_t, std::string> const& a, std::pair<uint_fast64_t, std::string> const& b) { return a.first < b.first; });
// Now, we project the sorted vector to its second component.
std::vector<std::string> result;
for (auto const& element : variablePairs) {
result.push_back(element.second);
}
return result;
}
template<DdType LibraryType>
std::vector<storm::expressions::Variable> DdManager<LibraryType>::getDdVariables() const {
// First, we initialize a list DD variables and their names.
std::vector<std::pair<uint_fast64_t, storm::expressions::Variable>> variablePairs;
for (auto const& variablePair : this->metaVariableMap) {
DdMetaVariable<LibraryType> const& metaVariable = variablePair.second;
// If the meta variable is of type bool, we don't need to suffix it with the bit number.
if (metaVariable.getType() == MetaVariableType::Bool) {
variablePairs.emplace_back(metaVariable.getDdVariables().front().getIndex(), variablePair.first);
} else {
// For integer-valued meta variables, we, however, have to add the suffix.
for (uint_fast64_t variableIndex = 0; variableIndex < metaVariable.getNumberOfDdVariables(); ++variableIndex) {
variablePairs.emplace_back(metaVariable.getDdVariables()[variableIndex].getIndex(), variablePair.first);
}
}
}
// Then, we sort this list according to the indices of the ADDs.
std::sort(variablePairs.begin(), variablePairs.end(), [](std::pair<uint_fast64_t, storm::expressions::Variable> const& a, std::pair<uint_fast64_t, storm::expressions::Variable> const& b) { return a.first < b.first; });
// Now, we project the sorted vector to its second component.
std::vector<storm::expressions::Variable> result;
for (auto const& element : variablePairs) {
result.push_back(element.second);
}
return result;
}
template<DdType LibraryType>
void DdManager<LibraryType>::allowDynamicReordering(bool value) {
internalDdManager.allowDynamicReordering(value);
}
template<DdType LibraryType>
bool DdManager<LibraryType>::isDynamicReorderingAllowed() const {
return internalDdManager.isDynamicReorderingAllowed();
}
template<DdType LibraryType>
void DdManager<LibraryType>::triggerReordering() {
internalDdManager.triggerReordering();
}
template<DdType LibraryType>
std::set<storm::expressions::Variable> DdManager<LibraryType>::getAllMetaVariables() const {
std::set<storm::expressions::Variable> result;
for (auto const& variable : this->metaVariableMap) {
result.insert(variable.first);
}
return result;
}
template<DdType LibraryType>
std::vector<uint_fast64_t> DdManager<LibraryType>::getSortedVariableIndices() const {
return this->getSortedVariableIndices(this->getAllMetaVariables());
}
template<DdType LibraryType>
std::vector<uint_fast64_t> DdManager<LibraryType>::getSortedVariableIndices(std::set<storm::expressions::Variable> const& metaVariables) const {
std::vector<uint_fast64_t> ddVariableIndices;
for (auto const& metaVariable : metaVariables) {
for (auto const& ddVariable : metaVariableMap.at(metaVariable).getDdVariables()) {
ddVariableIndices.push_back(ddVariable.getIndex());
}
}
// Next, we need to sort them, since they may be arbitrarily ordered otherwise.
std::sort(ddVariableIndices.begin(), ddVariableIndices.end());
return ddVariableIndices;
}
template<DdType LibraryType>
InternalDdManager<LibraryType>& DdManager<LibraryType>::getInternalDdManager() {
return internalDdManager;
}
template<DdType LibraryType>
InternalDdManager<LibraryType> const& DdManager<LibraryType>::getInternalDdManager() const {
return internalDdManager;
}
template<DdType LibraryType>
InternalDdManager<LibraryType>* DdManager<LibraryType>::getInternalDdManagerPointer() {
return &internalDdManager;
}
template<DdType LibraryType>
InternalDdManager<LibraryType> const* DdManager<LibraryType>::getInternalDdManagerPointer() const {
return &internalDdManager;
}
template<DdType LibraryType>
void DdManager<LibraryType>::debugCheck() const {
internalDdManager.debugCheck();
}
template class DdManager<DdType::CUDD>;
template Add<DdType::CUDD, double> DdManager<DdType::CUDD>::getAddZero() const;
template Add<DdType::CUDD, uint_fast64_t> DdManager<DdType::CUDD>::getAddZero() const;
template Add<DdType::CUDD, double> DdManager<DdType::CUDD>::getAddOne() const;
template Add<DdType::CUDD, uint_fast64_t> DdManager<DdType::CUDD>::getAddOne() const;
template Add<DdType::CUDD, double> DdManager<DdType::CUDD>::getInfinity<double>() const;
template Add<DdType::CUDD, uint_fast64_t> DdManager<DdType::CUDD>::getInfinity<uint_fast64_t>() const;
template Add<DdType::CUDD, double> DdManager<DdType::CUDD>::getConstant(double const& value) const;
template Add<DdType::CUDD, uint_fast64_t> DdManager<DdType::CUDD>::getConstant(uint_fast64_t const& value) const;
template Add<DdType::CUDD, double> DdManager<DdType::CUDD>::getIdentity(storm::expressions::Variable const& variable) const;
template Add<DdType::CUDD, uint_fast64_t> DdManager<DdType::CUDD>::getIdentity(storm::expressions::Variable const& variable) const;
template class DdManager<DdType::Sylvan>;
template Add<DdType::Sylvan, double> DdManager<DdType::Sylvan>::getAddZero() const;
template Add<DdType::Sylvan, uint_fast64_t> DdManager<DdType::Sylvan>::getAddZero() const;
#ifdef STORM_HAVE_CARL
template Add<DdType::Sylvan, storm::RationalNumber> DdManager<DdType::Sylvan>::getAddZero() const;
template Add<DdType::Sylvan, storm::RationalFunction> DdManager<DdType::Sylvan>::getAddZero() const;
#endif
template Add<DdType::Sylvan, double> DdManager<DdType::Sylvan>::getAddUndefined() const;
template Add<DdType::Sylvan, uint_fast64_t> DdManager<DdType::Sylvan>::getAddUndefined() const;
#ifdef STORM_HAVE_CARL
template Add<DdType::Sylvan, storm::RationalNumber> DdManager<DdType::Sylvan>::getAddUndefined() const;
template Add<DdType::Sylvan, storm::RationalFunction> DdManager<DdType::Sylvan>::getAddUndefined() const;
#endif
template Add<DdType::Sylvan, double> DdManager<DdType::Sylvan>::getAddOne() const;
template Add<DdType::Sylvan, uint_fast64_t> DdManager<DdType::Sylvan>::getAddOne() const;
#ifdef STORM_HAVE_CARL
template Add<DdType::Sylvan, storm::RationalNumber> DdManager<DdType::Sylvan>::getAddOne() const;
template Add<DdType::Sylvan, storm::RationalFunction> DdManager<DdType::Sylvan>::getAddOne() const;
#endif
template Add<DdType::Sylvan, double> DdManager<DdType::Sylvan>::getInfinity<double>() const;
template Add<DdType::Sylvan, uint_fast64_t> DdManager<DdType::Sylvan>::getInfinity<uint_fast64_t>() const;
#ifdef STORM_HAVE_CARL
template Add<DdType::Sylvan, storm::RationalNumber> DdManager<DdType::Sylvan>::getInfinity<storm::RationalNumber>() const;
template Add<DdType::Sylvan, storm::RationalFunction> DdManager<DdType::Sylvan>::getInfinity<storm::RationalFunction>() const;
#endif
template Add<DdType::Sylvan, double> DdManager<DdType::Sylvan>::getConstant(double const& value) const;
template Add<DdType::Sylvan, uint_fast64_t> DdManager<DdType::Sylvan>::getConstant(uint_fast64_t const& value) const;
#ifdef STORM_HAVE_CARL
template Add<DdType::Sylvan, storm::RationalNumber> DdManager<DdType::Sylvan>::getConstant(storm::RationalNumber const& value) const;
template Add<DdType::Sylvan, storm::RationalFunction> DdManager<DdType::Sylvan>::getConstant(storm::RationalFunction const& value) const;
#endif
template Add<DdType::Sylvan, double> DdManager<DdType::Sylvan>::getIdentity(storm::expressions::Variable const& variable) const;
template Add<DdType::Sylvan, uint_fast64_t> DdManager<DdType::Sylvan>::getIdentity(storm::expressions::Variable const& variable) const;
#ifdef STORM_HAVE_CARL
template Add<DdType::Sylvan, storm::RationalNumber> DdManager<DdType::Sylvan>::getIdentity(storm::expressions::Variable const& variable) const;
template Add<DdType::Sylvan, storm::RationalFunction> DdManager<DdType::Sylvan>::getIdentity(storm::expressions::Variable const& variable) const;
#endif
}
}