3#include <boost/functional/hash.hpp>
16#include "storm-config.h"
26 : ddManager(ddManager), sylvanBdd(sylvanBdd) {
31 std::vector<uint_fast64_t>
const& sortedDdVariableIndices,
32 std::function<
bool(uint64_t)>
const& filter) {
33 uint_fast64_t offset = 0;
34 return InternalBdd<DdType::Sylvan>(ddManager, sylvan::Bdd(fromVectorRec(offset, 0, sortedDdVariableIndices.size(), odd, sortedDdVariableIndices, filter)));
38 std::vector<uint_fast64_t>
const& ddVariableIndices, std::function<
bool(uint64_t)>
const& filter) {
39 if (currentLevel == maxLevel) {
44 if (filter(currentOffset++)) {
61 elseSuccessor = fromVectorRec(currentOffset, currentLevel + 1, maxLevel, odd.
getElseSuccessor(), ddVariableIndices, filter);
63 elseSuccessor = sylvan_false;
65 bdd_refs_push(elseSuccessor);
70 thenSuccessor = fromVectorRec(currentOffset, currentLevel + 1, maxLevel, odd.
getThenSuccessor(), ddVariableIndices, filter);
72 thenSuccessor = sylvan_false;
74 bdd_refs_push(thenSuccessor);
77 BDD currentVar = sylvan_ithvar(
static_cast<BDDVAR
>(ddVariableIndices[currentLevel]));
78 bdd_refs_push(currentVar);
80 BDD result = sylvan_ite(currentVar, thenSuccessor, elseSuccessor);
90 return sylvanBdd == other.sylvanBdd;
94 return sylvanBdd != other.sylvanBdd;
115 for (
auto const& variable : columnVariables) {
116 columnCube &= variable;
119 return this->swapVariables(rowVariables, columnVariables).andExists(relation, columnCube);
126template<
typename ValueType>
137 this->sylvanBdd |= other.sylvanBdd;
146 this->sylvanBdd &= other.sylvanBdd;
167 this->sylvanBdd = !this->sylvanBdd;
197 std::vector<uint32_t> fromIndices;
198 std::vector<uint32_t> toIndices;
199 for (
auto it1 = from.begin(), ite1 = from.end(), it2 = to.begin(); it1 != ite1; ++it1, ++it2) {
200 fromIndices.push_back(it1->getIndex());
201 fromIndices.push_back(it2->getIndex());
202 toIndices.push_back(it2->getIndex());
203 toIndices.push_back(it1->getIndex());
213 if (numberOfDdVariables == 0) {
216 return static_cast<uint_fast64_t
>(this->sylvanBdd.SatCount(numberOfDdVariables));
227 return static_cast<uint_fast64_t
>(this->sylvanBdd.NodeCount());
231 return this->sylvanBdd.isOne();
235 return this->sylvanBdd.isZero();
239 return static_cast<uint_fast64_t
>(this->sylvanBdd.TopVar());
243 return this->getIndex();
247 FILE* filePointer = fopen(filename.c_str(),
"a+");
249 if (filePointer ==
nullptr) {
252 this->sylvanBdd.PrintDot(filePointer);
258 FILE* filePointer = fopen(filename.c_str(),
"a+");
260 if (filePointer ==
nullptr) {
263 this->sylvanBdd.PrintText(filePointer);
276template<
typename ValueType>
278 if (std::is_same<ValueType, double>::value) {
280 }
else if (std::is_same<ValueType, uint_fast64_t>::value) {
283#ifdef STORM_HAVE_CARL
284 else if (std::is_same<ValueType, storm::RationalNumber>::value) {
286 }
else if (std::is_same<ValueType, storm::RationalFunction>::value) {
291 STORM_LOG_THROW(
false, storm::exceptions::InvalidOperationException,
"Illegal ADD type.");
297 this->toVectorRec(bdd_regular(this->getSylvanBdd().GetBDD()), result, rowOdd, bdd_isnegated(this->getSylvanBdd().GetBDD()), 0, ddVariableIndices.size(), 0,
303 uint_fast64_t maxLevel, uint_fast64_t currentRowOffset,
304 std::vector<uint_fast64_t>
const& ddRowVariableIndices)
const {
306 if (dd == sylvan_false && !complement) {
308 }
else if (dd == sylvan_true && complement) {
313 if (currentRowLevel == maxLevel) {
314 result.
set(currentRowOffset,
true);
315 }
else if (bdd_isterminal(dd) || ddRowVariableIndices[currentRowLevel] < sylvan_var(dd)) {
316 toVectorRec(dd, result, rowOdd.
getElseSuccessor(), complement, currentRowLevel + 1, maxLevel, currentRowOffset, ddRowVariableIndices);
318 ddRowVariableIndices);
321 BDD elseDdNode = sylvan_low(dd);
322 BDD thenDdNode = sylvan_high(dd);
325 bool elseComplemented = bdd_isnegated(elseDdNode) ^ complement;
326 bool thenComplemented = bdd_isnegated(thenDdNode) ^ complement;
328 toVectorRec(bdd_regular(elseDdNode), result, rowOdd.
getElseSuccessor(), elseComplemented, currentRowLevel + 1, maxLevel, currentRowOffset,
329 ddRowVariableIndices);
330 toVectorRec(bdd_regular(thenDdNode), result, rowOdd.
getThenSuccessor(), thenComplemented, currentRowLevel + 1, maxLevel,
331 currentRowOffset + rowOdd.
getElseOffset(), ddRowVariableIndices);
337 std::vector<std::unordered_map<std::pair<BDD, bool>, std::shared_ptr<Odd>, HashFunctor>> uniqueTableForLevels(ddVariableIndices.size() + 1);
340 std::shared_ptr<Odd> rootOdd = createOddRec(bdd_regular(this->getSylvanBdd().GetBDD()), bdd_isnegated(this->getSylvanBdd().GetBDD()), 0,
341 ddVariableIndices.size(), ddVariableIndices, uniqueTableForLevels);
344 return Odd(*rootOdd);
348 std::size_t result = 0;
349 boost::hash_combine(result, key.first);
350 boost::hash_combine(result, key.second);
354std::shared_ptr<Odd> InternalBdd<DdType::Sylvan>::createOddRec(
355 BDD dd,
bool complement, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector<uint_fast64_t>
const& ddVariableIndices,
356 std::vector<std::unordered_map<std::pair<BDD, bool>, std::shared_ptr<Odd>, HashFunctor>>& uniqueTableForLevels) {
358 auto const& iterator = uniqueTableForLevels[currentLevel].find(std::make_pair(dd, complement));
359 if (iterator != uniqueTableForLevels[currentLevel].end()) {
360 return iterator->second;
366 if (currentLevel == maxLevel) {
367 uint_fast64_t elseOffset = 0;
368 uint_fast64_t thenOffset = 0;
371 if (dd != mtbdd_false) {
377 thenOffset = 1 - thenOffset;
380 auto oddNode = std::make_shared<Odd>(
nullptr, elseOffset,
nullptr, thenOffset);
381 uniqueTableForLevels[currentLevel].emplace(std::make_pair(dd, complement), oddNode);
383 }
else if (bdd_isterminal(dd) || ddVariableIndices[currentLevel] < sylvan_var(dd)) {
386 std::shared_ptr<Odd> elseNode = createOddRec(dd, complement, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels);
387 std::shared_ptr<Odd> thenNode = elseNode;
388 uint_fast64_t totalOffset = elseNode->getElseOffset() + elseNode->getThenOffset();
389 auto oddNode = std::make_shared<Odd>(elseNode, totalOffset, thenNode, totalOffset);
390 uniqueTableForLevels[currentLevel].emplace(std::make_pair(dd, complement), oddNode);
394 BDD thenDdNode = sylvan_high(dd);
395 BDD elseDdNode = sylvan_low(dd);
398 bool elseComplemented = bdd_isnegated(elseDdNode) ^ complement;
399 bool thenComplemented = bdd_isnegated(thenDdNode) ^ complement;
401 std::shared_ptr<Odd> elseNode =
402 createOddRec(bdd_regular(elseDdNode), elseComplemented, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels);
403 std::shared_ptr<Odd> thenNode =
404 createOddRec(bdd_regular(thenDdNode), thenComplemented, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels);
406 auto oddNode = std::make_shared<Odd>(elseNode, elseNode->getElseOffset() + elseNode->getThenOffset(), thenNode,
407 thenNode->getElseOffset() + thenNode->getThenOffset());
408 uniqueTableForLevels[currentLevel].emplace(std::make_pair(dd, complement), oddNode);
414template<
typename ValueType>
416 std::vector<ValueType>
const& sourceValues, std::vector<ValueType>& targetValues)
const {
417 uint_fast64_t currentIndex = 0;
418 filterExplicitVectorRec(bdd_regular(this->getSylvanBdd().GetBDD()), 0, bdd_isnegated(this->getSylvanBdd().GetBDD()), ddVariableIndices.size(),
419 ddVariableIndices, 0, odd, targetValues, currentIndex, sourceValues);
422template<
typename ValueType>
424 std::vector<uint_fast64_t>
const& ddVariableIndices, uint_fast64_t currentOffset,
425 storm::dd::Odd const& odd, std::vector<ValueType>& result, uint_fast64_t& currentIndex,
426 std::vector<ValueType>
const& values) {
428 if (dd == sylvan_false && !complement) {
430 }
else if (dd == sylvan_true && complement) {
434 if (currentLevel == maxLevel) {
435 result[currentIndex++] = values[currentOffset];
436 }
else if (bdd_isterminal(dd) || ddVariableIndices[currentLevel] < sylvan_var(dd)) {
439 filterExplicitVectorRec(dd, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset, odd.
getElseSuccessor(), result, currentIndex,
441 filterExplicitVectorRec(dd, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset + odd.
getElseOffset(), odd.
getThenSuccessor(),
442 result, currentIndex, values);
445 BDD thenDdNode = sylvan_high(dd);
446 BDD elseDdNode = sylvan_low(dd);
449 bool elseComplemented = bdd_isnegated(elseDdNode) ^ complement;
450 bool thenComplemented = bdd_isnegated(thenDdNode) ^ complement;
452 filterExplicitVectorRec(bdd_regular(elseDdNode), currentLevel + 1, elseComplemented, maxLevel, ddVariableIndices, currentOffset, odd.
getElseSuccessor(),
453 result, currentIndex, values);
454 filterExplicitVectorRec(bdd_regular(thenDdNode), currentLevel + 1, thenComplemented, maxLevel, ddVariableIndices, currentOffset + odd.
getElseOffset(),
461 uint_fast64_t currentIndex = 0;
462 filterExplicitVectorRec(bdd_regular(this->getSylvanBdd().GetBDD()), 0, bdd_isnegated(this->getSylvanBdd().GetBDD()), ddVariableIndices.size(),
463 ddVariableIndices, 0, odd, targetValues, currentIndex, sourceValues);
467 std::vector<uint_fast64_t>
const& ddVariableIndices, uint_fast64_t currentOffset,
471 if (dd == sylvan_false && !complement) {
473 }
else if (dd == sylvan_true && complement) {
477 if (currentLevel == maxLevel) {
478 result.
set(currentIndex++, values.
get(currentOffset));
479 }
else if (bdd_isterminal(dd) || ddVariableIndices[currentLevel] < sylvan_var(dd)) {
482 filterExplicitVectorRec(dd, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset, odd.
getElseSuccessor(), result, currentIndex,
484 filterExplicitVectorRec(dd, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset + odd.
getElseOffset(), odd.
getThenSuccessor(),
485 result, currentIndex, values);
488 BDD thenDdNode = sylvan_high(dd);
489 BDD elseDdNode = sylvan_low(dd);
492 bool elseComplemented = bdd_isnegated(elseDdNode) ^ complement;
493 bool thenComplemented = bdd_isnegated(thenDdNode) ^ complement;
495 filterExplicitVectorRec(bdd_regular(elseDdNode), currentLevel + 1, elseComplemented, maxLevel, ddVariableIndices, currentOffset, odd.
getElseSuccessor(),
496 result, currentIndex, values);
497 filterExplicitVectorRec(bdd_regular(thenDdNode), currentLevel + 1, thenComplemented, maxLevel, ddVariableIndices, currentOffset + odd.
getElseOffset(),
503 std::vector<InternalBdd<DdType::Sylvan>> result;
504 splitIntoGroupsRec(this->getSylvanBdd().GetBDD(), result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size());
509 std::vector<uint_fast64_t>
const& ddGroupVariableIndices, uint_fast64_t currentLevel,
510 uint_fast64_t maxLevel)
const {
512 if (dd == sylvan_false) {
516 if (currentLevel == maxLevel) {
517 groups.push_back(InternalBdd<DdType::Sylvan>(ddManager, sylvan::Bdd(dd)));
518 }
else if (bdd_isterminal(dd) || ddGroupVariableIndices[currentLevel] < sylvan_var(dd)) {
519 splitIntoGroupsRec(dd, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
520 splitIntoGroupsRec(dd, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
523 BDD thenDdNode = sylvan_high(dd);
524 BDD elseDdNode = sylvan_low(dd);
526 splitIntoGroupsRec(elseDdNode, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
527 splitIntoGroupsRec(thenDdNode, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
531std::pair<std::vector<storm::expressions::Expression>, std::unordered_map<uint_fast64_t, storm::expressions::Variable>>
533 std::pair<std::vector<storm::expressions::Expression>, std::unordered_map<uint_fast64_t, storm::expressions::Variable>> result;
537 std::unordered_map<BDD, uint_fast64_t> nodeToCounterMap;
538 std::vector<uint_fast64_t> nextCounterForIndex(ddManager->getNumberOfDdVariables(), 0);
541 bool negated = bdd_isnegated(this->getSylvanBdd().GetBDD());
544 storm::expressions::Variable topVariable = this->toExpressionRec(bdd_regular(this->getSylvanBdd().GetBDD()), manager, result.first, result.second,
545 countIndexToVariablePair, nodeToCounterMap, nextCounterForIndex);
549 result.first.push_back(!topVariable);
551 result.first.push_back(topVariable);
559 std::unordered_map<uint_fast64_t, storm::expressions::Variable>& indexToVariableMap,
561 std::unordered_map<BDD, uint_fast64_t>& nodeToCounterMap, std::vector<uint_fast64_t>& nextCounterForIndex) {
565 auto nodeCounterIt = nodeToCounterMap.find(dd);
566 if (nodeCounterIt != nodeToCounterMap.end()) {
568 auto variableIt = countIndexToVariablePair.find(std::make_pair(nodeCounterIt->second, sylvan_var(dd)));
569 STORM_LOG_ASSERT(variableIt != countIndexToVariablePair.end(),
"Unable to find node.");
570 return variableIt->second;
577 if (!bdd_isterminal(dd)) {
579 nodeToCounterMap[dd] = nextCounterForIndex[sylvan_var(dd)];
580 countIndexToVariablePair[std::make_pair(nextCounterForIndex[sylvan_var(dd)], sylvan_var(dd))] = newNodeVariable;
581 ++nextCounterForIndex[sylvan_var(dd)];
584 nodeToCounterMap[dd] = 0;
585 countIndexToVariablePair[std::make_pair(0, sylvan_var(dd))] = newNodeVariable;
589 if (bdd_isterminal(dd)) {
590 if (dd == sylvan_true) {
597 BDD t = sylvan_high(dd);
598 BDD e = sylvan_low(dd);
599 BDD T = bdd_regular(t);
600 BDD E = bdd_regular(e);
602 toExpressionRec(T, manager, expressions, indexToVariableMap, countIndexToVariablePair, nodeToCounterMap, nextCounterForIndex);
604 toExpressionRec(E, manager, expressions, indexToVariableMap, countIndexToVariablePair, nodeToCounterMap, nextCounterForIndex);
608 auto indexVariable = indexToVariableMap.find(sylvan_var(dd));
610 if (indexVariable == indexToVariableMap.end()) {
611 levelVariable =
manager.declareFreshBooleanVariable();
612 indexToVariableMap[sylvan_var(dd)] = levelVariable;
614 levelVariable = indexVariable->second;
617 newNodeVariable,
storm::expressions::ite(levelVariable, t == T ? thenVariable : !thenVariable, e == E ? elseVariable : !elseVariable)));
621 return newNodeVariable;
624template InternalAdd<DdType::Sylvan, double> InternalBdd<DdType::Sylvan>::toAdd()
const;
625template InternalAdd<DdType::Sylvan, uint_fast64_t> InternalBdd<DdType::Sylvan>::toAdd()
const;
626template InternalAdd<DdType::Sylvan, storm::RationalNumber> InternalBdd<DdType::Sylvan>::toAdd()
const;
627template InternalAdd<DdType::Sylvan, storm::RationalFunction> InternalBdd<DdType::Sylvan>::toAdd()
const;
629template void InternalBdd<DdType::Sylvan>::filterExplicitVector(Odd
const& odd, std::vector<uint_fast64_t>
const& ddVariableIndices,
630 std::vector<double>
const& sourceValues, std::vector<double>& targetValues)
const;
631template void InternalBdd<DdType::Sylvan>::filterExplicitVector(Odd
const& odd, std::vector<uint_fast64_t>
const& ddVariableIndices,
632 std::vector<uint_fast64_t>
const& sourceValues, std::vector<uint_fast64_t>& targetValues)
const;
633template void InternalBdd<DdType::Sylvan>::filterExplicitVector(Odd
const& odd, std::vector<uint_fast64_t>
const& ddVariableIndices,
634 std::vector<storm::RationalNumber>
const& sourceValues,
635 std::vector<storm::RationalNumber>& targetValues)
const;
636template void InternalBdd<DdType::Sylvan>::filterExplicitVector(Odd
const& odd, std::vector<uint_fast64_t>
const& ddVariableIndices,
637 std::vector<storm::RationalFunction>
const& sourceValues,
638 std::vector<storm::RationalFunction>& targetValues)
const;
640template InternalAdd<DdType::Sylvan, double> InternalBdd<DdType::Sylvan>::ite(InternalAdd<DdType::Sylvan, double>
const& thenAdd,
641 InternalAdd<DdType::Sylvan, double>
const& elseAdd)
const;
642template InternalAdd<DdType::Sylvan, uint_fast64_t> InternalBdd<DdType::Sylvan>::ite(InternalAdd<DdType::Sylvan, uint_fast64_t>
const& thenAdd,
643 InternalAdd<DdType::Sylvan, uint_fast64_t>
const& elseAdd)
const;
644template InternalAdd<DdType::Sylvan, storm::RationalNumber> InternalBdd<DdType::Sylvan>::ite(
645 InternalAdd<DdType::Sylvan, storm::RationalNumber>
const& thenAdd, InternalAdd<DdType::Sylvan, storm::RationalNumber>
const& elseAdd)
const;
646template InternalAdd<DdType::Sylvan, storm::RationalFunction> InternalBdd<DdType::Sylvan>::ite(
647 InternalAdd<DdType::Sylvan, storm::RationalFunction>
const& thenAdd, InternalAdd<DdType::Sylvan, storm::RationalFunction>
const& elseAdd)
const;
Odd const & getThenSuccessor() const
Retrieves the then-successor of this ODD node.
uint_fast64_t getTotalOffset() const
Retrieves the total offset, i.e., the sum of the then- and else-offset.
uint_fast64_t getElseOffset() const
Retrieves the else-offset of this ODD node.
Odd const & getElseSuccessor() const
Retrieves the else-successor of this ODD node.
uint_fast64_t getThenOffset() const
Retrieves the then-offset of this ODD node.
This class is responsible for managing a set of typed variables and all expressions using these varia...
A bit vector that is internally represented as a vector of 64-bit values.
void set(uint_fast64_t index, bool value=true)
Sets the given truth value at the given index.
bool get(uint_fast64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
#define STORM_LOG_ERROR(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
Expression ite(Expression const &condition, Expression const &thenExpression, Expression const &elseExpression)
Expression iff(Expression const &first, Expression const &second)
SettingsManager const & manager()
Retrieves the settings manager.