#include "storm/storage/dd/sylvan/InternalSylvanAdd.h" #include "storm/storage/dd/sylvan/SylvanAddIterator.h" #include "storm/storage/dd/sylvan/InternalSylvanDdManager.h" #include "storm/storage/dd/DdManager.h" #include "storm/storage/SparseMatrix.h" #include "storm/storage/BitVector.h" #include "storm/utility/macros.h" #include "storm/utility/constants.h" #include "storm/exceptions/NotImplementedException.h" #include "storm/exceptions/InvalidOperationException.h" #include "storm/exceptions/NotSupportedException.h" #include "storm-config.h" namespace storm { namespace dd { template InternalAdd::InternalAdd() : ddManager(nullptr), sylvanMtbdd() { // Intentionally left empty. } template InternalAdd::InternalAdd(InternalDdManager const* ddManager, sylvan::Mtbdd const& sylvanMtbdd) : ddManager(ddManager), sylvanMtbdd(sylvanMtbdd) { // Intentionally left empty. } template ValueType InternalAdd::getValue(MTBDD const& node) { STORM_LOG_ASSERT(mtbdd_isleaf(node), "Expected leaf, but got variable " << mtbdd_getvar(node) << "."); bool negated = mtbdd_hascomp(node); MTBDD n = mtbdd_regular(node); if (std::is_same::value) { STORM_LOG_ASSERT(mtbdd_gettype(n) == 1, "Expected a double value."); return negated ? -mtbdd_getdouble(n) : mtbdd_getdouble(n); } else if (std::is_same::value) { STORM_LOG_ASSERT(mtbdd_gettype(node) == 0, "Expected an unsigned value."); return negated ? -mtbdd_getint64(node) : mtbdd_getint64(node); } #ifdef STORM_HAVE_CARL else if (std::is_same::value) { STORM_LOG_ASSERT(false, "Non-specialized version of getValue() called for storm::RationalFunction value."); } #endif else { STORM_LOG_ASSERT(false, "Illegal or unknown type in MTBDD."); } } template<> storm::RationalNumber InternalAdd::getValue(MTBDD const& node) { STORM_LOG_ASSERT(mtbdd_isleaf(node), "Expected leaf, but got variable " << mtbdd_getvar(node) << "."); bool negated = mtbdd_hascomp(node); STORM_LOG_ASSERT(mtbdd_gettype(node) == sylvan_storm_rational_number_get_type(), "Expected a storm::RationalNumber value."); storm_rational_number_ptr ptr = (storm_rational_number_ptr)mtbdd_getstorm_rational_number_ptr(node); storm::RationalNumber* rationalNumber = (storm::RationalNumber*)(ptr); return negated ? -(*rationalNumber) : (*rationalNumber); } #ifdef STORM_HAVE_CARL template<> storm::RationalFunction InternalAdd::getValue(MTBDD const& node) { STORM_LOG_ASSERT(mtbdd_isleaf(node), "Expected leaf, but got variable " << mtbdd_getvar(node) << "."); bool negated = mtbdd_hascomp(node); STORM_LOG_ASSERT(mtbdd_gettype(node) == sylvan_storm_rational_function_get_type(), "Expected a storm::RationalFunction value."); uint64_t value = mtbdd_getvalue(node); storm_rational_function_ptr ptr = (storm_rational_function_ptr)value; storm::RationalFunction* rationalFunction = (storm::RationalFunction*)(ptr); return negated ? -(*rationalFunction) : (*rationalFunction); } #endif template bool InternalAdd::operator==(InternalAdd const& other) const { return this->sylvanMtbdd == other.sylvanMtbdd; } template bool InternalAdd::operator!=(InternalAdd const& other) const { return this->sylvanMtbdd != other.sylvanMtbdd; } template InternalAdd InternalAdd::operator+(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.Plus(other.sylvanMtbdd)); } template<> InternalAdd InternalAdd::operator+(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.PlusRN(other.sylvanMtbdd)); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::operator+(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.PlusRF(other.sylvanMtbdd)); } #endif template InternalAdd& InternalAdd::operator+=(InternalAdd const& other) { this->sylvanMtbdd = this->sylvanMtbdd.Plus(other.sylvanMtbdd); return *this; } template<> InternalAdd& InternalAdd::operator+=(InternalAdd const& other) { this->sylvanMtbdd = this->sylvanMtbdd.PlusRN(other.sylvanMtbdd); return *this; } #ifdef STORM_HAVE_CARL template<> InternalAdd& InternalAdd::operator+=(InternalAdd const& other) { this->sylvanMtbdd = this->sylvanMtbdd.PlusRF(other.sylvanMtbdd); return *this; } #endif template InternalAdd InternalAdd::operator*(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.Times(other.sylvanMtbdd)); } template<> InternalAdd InternalAdd::operator*(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.TimesRN(other.sylvanMtbdd)); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::operator*(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.TimesRF(other.sylvanMtbdd)); } #endif template InternalAdd& InternalAdd::operator*=(InternalAdd const& other) { this->sylvanMtbdd = this->sylvanMtbdd.Times(other.sylvanMtbdd); return *this; } template<> InternalAdd& InternalAdd::operator*=(InternalAdd const& other) { this->sylvanMtbdd = this->sylvanMtbdd.TimesRN(other.sylvanMtbdd); return *this; } #ifdef STORM_HAVE_CARL template<> InternalAdd& InternalAdd::operator*=(InternalAdd const& other) { this->sylvanMtbdd = this->sylvanMtbdd.TimesRF(other.sylvanMtbdd); return *this; } #endif template InternalAdd InternalAdd::operator-(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.Minus(other.sylvanMtbdd)); } template<> InternalAdd InternalAdd::operator-(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.MinusRN(other.sylvanMtbdd)); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::operator-(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.MinusRF(other.sylvanMtbdd)); } #endif template InternalAdd& InternalAdd::operator-=(InternalAdd const& other) { this->sylvanMtbdd = this->sylvanMtbdd.Minus(other.sylvanMtbdd); return *this; } template<> InternalAdd& InternalAdd::operator-=(InternalAdd const& other) { this->sylvanMtbdd = this->sylvanMtbdd.MinusRN(other.sylvanMtbdd); return *this; } #ifdef STORM_HAVE_CARL template<> InternalAdd& InternalAdd::operator-=(InternalAdd const& other) { this->sylvanMtbdd = this->sylvanMtbdd.MinusRF(other.sylvanMtbdd); return *this; } #endif template InternalAdd InternalAdd::operator/(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.Divide(other.sylvanMtbdd)); } template<> InternalAdd InternalAdd::operator/(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.DivideRN(other.sylvanMtbdd)); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::operator/(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.DivideRF(other.sylvanMtbdd)); } #endif template InternalAdd& InternalAdd::operator/=(InternalAdd const& other) { this->sylvanMtbdd = this->sylvanMtbdd.Divide(other.sylvanMtbdd); return *this; } template<> InternalAdd& InternalAdd::operator/=(InternalAdd const& other) { this->sylvanMtbdd = this->sylvanMtbdd.DivideRN(other.sylvanMtbdd); return *this; } #ifdef STORM_HAVE_CARL template<> InternalAdd& InternalAdd::operator/=(InternalAdd const& other) { this->sylvanMtbdd = this->sylvanMtbdd.DivideRF(other.sylvanMtbdd); return *this; } #endif template InternalBdd InternalAdd::equals(InternalAdd const& other) const { return InternalBdd(ddManager, this->sylvanMtbdd.Equals(other.sylvanMtbdd)); } template<> InternalBdd InternalAdd::equals(InternalAdd const& other) const { return InternalBdd(ddManager, this->sylvanMtbdd.EqualsRN(other.sylvanMtbdd)); } #ifdef STORM_HAVE_CARL template<> InternalBdd InternalAdd::equals(InternalAdd const& other) const { return InternalBdd(ddManager, this->sylvanMtbdd.EqualsRF(other.sylvanMtbdd)); } #endif template InternalBdd InternalAdd::notEquals(InternalAdd const& other) const { return !this->equals(other); } template InternalBdd InternalAdd::less(InternalAdd const& other) const { return InternalBdd(ddManager, this->sylvanMtbdd.Less(other.sylvanMtbdd)); } template<> InternalBdd InternalAdd::less(InternalAdd const& other) const { return InternalBdd(ddManager, this->sylvanMtbdd.LessRN(other.sylvanMtbdd)); } #ifdef STORM_HAVE_CARL template<> InternalBdd InternalAdd::less(InternalAdd const& other) const { return InternalBdd(ddManager, this->sylvanMtbdd.LessRF(other.sylvanMtbdd)); } #endif template InternalBdd InternalAdd::lessOrEqual(InternalAdd const& other) const { return InternalBdd(ddManager, this->sylvanMtbdd.LessOrEqual(other.sylvanMtbdd)); } template<> InternalBdd InternalAdd::lessOrEqual(InternalAdd const& other) const { return InternalBdd(ddManager, this->sylvanMtbdd.LessOrEqualRN(other.sylvanMtbdd)); } #ifdef STORM_HAVE_CARL template<> InternalBdd InternalAdd::lessOrEqual(InternalAdd const& other) const { return InternalBdd(ddManager, this->sylvanMtbdd.LessOrEqualRF(other.sylvanMtbdd)); } #endif template InternalBdd InternalAdd::greater(InternalAdd const& other) const { return !this->lessOrEqual(other); } template InternalBdd InternalAdd::greaterOrEqual(InternalAdd const& other) const { return !this->less(other); } template InternalAdd InternalAdd::pow(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.Pow(other.sylvanMtbdd)); } template<> InternalAdd InternalAdd::pow(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.PowRN(other.sylvanMtbdd)); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::pow(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.PowRF(other.sylvanMtbdd)); } #endif template InternalAdd InternalAdd::mod(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.Mod(other.sylvanMtbdd)); } template<> InternalAdd InternalAdd::mod(InternalAdd const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Operation (mod) not supported by rational numbers."); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::mod(InternalAdd const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Operation (mod) not supported by rational functions."); } #endif template InternalAdd InternalAdd::logxy(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.Logxy(other.sylvanMtbdd)); } template<> InternalAdd InternalAdd::logxy(InternalAdd const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Operation (logxy) not supported by rational numbers."); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::logxy(InternalAdd const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Operation (logxy) not supported by rational functions."); } #endif template InternalAdd InternalAdd::floor() const { return InternalAdd(ddManager, this->sylvanMtbdd.Floor()); } template<> InternalAdd InternalAdd::floor() const { return InternalAdd(ddManager, this->sylvanMtbdd.FloorRN()); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::floor() const { return InternalAdd(ddManager, this->sylvanMtbdd.FloorRF()); } #endif template InternalAdd InternalAdd::ceil() const { return InternalAdd(ddManager, this->sylvanMtbdd.Ceil()); } template<> InternalAdd InternalAdd::ceil() const { return InternalAdd(ddManager, this->sylvanMtbdd.CeilRN()); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::ceil() const { return InternalAdd(ddManager, this->sylvanMtbdd.CeilRF()); } #endif template InternalAdd InternalAdd::sharpenKwekMehlhorn(size_t precision) const { return InternalAdd(ddManager, this->sylvanMtbdd.SharpenKwekMehlhorn(precision)); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::sharpenKwekMehlhorn(size_t precision) const { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Operation not supported."); } #endif template InternalAdd InternalAdd::minimum(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.Min(other.sylvanMtbdd)); } template<> InternalAdd InternalAdd::minimum(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.MinRN(other.sylvanMtbdd)); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::minimum(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.MinRF(other.sylvanMtbdd)); } #endif template InternalAdd InternalAdd::maximum(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.Max(other.sylvanMtbdd)); } template<> InternalAdd InternalAdd::maximum(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.MaxRN(other.sylvanMtbdd)); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::maximum(InternalAdd const& other) const { return InternalAdd(ddManager, this->sylvanMtbdd.MaxRF(other.sylvanMtbdd)); } #endif template template InternalAdd InternalAdd::toValueType() const { if (std::is_same::value) { return *this; } STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot convert this ADD to the target type."); } template<> template<> InternalAdd InternalAdd::toValueType() const { return InternalAdd(ddManager, this->sylvanMtbdd.ToDoubleRN()); } template<> template<> InternalAdd InternalAdd::toValueType() const { return InternalAdd(ddManager, this->sylvanMtbdd.ToRationalNumber()); } #ifdef STORM_HAVE_CARL template<> template<> InternalAdd InternalAdd::toValueType() const { return InternalAdd(ddManager, this->sylvanMtbdd.ToDoubleRF()); } #endif template InternalAdd InternalAdd::sumAbstract(InternalBdd const& cube) const { return InternalAdd(ddManager, this->sylvanMtbdd.AbstractPlus(cube.sylvanBdd)); } template<> InternalAdd InternalAdd::sumAbstract(InternalBdd const& cube) const { return InternalAdd(ddManager, this->sylvanMtbdd.AbstractPlusRN(cube.sylvanBdd)); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::sumAbstract(InternalBdd const& cube) const { return InternalAdd(ddManager, this->sylvanMtbdd.AbstractPlusRF(cube.sylvanBdd)); } #endif template InternalAdd InternalAdd::minAbstract(InternalBdd const& cube) const { return InternalAdd(ddManager, this->sylvanMtbdd.AbstractMin(cube.sylvanBdd)); } template InternalBdd InternalAdd::minAbstractRepresentative(InternalBdd const& cube) const { return InternalBdd(ddManager, this->sylvanMtbdd.AbstractMinRepresentative(cube.sylvanBdd)); } template<> InternalBdd InternalAdd::minAbstractRepresentative(InternalBdd const& cube) const { return InternalBdd(ddManager, this->sylvanMtbdd.AbstractMinRepresentativeRN(cube.sylvanBdd)); } template<> InternalAdd InternalAdd::minAbstract(InternalBdd const& cube) const { return InternalAdd(ddManager, this->sylvanMtbdd.AbstractMinRN(cube.sylvanBdd)); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::minAbstract(InternalBdd const& cube) const { return InternalAdd(ddManager, this->sylvanMtbdd.AbstractMinRF(cube.sylvanBdd)); } #endif template InternalAdd InternalAdd::maxAbstract(InternalBdd const& cube) const { return InternalAdd(ddManager, this->sylvanMtbdd.AbstractMax(cube.sylvanBdd)); } template InternalBdd InternalAdd::maxAbstractRepresentative(InternalBdd const& cube) const { return InternalBdd(ddManager, this->sylvanMtbdd.AbstractMaxRepresentative(cube.sylvanBdd)); } template<> InternalBdd InternalAdd::maxAbstractRepresentative(InternalBdd const& cube) const { return InternalBdd(ddManager, this->sylvanMtbdd.AbstractMaxRepresentativeRN(cube.sylvanBdd)); } template<> InternalAdd InternalAdd::maxAbstract(InternalBdd const& cube) const { return InternalAdd(ddManager, this->sylvanMtbdd.AbstractMaxRN(cube.sylvanBdd)); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::maxAbstract(InternalBdd const& cube) const { return InternalAdd(ddManager, this->sylvanMtbdd.AbstractMaxRF(cube.sylvanBdd)); } #endif template bool InternalAdd::equalModuloPrecision(InternalAdd const& other, ValueType const& precision, bool relative) const { if (relative) { return this->sylvanMtbdd.EqualNormRel(other.sylvanMtbdd, precision); } else { return this->sylvanMtbdd.EqualNorm(other.sylvanMtbdd, precision); } } #ifdef STORM_HAVE_CARL template<> bool InternalAdd::equalModuloPrecision(InternalAdd const& other, storm::RationalNumber const& precision, bool relative) const { if (relative) { return this->sylvanMtbdd.EqualNormRelRN(other.sylvanMtbdd, precision); } else { return this->sylvanMtbdd.EqualNormRN(other.sylvanMtbdd, precision); } } template<> bool InternalAdd::equalModuloPrecision(InternalAdd const& other, storm::RationalFunction const& precision, bool relative) const { if (relative) { return this->sylvanMtbdd.EqualNormRelRF(other.sylvanMtbdd, precision); } else { return this->sylvanMtbdd.EqualNormRF(other.sylvanMtbdd, precision); } } #endif template InternalAdd InternalAdd::swapVariables(std::vector> const& from, std::vector> const& to) const { std::vector fromIndices; std::vector toIndices; for (auto it1 = from.begin(), ite1 = from.end(), it2 = to.begin(); it1 != ite1; ++it1, ++it2) { fromIndices.push_back(it1->getIndex()); fromIndices.push_back(it2->getIndex()); toIndices.push_back(it2->getIndex()); toIndices.push_back(it1->getIndex()); } return InternalAdd(ddManager, this->sylvanMtbdd.Permute(fromIndices, toIndices)); } template InternalAdd InternalAdd::permuteVariables(std::vector> const& from, std::vector> const& to) const { std::vector fromIndices; std::vector toIndices; for (auto it1 = from.begin(), ite1 = from.end(), it2 = to.begin(); it1 != ite1; ++it1, ++it2) { fromIndices.push_back(it1->getIndex()); toIndices.push_back(it2->getIndex()); } return InternalAdd(ddManager, this->sylvanMtbdd.Permute(fromIndices, toIndices)); } template InternalAdd InternalAdd::multiplyMatrix(InternalAdd const& otherMatrix, std::vector> const& summationDdVariables) const { InternalBdd summationVariables = ddManager->getBddOne(); for (auto const& ddVariable : summationDdVariables) { summationVariables &= ddVariable; } return InternalAdd(ddManager, this->sylvanMtbdd.AndExists(otherMatrix.sylvanMtbdd, summationVariables.getSylvanBdd())); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::multiplyMatrix(InternalAdd const& otherMatrix, std::vector> const& summationDdVariables) const { InternalBdd summationVariables = ddManager->getBddOne(); for (auto const& ddVariable : summationDdVariables) { summationVariables &= ddVariable; } return InternalAdd(ddManager, this->sylvanMtbdd.AndExistsRF(otherMatrix.sylvanMtbdd, summationVariables.getSylvanBdd())); } #endif template<> InternalAdd InternalAdd::multiplyMatrix(InternalAdd const& otherMatrix, std::vector> const& summationDdVariables) const { InternalBdd summationVariables = ddManager->getBddOne(); for (auto const& ddVariable : summationDdVariables) { summationVariables &= ddVariable; } return InternalAdd(ddManager, this->sylvanMtbdd.AndExistsRN(otherMatrix.sylvanMtbdd, summationVariables.getSylvanBdd())); } template InternalAdd InternalAdd::multiplyMatrix(InternalBdd const& otherMatrix, std::vector> const& summationDdVariables) const { InternalBdd summationVariables = ddManager->getBddOne(); for (auto const& ddVariable : summationDdVariables) { summationVariables &= ddVariable; } return InternalAdd(ddManager, this->sylvanMtbdd.AndExists(sylvan::Bdd(otherMatrix.getSylvanBdd().GetBDD()), summationVariables.getSylvanBdd())); } #ifdef STORM_HAVE_CARL template<> InternalAdd InternalAdd::multiplyMatrix(InternalBdd const& otherMatrix, std::vector> const& summationDdVariables) const { InternalBdd summationVariables = ddManager->getBddOne(); for (auto const& ddVariable : summationDdVariables) { summationVariables &= ddVariable; } return InternalAdd(ddManager, this->sylvanMtbdd.AndExistsRF(sylvan::Bdd(otherMatrix.getSylvanBdd().GetBDD()), summationVariables.getSylvanBdd())); } #endif template<> InternalAdd InternalAdd::multiplyMatrix(InternalBdd const& otherMatrix, std::vector> const& summationDdVariables) const { InternalBdd summationVariables = ddManager->getBddOne(); for (auto const& ddVariable : summationDdVariables) { summationVariables &= ddVariable; } return InternalAdd(ddManager, this->sylvanMtbdd.AndExistsRN(sylvan::Bdd(otherMatrix.getSylvanBdd().GetBDD()), summationVariables.getSylvanBdd())); } template InternalBdd InternalAdd::greater(ValueType const& value) const { return InternalBdd(ddManager, this->sylvanMtbdd.BddStrictThreshold(value)); } template<> InternalBdd InternalAdd::greater(storm::RationalNumber const& value) const { return InternalBdd(ddManager, this->sylvanMtbdd.BddStrictThresholdRN(value)); } #ifdef STORM_HAVE_CARL template<> InternalBdd InternalAdd::greater(storm::RationalFunction const& value) const { return InternalBdd(ddManager, this->sylvanMtbdd.BddStrictThresholdRF(value)); } #endif template InternalBdd InternalAdd::greaterOrEqual(ValueType const& value) const { return InternalBdd(ddManager, this->sylvanMtbdd.BddThreshold(value)); } template<> InternalBdd InternalAdd::greaterOrEqual(storm::RationalNumber const& value) const { return InternalBdd(ddManager, this->sylvanMtbdd.BddThresholdRN(value)); } #ifdef STORM_HAVE_CARL template<> InternalBdd InternalAdd::greaterOrEqual(storm::RationalFunction const& value) const { return InternalBdd(ddManager, this->sylvanMtbdd.BddThresholdRF(value)); } #endif template InternalBdd InternalAdd::less(ValueType const& value) const { return !this->greaterOrEqual(value); } template InternalBdd InternalAdd::lessOrEqual(ValueType const& value) const { return !this->greater(value); } template InternalBdd InternalAdd::notZero() const { return InternalBdd(ddManager, this->sylvanMtbdd.NotZero()); } template InternalAdd InternalAdd::constrain(InternalAdd const&) const { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Operation (constrain) not yet implemented."); } template InternalAdd InternalAdd::restrict(InternalAdd const&) const { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Operation (restrict) not yet implemented."); } template InternalBdd InternalAdd::getSupport() const { return InternalBdd(ddManager, sylvan::Bdd(static_cast(this->sylvanMtbdd.Support().GetMTBDD()))); } template uint_fast64_t InternalAdd::getNonZeroCount(uint_fast64_t numberOfDdVariables) const { if (numberOfDdVariables == 0) { return 0; } return static_cast(this->sylvanMtbdd.NonZeroCount(numberOfDdVariables)); } template uint_fast64_t InternalAdd::getLeafCount() const { return static_cast(this->sylvanMtbdd.CountLeaves()); } template uint_fast64_t InternalAdd::getNodeCount() const { return static_cast(this->sylvanMtbdd.NodeCount()); } template ValueType InternalAdd::getMin() const { return getValue(this->sylvanMtbdd.Minimum().GetMTBDD()); } template <> storm::RationalNumber InternalAdd::getMin() const { return getValue(this->sylvanMtbdd.MinimumRN().GetMTBDD()); } #ifdef STORM_HAVE_CARL template <> storm::RationalFunction InternalAdd::getMin() const { return getValue(this->sylvanMtbdd.MinimumRF().GetMTBDD()); } #endif template ValueType InternalAdd::getMax() const { return getValue(this->sylvanMtbdd.Maximum().GetMTBDD()); } template<> storm::RationalNumber InternalAdd::getMax() const { return getValue(this->sylvanMtbdd.MaximumRN().GetMTBDD()); } #ifdef STORM_HAVE_CARL template<> storm::RationalFunction InternalAdd::getMax() const { return getValue(this->sylvanMtbdd.MaximumRF().GetMTBDD()); } #endif template ValueType InternalAdd::getValue() const { return getValue(this->sylvanMtbdd.GetMTBDD()); } template bool InternalAdd::isOne() const { return *this == ddManager->getAddOne(); } template bool InternalAdd::isZero() const { return *this == ddManager->getAddZero(); } template bool InternalAdd::isConstant() const { return this->sylvanMtbdd.isTerminal(); } template uint_fast64_t InternalAdd::getIndex() const { return static_cast(this->sylvanMtbdd.TopVar()); } template uint_fast64_t InternalAdd::getLevel() const { return this->getIndex(); } template void InternalAdd::exportToDot(std::string const& filename, std::vector const&, bool) const { // Open the file, dump the DD and close it again. FILE* filePointer = fopen(filename.c_str() , "a+"); this->sylvanMtbdd.PrintDot(filePointer); fclose(filePointer); } template void InternalAdd::exportToText(std::string const& filename) const { // Open the file, dump the DD and close it again. FILE* filePointer = fopen(filename.c_str() , "a+"); this->sylvanMtbdd.PrintText(filePointer); fclose(filePointer); } template AddIterator InternalAdd::begin(DdManager const& fullDdManager, InternalBdd const& variableCube, uint_fast64_t numberOfDdVariables, std::set const& metaVariables, bool enumerateDontCareMetaVariables) const { return AddIterator::createBeginIterator(fullDdManager, this->getSylvanMtbdd(), variableCube.getSylvanBdd(), numberOfDdVariables, &metaVariables, enumerateDontCareMetaVariables); } template AddIterator InternalAdd::end(DdManager const& fullDdManager) const { return AddIterator::createEndIterator(fullDdManager); } template Odd InternalAdd::createOdd(std::vector const& ddVariableIndices) const { // Prepare a unique table for each level that keeps the constructed ODD nodes unique. std::vector>> uniqueTableForLevels(ddVariableIndices.size() + 1); // Now construct the ODD structure from the ADD. std::shared_ptr rootOdd = createOddRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), 0, ddVariableIndices.size(), ddVariableIndices, uniqueTableForLevels); // Return a copy of the root node to remove the shared_ptr encapsulation. return Odd(*rootOdd); } template std::shared_ptr InternalAdd::createOddRec(BDD dd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector const& ddVariableIndices, std::vector>>& 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; STORM_LOG_ASSERT(mtbdd_isleaf(dd), "Expected leaf at last level."); // If the DD is not the zero leaf, then the then-offset is 1. if (!mtbdd_iszero(dd)) { thenOffset = 1; } auto oddNode = std::make_shared(nullptr, elseOffset, nullptr, thenOffset); uniqueTableForLevels[currentLevel].emplace(dd, oddNode); return oddNode; } else if (mtbdd_isleaf(dd) || ddVariableIndices[currentLevel] < mtbdd_getvar(dd)) { // 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 elseNode = createOddRec(dd, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels); std::shared_ptr thenNode = elseNode; auto oddNode = std::make_shared(elseNode, elseNode->getElseOffset() + elseNode->getThenOffset(), thenNode, thenNode->getElseOffset() + thenNode->getThenOffset()); uniqueTableForLevels[currentLevel].emplace(dd, oddNode); return oddNode; } else { // Otherwise, we compute the ODDs for both the then- and else successors. std::shared_ptr elseNode = createOddRec(mtbdd_regular(mtbdd_getlow(dd)), currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels); std::shared_ptr thenNode = createOddRec(mtbdd_regular(mtbdd_gethigh(dd)), currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels); uint_fast64_t totalElseOffset = elseNode->getElseOffset() + elseNode->getThenOffset(); uint_fast64_t totalThenOffset = thenNode->getElseOffset() + thenNode->getThenOffset(); auto oddNode = std::make_shared(elseNode, totalElseOffset, thenNode, totalThenOffset); uniqueTableForLevels[currentLevel].emplace(dd, oddNode); return oddNode; } } } template InternalDdManager const& InternalAdd::getInternalDdManager() const { return *ddManager; } template void InternalAdd::composeWithExplicitVector(storm::dd::Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const { forEachRec(this->getSylvanMtbdd().GetMTBDD(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, [&function, &targetVector] (uint64_t const& offset, ValueType const& value) { targetVector[offset] = function(targetVector[offset], value); }); } template void InternalAdd::composeWithExplicitVector(storm::dd::Odd const& odd, std::vector const& ddVariableIndices, std::vector const& offsets, std::vector& targetVector, std::function const& function) const { forEachRec(this->getSylvanMtbdd().GetMTBDD(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, [&function, &targetVector, &offsets] (uint64_t const& offset, ValueType const& value) { ValueType& targetValue = targetVector[offsets[offset]]; targetValue = function(targetValue, value); }); } template void InternalAdd::forEach(Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const { forEachRec(this->getSylvanMtbdd().GetMTBDD(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, function); } template void InternalAdd::forEachRec(MTBDD dd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const { // For the empty DD, we do not need to add any entries. if (mtbdd_isleaf(dd) && mtbdd_iszero(dd)) { return; } // If we are at the maximal level, the value to be set is stored as a constant in the DD. if (currentLevel == maxLevel) { function(currentOffset, getValue(dd)); } else if (mtbdd_isleaf(dd) || ddVariableIndices[currentLevel] < mtbdd_getvar(dd)) { // 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. forEachRec(dd, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, function); forEachRec(dd, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, function); } else { // Otherwise, we simply recursively call the function for both (different) cases. MTBDD thenNode = mtbdd_gethigh(dd); MTBDD elseNode = mtbdd_getlow(dd); forEachRec(elseNode, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, function); forEachRec(thenNode, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, function); } } template std::vector InternalAdd::decodeGroupLabels(std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices) const { std::vector result; decodeGroupLabelsRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), result, ddGroupVariableIndices, ddLabelVariableIndices, 0, ddGroupVariableIndices.size(), 0); return result; } template void InternalAdd::decodeGroupLabelsRec(MTBDD dd, std::vector& labels, std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const { // For the empty DD, we do not need to create a group. if (mtbdd_isleaf(dd) && mtbdd_iszero(dd)) { return; } if (currentLevel == maxLevel) { labels.push_back(label); } else { uint64_t elseLabel = label; uint64_t thenLabel = label; if (ddLabelVariableIndices.get(currentLevel)) { elseLabel <<= 1; thenLabel = (thenLabel << 1) | 1; } if (mtbdd_isleaf(dd) || ddGroupVariableIndices[currentLevel] < mtbdd_getvar(dd)) { decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, elseLabel); decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, thenLabel); } else { // Otherwise, we compute the ODDs for both the then- and else successors. MTBDD thenDdNode = mtbdd_gethigh(dd); MTBDD elseDdNode = mtbdd_getlow(dd); decodeGroupLabelsRec(mtbdd_regular(elseDdNode), labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, elseLabel); decodeGroupLabelsRec(mtbdd_regular(thenDdNode), labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, thenLabel); } } } template std::vector> InternalAdd::splitIntoGroups(std::vector const& ddGroupVariableIndices) const { std::vector> result; splitIntoGroupsRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), mtbdd_hascomp(this->getSylvanMtbdd().GetMTBDD()), result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size()); return result; } template std::vector, InternalAdd>> InternalAdd::splitIntoGroups(InternalAdd vector, std::vector const& ddGroupVariableIndices) const { std::vector, InternalAdd>> result; splitIntoGroupsRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), mtbdd_hascomp(this->getSylvanMtbdd().GetMTBDD()), mtbdd_regular(vector.getSylvanMtbdd().GetMTBDD()), mtbdd_hascomp(vector.getSylvanMtbdd().GetMTBDD()), result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size()); return result; } template void InternalAdd::splitIntoGroupsRec(MTBDD dd, bool negated, std::vector>& groups, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const { // For the empty DD, we do not need to create a group. if (mtbdd_isleaf(dd) && mtbdd_iszero(dd)) { return; } if (currentLevel == maxLevel) { groups.push_back(InternalAdd(ddManager, negated ? sylvan::Mtbdd(dd).Negate() : sylvan::Mtbdd(dd))); } else if (mtbdd_isleaf(dd) || ddGroupVariableIndices[currentLevel] < mtbdd_getvar(dd)) { splitIntoGroupsRec(dd, negated, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); splitIntoGroupsRec(dd, negated, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); } else { // Otherwise, we compute the ODDs for both the then- and else successors. MTBDD thenDdNode = mtbdd_gethigh(dd); MTBDD elseDdNode = mtbdd_getlow(dd); // Determine whether we have to evaluate the successors as if they were complemented. bool elseComplemented = mtbdd_hascomp(elseDdNode) ^ negated; bool thenComplemented = mtbdd_hascomp(thenDdNode) ^ negated; // FIXME: We first traverse the else successor (unlike other variants of this method). // Otherwise, the GameBasedMdpModelCheckerTest would not terminate. See github issue #64 splitIntoGroupsRec(mtbdd_regular(elseDdNode), elseComplemented, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); splitIntoGroupsRec(mtbdd_regular(thenDdNode), thenComplemented, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); } } template void InternalAdd::splitIntoGroupsRec(MTBDD dd1, bool negated1, MTBDD dd2, bool negated2, std::vector, InternalAdd>>& groups, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const { // For the empty DD, we do not need to create a group. if (mtbdd_isleaf(dd1) && mtbdd_isleaf(dd2) && mtbdd_iszero(dd1) && mtbdd_iszero(dd2)) { return; } if (currentLevel == maxLevel) { groups.push_back(std::make_pair(InternalAdd(ddManager, negated1 ? sylvan::Mtbdd(dd1).Negate() : sylvan::Mtbdd(dd1)), InternalAdd(ddManager, negated2 ? sylvan::Mtbdd(dd2).Negate() : sylvan::Mtbdd(dd2)))); } else if (mtbdd_isleaf(dd1) || ddGroupVariableIndices[currentLevel] < mtbdd_getvar(dd1)) { if (mtbdd_isleaf(dd2) || ddGroupVariableIndices[currentLevel] < mtbdd_getvar(dd2)) { splitIntoGroupsRec(dd1, negated1, dd2, negated2, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); splitIntoGroupsRec(dd1, negated1, dd2, negated2, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); } else { MTBDD dd2ThenNode = mtbdd_gethigh(dd2); MTBDD dd2ElseNode = mtbdd_getlow(dd2); // Determine whether we have to evaluate the successors as if they were complemented. bool elseComplemented = mtbdd_hascomp(dd2ElseNode) ^ negated2; bool thenComplemented = mtbdd_hascomp(dd2ThenNode) ^ negated2; splitIntoGroupsRec(dd1, negated1, mtbdd_regular(dd2ThenNode), thenComplemented, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); splitIntoGroupsRec(dd1, negated1, mtbdd_regular(dd2ElseNode), elseComplemented, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); } } else if (mtbdd_isleaf(dd2) || ddGroupVariableIndices[currentLevel] < mtbdd_getvar(dd2)) { MTBDD dd1ThenNode = mtbdd_gethigh(dd1); MTBDD dd1ElseNode = mtbdd_getlow(dd1); // Determine whether we have to evaluate the successors as if they were complemented. bool elseComplemented = mtbdd_hascomp(dd1ElseNode) ^ negated1; bool thenComplemented = mtbdd_hascomp(dd1ThenNode) ^ negated1; splitIntoGroupsRec(mtbdd_regular(dd1ThenNode), thenComplemented, dd2, negated2, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); splitIntoGroupsRec(mtbdd_regular(dd1ElseNode), elseComplemented, dd2, negated2, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); } else { MTBDD dd1ThenNode = mtbdd_gethigh(dd1); MTBDD dd1ElseNode = mtbdd_getlow(dd1); MTBDD dd2ThenNode = mtbdd_gethigh(dd2); MTBDD dd2ElseNode = mtbdd_getlow(dd2); // Determine whether we have to evaluate the successors as if they were complemented. bool dd1ElseComplemented = mtbdd_hascomp(dd1ElseNode) ^ negated1; bool dd1ThenComplemented = mtbdd_hascomp(dd1ThenNode) ^ negated1; bool dd2ElseComplemented = mtbdd_hascomp(dd2ElseNode) ^ negated2; bool dd2ThenComplemented = mtbdd_hascomp(dd2ThenNode) ^ negated2; splitIntoGroupsRec(mtbdd_regular(dd1ThenNode), dd1ThenComplemented, mtbdd_regular(dd2ThenNode), dd2ThenComplemented, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); splitIntoGroupsRec(mtbdd_regular(dd1ElseNode), dd1ElseComplemented, mtbdd_regular(dd2ElseNode), dd2ElseComplemented, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); } } template void InternalAdd::toMatrixComponents(std::vector const& rowGroupIndices, std::vector& rowIndications, std::vector>& columnsAndValues, Odd const& rowOdd, Odd const& columnOdd, std::vector const& ddRowVariableIndices, std::vector const& ddColumnVariableIndices, bool writeValues) const { return toMatrixComponentsRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), mtbdd_hascomp(this->getSylvanMtbdd().GetMTBDD()), rowGroupIndices, rowIndications, columnsAndValues, rowOdd, columnOdd, 0, 0, ddRowVariableIndices.size() + ddColumnVariableIndices.size(), 0, 0, ddRowVariableIndices, ddColumnVariableIndices, writeValues); } template void InternalAdd::toMatrixComponentsRec(MTBDD dd, bool negated, std::vector const& rowGroupOffsets, std::vector& rowIndications, std::vector>& 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 const& ddRowVariableIndices, std::vector const& ddColumnVariableIndices, bool generateValues) const { // For the empty DD, we do not need to add any entries. if (mtbdd_isleaf(dd) && mtbdd_iszero(dd)) { return; } // If we are at the maximal level, the value to be set is stored as a constant in the DD. if (currentRowLevel + currentColumnLevel == maxLevel) { if (generateValues) { columnsAndValues[rowIndications[rowGroupOffsets[currentRowOffset]]] = storm::storage::MatrixEntry(currentColumnOffset, negated ? -getValue(dd) : getValue(dd)); } ++rowIndications[rowGroupOffsets[currentRowOffset]]; } else { MTBDD elseElse; MTBDD elseThen; MTBDD thenElse; MTBDD thenThen; if (mtbdd_isleaf(dd) || ddColumnVariableIndices[currentColumnLevel] < mtbdd_getvar(dd)) { elseElse = elseThen = thenElse = thenThen = dd; } else if (ddRowVariableIndices[currentColumnLevel] < mtbdd_getvar(dd)) { elseElse = thenElse = mtbdd_getlow(dd); elseThen = thenThen = mtbdd_gethigh(dd); } else { MTBDD elseNode = mtbdd_getlow(dd); if (mtbdd_isleaf(elseNode) || ddColumnVariableIndices[currentColumnLevel] < mtbdd_getvar(elseNode)) { elseElse = elseThen = elseNode; } else { elseElse = mtbdd_getlow(elseNode); elseThen = mtbdd_gethigh(elseNode); } MTBDD thenNode = mtbdd_gethigh(dd); if (mtbdd_isleaf(thenNode) || ddColumnVariableIndices[currentColumnLevel] < mtbdd_getvar(thenNode)) { thenElse = thenThen = thenNode; } else { thenElse = mtbdd_getlow(thenNode); thenThen = mtbdd_gethigh(thenNode); } } // Visit else-else. toMatrixComponentsRec(mtbdd_regular(elseElse), mtbdd_hascomp(elseElse) ^ negated, rowGroupOffsets, rowIndications, columnsAndValues, rowOdd.getElseSuccessor(), columnOdd.getElseSuccessor(), currentRowLevel + 1, currentColumnLevel + 1, maxLevel, currentRowOffset, currentColumnOffset, ddRowVariableIndices, ddColumnVariableIndices, generateValues); // Visit else-then. toMatrixComponentsRec(mtbdd_regular(elseThen), mtbdd_hascomp(elseThen) ^ negated, rowGroupOffsets, rowIndications, columnsAndValues, rowOdd.getElseSuccessor(), columnOdd.getThenSuccessor(), currentRowLevel + 1, currentColumnLevel + 1, maxLevel, currentRowOffset, currentColumnOffset + columnOdd.getElseOffset(), ddRowVariableIndices, ddColumnVariableIndices, generateValues); // Visit then-else. toMatrixComponentsRec(mtbdd_regular(thenElse), mtbdd_hascomp(thenElse) ^ negated, rowGroupOffsets, rowIndications, columnsAndValues, rowOdd.getThenSuccessor(), columnOdd.getElseSuccessor(), currentRowLevel + 1, currentColumnLevel + 1, maxLevel, currentRowOffset + rowOdd.getElseOffset(), currentColumnOffset, ddRowVariableIndices, ddColumnVariableIndices, generateValues); // Visit then-then. toMatrixComponentsRec(mtbdd_regular(thenThen), mtbdd_hascomp(thenThen) ^ negated, rowGroupOffsets, rowIndications, columnsAndValues, rowOdd.getThenSuccessor(), columnOdd.getThenSuccessor(), currentRowLevel + 1, currentColumnLevel + 1, maxLevel, currentRowOffset + rowOdd.getElseOffset(), currentColumnOffset + columnOdd.getElseOffset(), ddRowVariableIndices, ddColumnVariableIndices, generateValues); } } template InternalAdd InternalAdd::fromVector(InternalDdManager const* ddManager, std::vector const& values, storm::dd::Odd const& odd, std::vector const& ddVariableIndices) { uint_fast64_t offset = 0; return InternalAdd(ddManager, sylvan::Mtbdd(fromVectorRec(offset, 0, ddVariableIndices.size(), values, odd, ddVariableIndices))); } template MTBDD InternalAdd::fromVectorRec(uint_fast64_t& currentOffset, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector const& values, Odd const& odd, std::vector 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 // need to copy the next value of the vector iff the then-offset is greater than zero. if (odd.getThenOffset() > 0) { return getLeaf(values[currentOffset++]); } else { return getLeaf(storm::utility::zero()); } } else { // If the total offset is zero, we can just return the constant zero DD. if (odd.getThenOffset() + odd.getElseOffset() == 0) { return getLeaf(storm::utility::zero()); } // Determine the new else-successor. MTBDD elseSuccessor; if (odd.getElseOffset() > 0) { elseSuccessor = fromVectorRec(currentOffset, currentLevel + 1, maxLevel, values, odd.getElseSuccessor(), ddVariableIndices); } else { elseSuccessor = getLeaf(storm::utility::zero()); } mtbdd_refs_push(elseSuccessor); // Determine the new then-successor. MTBDD thenSuccessor; if (odd.getThenOffset() > 0) { thenSuccessor = fromVectorRec(currentOffset, currentLevel + 1, maxLevel, values, odd.getThenSuccessor(), ddVariableIndices); } else { thenSuccessor = getLeaf(storm::utility::zero()); } mtbdd_refs_push(thenSuccessor); // Create a node representing ITE(currentVar, thenSuccessor, elseSuccessor); MTBDD currentVar = mtbdd_makenode(ddVariableIndices[currentLevel], mtbdd_false, mtbdd_true); mtbdd_refs_push(thenSuccessor); LACE_ME; MTBDD result = mtbdd_ite(currentVar, thenSuccessor, elseSuccessor); // Dispose of the intermediate results mtbdd_refs_pop(3); return result; } } template MTBDD InternalAdd::getLeaf(double value) { return mtbdd_double(value); } template MTBDD InternalAdd::getLeaf(uint_fast64_t value) { return mtbdd_int64(value); } template MTBDD InternalAdd::getLeaf(storm::RationalFunction const& value) { storm_rational_function_ptr ptr = (storm_rational_function_ptr)(&value); return mtbdd_storm_rational_function(ptr); } template MTBDD InternalAdd::getLeaf(storm::RationalNumber const& value) { storm_rational_function_ptr ptr = (storm_rational_number_ptr)(&value); return mtbdd_storm_rational_number(ptr); } template sylvan::Mtbdd InternalAdd::getSylvanMtbdd() const { return sylvanMtbdd; } template std::string InternalAdd::getStringId() const { std::stringstream ss; ss << this->getSylvanMtbdd().GetMTBDD(); return ss.str(); } template class InternalAdd; template class InternalAdd; template class InternalAdd; #ifdef STORM_HAVE_CARL template class InternalAdd; #endif } }