Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
InternalSylvanAdd.cpp
Go to the documentation of this file.
2
4
8
11
17
18#include "storm-config.h"
19
20namespace storm {
21namespace dd {
22template<typename ValueType>
23InternalAdd<DdType::Sylvan, ValueType>::InternalAdd() : ddManager(nullptr), sylvanMtbdd() {
24 // Intentionally left empty.
25}
26
27template<typename ValueType>
29 : ddManager(ddManager), sylvanMtbdd(sylvanMtbdd) {
30 // Intentionally left empty.
31}
32
33template<typename ValueType>
35 STORM_LOG_ASSERT(mtbdd_isleaf(node), "Expected leaf, but got variable " << mtbdd_getvar(node) << ".");
36
37 bool negated = mtbdd_hascomp(node);
38 MTBDD n = mtbdd_regular(node);
39
40 if (std::is_same<ValueType, double>::value) {
41 STORM_LOG_ASSERT(mtbdd_gettype(n) == 1, "Expected a double value.");
42 return negated ? -mtbdd_getdouble(n) : mtbdd_getdouble(n);
43 } else if (std::is_same<ValueType, uint_fast64_t>::value) {
44 STORM_LOG_ASSERT(mtbdd_gettype(node) == 0, "Expected an unsigned value.");
45 return negated ? -mtbdd_getint64(node) : mtbdd_getint64(node);
46 }
47#ifdef STORM_HAVE_CARL
48 else if (std::is_same<ValueType, storm::RationalFunction>::value) {
49 STORM_LOG_ASSERT(false, "Non-specialized version of getValue() called for storm::RationalFunction value.");
50 }
51#endif
52 else {
53 STORM_LOG_ASSERT(false, "Illegal or unknown type in MTBDD.");
54 }
55}
56
57template<>
58storm::RationalNumber InternalAdd<DdType::Sylvan, storm::RationalNumber>::getValue(MTBDD const& node) {
59 STORM_LOG_ASSERT(mtbdd_isleaf(node), "Expected leaf, but got variable " << mtbdd_getvar(node) << ".");
60
61 bool negated = mtbdd_hascomp(node);
62
63 STORM_LOG_ASSERT(mtbdd_gettype(node) == sylvan_storm_rational_number_get_type(), "Expected a storm::RationalNumber value.");
64 storm_rational_number_ptr ptr = (storm_rational_number_ptr)mtbdd_getstorm_rational_number_ptr(node);
65 storm::RationalNumber* rationalNumber = (storm::RationalNumber*)(ptr);
66
67 return negated ? -(*rationalNumber) : (*rationalNumber);
68}
69
70#ifdef STORM_HAVE_CARL
71template<>
73 STORM_LOG_ASSERT(mtbdd_isleaf(node), "Expected leaf, but got variable " << mtbdd_getvar(node) << ".");
74
75 bool negated = mtbdd_hascomp(node);
76
77 STORM_LOG_ASSERT(mtbdd_gettype(node) == sylvan_storm_rational_function_get_type(), "Expected a storm::RationalFunction value.");
78 uint64_t value = mtbdd_getvalue(node);
79 storm_rational_function_ptr ptr = (storm_rational_function_ptr)value;
80
81 storm::RationalFunction* rationalFunction = (storm::RationalFunction*)(ptr);
82
83 return negated ? -(*rationalFunction) : (*rationalFunction);
84}
85#endif
86
87template<typename ValueType>
89 return this->sylvanMtbdd == other.sylvanMtbdd;
90}
91
92template<typename ValueType>
94 return this->sylvanMtbdd != other.sylvanMtbdd;
95}
96
97template<typename ValueType>
101
102template<>
107
108#ifdef STORM_HAVE_CARL
109template<>
112 return InternalAdd<DdType::Sylvan, storm::RationalFunction>(ddManager, this->sylvanMtbdd.PlusRF(other.sylvanMtbdd));
113}
114#endif
115
116template<typename ValueType>
118 this->sylvanMtbdd = this->sylvanMtbdd.Plus(other.sylvanMtbdd);
119 return *this;
120}
121
122template<>
125 this->sylvanMtbdd = this->sylvanMtbdd.PlusRN(other.sylvanMtbdd);
126 return *this;
127}
128
129#ifdef STORM_HAVE_CARL
130template<>
133 this->sylvanMtbdd = this->sylvanMtbdd.PlusRF(other.sylvanMtbdd);
134 return *this;
135}
136#endif
137
138template<typename ValueType>
142
143template<>
148
149#ifdef STORM_HAVE_CARL
150template<>
153 return InternalAdd<DdType::Sylvan, storm::RationalFunction>(ddManager, this->sylvanMtbdd.TimesRF(other.sylvanMtbdd));
154}
155#endif
156
157template<typename ValueType>
159 this->sylvanMtbdd = this->sylvanMtbdd.Times(other.sylvanMtbdd);
160 return *this;
161}
162
163template<>
166 this->sylvanMtbdd = this->sylvanMtbdd.TimesRN(other.sylvanMtbdd);
167 return *this;
168}
169
170#ifdef STORM_HAVE_CARL
171template<>
174 this->sylvanMtbdd = this->sylvanMtbdd.TimesRF(other.sylvanMtbdd);
175 return *this;
176}
177#endif
178
179template<typename ValueType>
183
184template<>
189
190#ifdef STORM_HAVE_CARL
191template<>
194 return InternalAdd<DdType::Sylvan, storm::RationalFunction>(ddManager, this->sylvanMtbdd.MinusRF(other.sylvanMtbdd));
195}
196#endif
197
198template<typename ValueType>
200 this->sylvanMtbdd = this->sylvanMtbdd.Minus(other.sylvanMtbdd);
201 return *this;
202}
203
204template<>
207 this->sylvanMtbdd = this->sylvanMtbdd.MinusRN(other.sylvanMtbdd);
208 return *this;
209}
210
211#ifdef STORM_HAVE_CARL
212template<>
215 this->sylvanMtbdd = this->sylvanMtbdd.MinusRF(other.sylvanMtbdd);
216 return *this;
217}
218#endif
219
220template<typename ValueType>
224
225template<>
230
231#ifdef STORM_HAVE_CARL
232template<>
235 return InternalAdd<DdType::Sylvan, storm::RationalFunction>(ddManager, this->sylvanMtbdd.DivideRF(other.sylvanMtbdd));
236}
237#endif
238
239template<typename ValueType>
241 this->sylvanMtbdd = this->sylvanMtbdd.Divide(other.sylvanMtbdd);
242 return *this;
243}
244
245template<>
248 this->sylvanMtbdd = this->sylvanMtbdd.DivideRN(other.sylvanMtbdd);
249 return *this;
250}
251
252#ifdef STORM_HAVE_CARL
253template<>
256 this->sylvanMtbdd = this->sylvanMtbdd.DivideRF(other.sylvanMtbdd);
257 return *this;
258}
259#endif
260
261template<typename ValueType>
263 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.Equals(other.sylvanMtbdd));
264}
265
266template<>
270
271#ifdef STORM_HAVE_CARL
272template<>
275 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.EqualsRF(other.sylvanMtbdd));
276}
277#endif
278
279template<typename ValueType>
283
284template<typename ValueType>
286 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.Less(other.sylvanMtbdd));
287}
288
289template<>
293
294#ifdef STORM_HAVE_CARL
295template<>
298 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.LessRF(other.sylvanMtbdd));
299}
300#endif
301
302template<typename ValueType>
304 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.LessOrEqual(other.sylvanMtbdd));
305}
306
307template<>
312
313#ifdef STORM_HAVE_CARL
314template<>
317 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.LessOrEqualRF(other.sylvanMtbdd));
318}
319#endif
320
321template<typename ValueType>
325
326template<typename ValueType>
330
331template<typename ValueType>
335
336template<>
341
342#ifdef STORM_HAVE_CARL
343template<>
346 return InternalAdd<DdType::Sylvan, storm::RationalFunction>(ddManager, this->sylvanMtbdd.PowRF(other.sylvanMtbdd));
347}
348#endif
349
350template<typename ValueType>
354
355template<>
360
361#ifdef STORM_HAVE_CARL
362template<>
365 STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Operation (mod) not supported by rational functions.");
366}
367#endif
368
369template<typename ValueType>
373
374template<>
377 STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Operation (logxy) not supported by rational numbers.");
378}
379
380#ifdef STORM_HAVE_CARL
381template<>
384 STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Operation (logxy) not supported by rational functions.");
385}
386#endif
387
388template<typename ValueType>
392
393template<>
397
398#ifdef STORM_HAVE_CARL
399template<>
401 return InternalAdd<DdType::Sylvan, storm::RationalFunction>(ddManager, this->sylvanMtbdd.FloorRF());
402}
403#endif
404
405template<typename ValueType>
409
410template<>
414
415#ifdef STORM_HAVE_CARL
416template<>
418 return InternalAdd<DdType::Sylvan, storm::RationalFunction>(ddManager, this->sylvanMtbdd.CeilRF());
419}
420#endif
421
422template<typename ValueType>
426
427#ifdef STORM_HAVE_CARL
428template<>
430 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Operation not supported.");
431}
432#endif
433
434template<typename ValueType>
438
439template<>
444
445#ifdef STORM_HAVE_CARL
446template<>
449 return InternalAdd<DdType::Sylvan, storm::RationalFunction>(ddManager, this->sylvanMtbdd.MinRF(other.sylvanMtbdd));
450}
451#endif
452
453template<typename ValueType>
457
458template<>
463
464#ifdef STORM_HAVE_CARL
465template<>
468 return InternalAdd<DdType::Sylvan, storm::RationalFunction>(ddManager, this->sylvanMtbdd.MaxRF(other.sylvanMtbdd));
469}
470#endif
471
472template<typename ValueType>
473template<typename TargetValueType>
475 if (std::is_same<TargetValueType, ValueType>::value) {
476 return *this;
477 }
478 STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot convert this ADD to the target type.");
479}
480
481template<>
482template<>
486
487template<>
488template<>
492
493#ifdef STORM_HAVE_CARL
494template<>
495template<>
497 return InternalAdd<DdType::Sylvan, double>(ddManager, this->sylvanMtbdd.ToDoubleRF());
498}
499#endif
500
501template<typename ValueType>
505
506template<>
511
512#ifdef STORM_HAVE_CARL
513template<>
515 InternalBdd<DdType::Sylvan> const& cube) const {
516 return InternalAdd<DdType::Sylvan, storm::RationalFunction>(ddManager, this->sylvanMtbdd.AbstractPlusRF(cube.sylvanBdd));
517}
518#endif
519
520template<typename ValueType>
524
525template<typename ValueType>
527 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.AbstractMinRepresentative(cube.sylvanBdd));
528}
529
530template<>
532 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.AbstractMinRepresentativeRN(cube.sylvanBdd));
533}
534
535template<>
540
541#ifdef STORM_HAVE_CARL
542template<>
544 InternalBdd<DdType::Sylvan> const& cube) const {
545 return InternalAdd<DdType::Sylvan, storm::RationalFunction>(ddManager, this->sylvanMtbdd.AbstractMinRF(cube.sylvanBdd));
546}
547#endif
548
549template<typename ValueType>
553
554template<typename ValueType>
556 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.AbstractMaxRepresentative(cube.sylvanBdd));
557}
558
559template<>
561 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.AbstractMaxRepresentativeRN(cube.sylvanBdd));
562}
563
564template<>
569
570#ifdef STORM_HAVE_CARL
571template<>
573 InternalBdd<DdType::Sylvan> const& cube) const {
574 return InternalAdd<DdType::Sylvan, storm::RationalFunction>(ddManager, this->sylvanMtbdd.AbstractMaxRF(cube.sylvanBdd));
575}
576#endif
577
578template<typename ValueType>
580 bool relative) const {
581 if (relative) {
582 return this->sylvanMtbdd.EqualNormRel(other.sylvanMtbdd, precision);
583 } else {
584 return this->sylvanMtbdd.EqualNorm(other.sylvanMtbdd, precision);
585 }
586}
587
588#ifdef STORM_HAVE_CARL
589template<>
591 storm::RationalNumber const& precision, bool relative) const {
592 if (relative) {
593 return this->sylvanMtbdd.EqualNormRelRN(other.sylvanMtbdd, precision);
594 } else {
595 return this->sylvanMtbdd.EqualNormRN(other.sylvanMtbdd, precision);
596 }
597}
598
599template<>
600bool InternalAdd<DdType::Sylvan, storm::RationalFunction>::equalModuloPrecision(InternalAdd<DdType::Sylvan, storm::RationalFunction> const& other,
601 storm::RationalFunction const& precision, bool relative) const {
602 if (relative) {
603 return this->sylvanMtbdd.EqualNormRelRF(other.sylvanMtbdd, precision);
604 } else {
605 return this->sylvanMtbdd.EqualNormRF(other.sylvanMtbdd, precision);
606 }
607}
608#endif
609
610template<typename ValueType>
612 std::vector<InternalBdd<DdType::Sylvan>> const& to) const {
613 std::vector<uint32_t> fromIndices;
614 std::vector<uint32_t> toIndices;
615 for (auto it1 = from.begin(), ite1 = from.end(), it2 = to.begin(); it1 != ite1; ++it1, ++it2) {
616 fromIndices.push_back(it1->getIndex());
617 fromIndices.push_back(it2->getIndex());
618 toIndices.push_back(it2->getIndex());
619 toIndices.push_back(it1->getIndex());
620 }
621 return InternalAdd<DdType::Sylvan, ValueType>(ddManager, this->sylvanMtbdd.Permute(fromIndices, toIndices));
622}
623
624template<typename ValueType>
626 std::vector<InternalBdd<DdType::Sylvan>> const& to) const {
627 std::vector<uint32_t> fromIndices;
628 std::vector<uint32_t> toIndices;
629 for (auto it1 = from.begin(), ite1 = from.end(), it2 = to.begin(); it1 != ite1; ++it1, ++it2) {
630 fromIndices.push_back(it1->getIndex());
631 toIndices.push_back(it2->getIndex());
632 }
633 return InternalAdd<DdType::Sylvan, ValueType>(ddManager, this->sylvanMtbdd.Permute(fromIndices, toIndices));
634}
635
636template<typename ValueType>
638 InternalAdd<DdType::Sylvan, ValueType> const& otherMatrix, std::vector<InternalBdd<DdType::Sylvan>> const& summationDdVariables) const {
639 InternalBdd<DdType::Sylvan> summationVariables = ddManager->getBddOne();
640 for (auto const& ddVariable : summationDdVariables) {
641 summationVariables &= ddVariable;
642 }
643
644 return InternalAdd<DdType::Sylvan, ValueType>(ddManager, this->sylvanMtbdd.AndExists(otherMatrix.sylvanMtbdd, summationVariables.getSylvanBdd()));
645}
646
647#ifdef STORM_HAVE_CARL
648template<>
650 InternalAdd<DdType::Sylvan, storm::RationalFunction> const& otherMatrix, std::vector<InternalBdd<DdType::Sylvan>> const& summationDdVariables) const {
651 InternalBdd<DdType::Sylvan> summationVariables = ddManager->getBddOne();
652 for (auto const& ddVariable : summationDdVariables) {
653 summationVariables &= ddVariable;
654 }
655
656 return InternalAdd<DdType::Sylvan, storm::RationalFunction>(ddManager,
657 this->sylvanMtbdd.AndExistsRF(otherMatrix.sylvanMtbdd, summationVariables.getSylvanBdd()));
658}
659#endif
660
661template<>
663 InternalAdd<DdType::Sylvan, storm::RationalNumber> const& otherMatrix, std::vector<InternalBdd<DdType::Sylvan>> const& summationDdVariables) const {
664 InternalBdd<DdType::Sylvan> summationVariables = ddManager->getBddOne();
665 for (auto const& ddVariable : summationDdVariables) {
666 summationVariables &= ddVariable;
667 }
668
670 this->sylvanMtbdd.AndExistsRN(otherMatrix.sylvanMtbdd, summationVariables.getSylvanBdd()));
671}
672
673template<typename ValueType>
675 InternalBdd<DdType::Sylvan> const& otherMatrix, std::vector<InternalBdd<DdType::Sylvan>> const& summationDdVariables) const {
676 InternalBdd<DdType::Sylvan> summationVariables = ddManager->getBddOne();
677 for (auto const& ddVariable : summationDdVariables) {
678 summationVariables &= ddVariable;
679 }
680
682 ddManager, this->sylvanMtbdd.AndExists(sylvan::Bdd(otherMatrix.getSylvanBdd().GetBDD()), summationVariables.getSylvanBdd()));
683}
684
685#ifdef STORM_HAVE_CARL
686template<>
688 InternalBdd<DdType::Sylvan> const& otherMatrix, std::vector<InternalBdd<DdType::Sylvan>> const& summationDdVariables) const {
689 InternalBdd<DdType::Sylvan> summationVariables = ddManager->getBddOne();
690 for (auto const& ddVariable : summationDdVariables) {
691 summationVariables &= ddVariable;
692 }
693
694 return InternalAdd<DdType::Sylvan, storm::RationalFunction>(
695 ddManager, this->sylvanMtbdd.AndExistsRF(sylvan::Bdd(otherMatrix.getSylvanBdd().GetBDD()), summationVariables.getSylvanBdd()));
696}
697#endif
698
699template<>
701 InternalBdd<DdType::Sylvan> const& otherMatrix, std::vector<InternalBdd<DdType::Sylvan>> const& summationDdVariables) const {
702 InternalBdd<DdType::Sylvan> summationVariables = ddManager->getBddOne();
703 for (auto const& ddVariable : summationDdVariables) {
704 summationVariables &= ddVariable;
705 }
706
708 ddManager, this->sylvanMtbdd.AndExistsRN(sylvan::Bdd(otherMatrix.getSylvanBdd().GetBDD()), summationVariables.getSylvanBdd()));
709}
710
711template<typename ValueType>
713 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.BddStrictThreshold(value));
714}
715
716template<>
718 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.BddStrictThresholdRN(value));
719}
720
721#ifdef STORM_HAVE_CARL
722template<>
724 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.BddStrictThresholdRF(value));
725}
726#endif
727
728template<typename ValueType>
730 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.BddThreshold(value));
731}
732
733template<>
735 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.BddThresholdRN(value));
736}
737
738#ifdef STORM_HAVE_CARL
739template<>
741 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.BddThresholdRF(value));
742}
743#endif
744
745template<typename ValueType>
747 return !this->greaterOrEqual(value);
748}
749
750template<typename ValueType>
752 return !this->greater(value);
753}
754
755template<typename ValueType>
757 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanMtbdd.NotZero());
758}
759
760template<typename ValueType>
762 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Operation (constrain) not yet implemented.");
763}
764
765template<typename ValueType>
767 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Operation (restrict) not yet implemented.");
768}
769
770template<typename ValueType>
772 return InternalBdd<DdType::Sylvan>(ddManager, sylvan::Bdd(static_cast<BDD>(this->sylvanMtbdd.Support().GetMTBDD())));
773}
774
775template<typename ValueType>
776uint_fast64_t InternalAdd<DdType::Sylvan, ValueType>::getNonZeroCount(uint_fast64_t numberOfDdVariables) const {
777 if (numberOfDdVariables == 0) {
778 return 0;
779 }
780 return static_cast<uint_fast64_t>(this->sylvanMtbdd.NonZeroCount(numberOfDdVariables));
781}
782
783template<typename ValueType>
785 return static_cast<uint_fast64_t>(this->sylvanMtbdd.CountLeaves());
786}
787
788template<typename ValueType>
790 return static_cast<uint_fast64_t>(this->sylvanMtbdd.NodeCount());
791}
792
793template<typename ValueType>
795 return getValue(this->sylvanMtbdd.Minimum().GetMTBDD());
796}
797
798template<>
800 return getValue(this->sylvanMtbdd.MinimumRN().GetMTBDD());
801}
802
803#ifdef STORM_HAVE_CARL
804template<>
806 return getValue(this->sylvanMtbdd.MinimumRF().GetMTBDD());
807}
808#endif
809
810template<typename ValueType>
812 return getValue(this->sylvanMtbdd.Maximum().GetMTBDD());
813}
814
815template<>
817 return getValue(this->sylvanMtbdd.MaximumRN().GetMTBDD());
818}
819
820#ifdef STORM_HAVE_CARL
821template<>
823 return getValue(this->sylvanMtbdd.MaximumRF().GetMTBDD());
824}
825#endif
826
827template<typename ValueType>
829 return getValue(this->sylvanMtbdd.GetMTBDD());
830}
831
832template<typename ValueType>
834 return *this == ddManager->getAddOne<ValueType>();
835}
836
837template<typename ValueType>
839 return *this == ddManager->getAddZero<ValueType>();
840}
841
842template<typename ValueType>
844 return this->sylvanMtbdd.isTerminal();
845}
846
847template<typename ValueType>
849 return static_cast<uint_fast64_t>(this->sylvanMtbdd.TopVar());
850}
851
852template<typename ValueType>
854 return this->getIndex();
855}
856
857template<typename ValueType>
858void InternalAdd<DdType::Sylvan, ValueType>::exportToDot(std::string const& filename, std::vector<std::string> const&, bool) const {
859 // Open the file, dump the DD and close it again.
860 FILE* filePointer = fopen(filename.c_str(), "a+");
861 // fopen returns a nullptr on failure
862 if (filePointer == nullptr) {
863 STORM_LOG_ERROR("Failure to open file: " << filename);
864 } else {
865 this->sylvanMtbdd.PrintDot(filePointer);
866 fclose(filePointer);
867 }
868}
869
870template<typename ValueType>
871void InternalAdd<DdType::Sylvan, ValueType>::exportToText(std::string const& filename) const {
872 // Open the file, dump the DD and close it again.
873 FILE* filePointer = fopen(filename.c_str(), "a+");
874 // fopen returns a nullptr on failure
875 if (filePointer == nullptr) {
876 STORM_LOG_ERROR("Failure to open file: " << filename);
877 } else {
878 this->sylvanMtbdd.PrintText(filePointer);
879 fclose(filePointer);
880 }
881}
882
883template<typename ValueType>
885 InternalBdd<DdType::Sylvan> const& variableCube,
886 uint_fast64_t numberOfDdVariables,
887 std::set<storm::expressions::Variable> const& metaVariables,
888 bool enumerateDontCareMetaVariables) const {
889 return AddIterator<DdType::Sylvan, ValueType>::createBeginIterator(fullDdManager, this->getSylvanMtbdd(), variableCube.getSylvanBdd(), numberOfDdVariables,
890 &metaVariables, enumerateDontCareMetaVariables);
891}
892
893template<typename ValueType>
897
898template<typename ValueType>
899Odd InternalAdd<DdType::Sylvan, ValueType>::createOdd(std::vector<uint_fast64_t> const& ddVariableIndices) const {
900 // Prepare a unique table for each level that keeps the constructed ODD nodes unique.
901 std::vector<std::unordered_map<BDD, std::shared_ptr<Odd>>> uniqueTableForLevels(ddVariableIndices.size() + 1);
902
903 // Now construct the ODD structure from the ADD.
904 std::shared_ptr<Odd> rootOdd =
905 createOddRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), 0, ddVariableIndices.size(), ddVariableIndices, uniqueTableForLevels);
906
907 // Return a copy of the root node to remove the shared_ptr encapsulation.
908 return Odd(*rootOdd);
909}
910
911template<typename ValueType>
912std::shared_ptr<Odd> InternalAdd<DdType::Sylvan, ValueType>::createOddRec(BDD dd, uint_fast64_t currentLevel, uint_fast64_t maxLevel,
913 std::vector<uint_fast64_t> const& ddVariableIndices,
914 std::vector<std::unordered_map<BDD, std::shared_ptr<Odd>>>& uniqueTableForLevels) {
915 // Check whether the ODD for this node has already been computed (for this level) and if so, return this instead.
916 auto const& iterator = uniqueTableForLevels[currentLevel].find(dd);
917 if (iterator != uniqueTableForLevels[currentLevel].end()) {
918 return iterator->second;
919 } else {
920 // Otherwise, we need to recursively compute the ODD.
921
922 // If we are already past the maximal level that is to be considered, we can simply create an Odd without
923 // successors
924 if (currentLevel == maxLevel) {
925 uint_fast64_t elseOffset = 0;
926 uint_fast64_t thenOffset = 0;
927
928 STORM_LOG_ASSERT(mtbdd_isleaf(dd), "Expected leaf at last level.");
929
930 // If the DD is not the zero leaf, then the then-offset is 1.
931 if (!mtbdd_iszero(dd)) {
932 thenOffset = 1;
933 }
934
935 auto oddNode = std::make_shared<Odd>(nullptr, elseOffset, nullptr, thenOffset);
936 uniqueTableForLevels[currentLevel].emplace(dd, oddNode);
937 return oddNode;
938 } else if (mtbdd_isleaf(dd) || ddVariableIndices[currentLevel] < mtbdd_getvar(dd)) {
939 // If we skipped the level in the DD, we compute the ODD just for the else-successor and use the same
940 // node for the then-successor as well.
941 std::shared_ptr<Odd> elseNode = createOddRec(dd, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels);
942 std::shared_ptr<Odd> thenNode = elseNode;
943 auto oddNode = std::make_shared<Odd>(elseNode, elseNode->getElseOffset() + elseNode->getThenOffset(), thenNode,
944 thenNode->getElseOffset() + thenNode->getThenOffset());
945 uniqueTableForLevels[currentLevel].emplace(dd, oddNode);
946 return oddNode;
947 } else {
948 // Otherwise, we compute the ODDs for both the then- and else successors.
949 std::shared_ptr<Odd> elseNode = createOddRec(mtbdd_regular(mtbdd_getlow(dd)), currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels);
950 std::shared_ptr<Odd> thenNode = createOddRec(mtbdd_regular(mtbdd_gethigh(dd)), currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels);
951
952 uint_fast64_t totalElseOffset = elseNode->getElseOffset() + elseNode->getThenOffset();
953 uint_fast64_t totalThenOffset = thenNode->getElseOffset() + thenNode->getThenOffset();
954
955 auto oddNode = std::make_shared<Odd>(elseNode, totalElseOffset, thenNode, totalThenOffset);
956 uniqueTableForLevels[currentLevel].emplace(dd, oddNode);
957 return oddNode;
958 }
959 }
960}
961
962template<typename ValueType>
966
967template<typename ValueType>
968void InternalAdd<DdType::Sylvan, ValueType>::composeWithExplicitVector(storm::dd::Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
969 std::vector<ValueType>& targetVector,
970 std::function<ValueType(ValueType const&, ValueType const&)> const& function) const {
971 forEachRec(this->getSylvanMtbdd().GetMTBDD(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices,
972 [&function, &targetVector](uint64_t const& offset, ValueType const& value) { targetVector[offset] = function(targetVector[offset], value); });
973}
974
975template<typename ValueType>
976void InternalAdd<DdType::Sylvan, ValueType>::composeWithExplicitVector(storm::dd::Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
977 std::vector<uint_fast64_t> const& offsets, std::vector<ValueType>& targetVector,
978 std::function<ValueType(ValueType const&, ValueType const&)> const& function) const {
979 forEachRec(this->getSylvanMtbdd().GetMTBDD(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices,
980 [&function, &targetVector, &offsets](uint64_t const& offset, ValueType const& value) {
981 ValueType& targetValue = targetVector[offsets[offset]];
982 targetValue = function(targetValue, value);
983 });
984}
985
986template<typename ValueType>
987void InternalAdd<DdType::Sylvan, ValueType>::forEach(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
988 std::function<void(uint64_t const&, ValueType const&)> const& function) const {
989 forEachRec(this->getSylvanMtbdd().GetMTBDD(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, function);
990}
991
992template<typename ValueType>
993void InternalAdd<DdType::Sylvan, ValueType>::forEachRec(MTBDD dd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset,
994 Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
995 std::function<void(uint64_t const&, ValueType const&)> const& function) const {
996 // For the empty DD, we do not need to add any entries.
997 if (mtbdd_isleaf(dd) && mtbdd_iszero(dd)) {
998 return;
999 }
1000
1001 // If we are at the maximal level, the value to be set is stored as a constant in the DD.
1002 if (currentLevel == maxLevel) {
1003 function(currentOffset, getValue(dd));
1004 } else if (mtbdd_isleaf(dd) || ddVariableIndices[currentLevel] < mtbdd_getvar(dd)) {
1005 // If we skipped a level, we need to enumerate the explicit entries for the case in which the bit is set
1006 // and for the one in which it is not set.
1007 forEachRec(dd, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, function);
1008 forEachRec(dd, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, function);
1009 } else {
1010 // Otherwise, we simply recursively call the function for both (different) cases.
1011 MTBDD thenNode = mtbdd_gethigh(dd);
1012 MTBDD elseNode = mtbdd_getlow(dd);
1013
1014 forEachRec(elseNode, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, function);
1015 forEachRec(thenNode, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, function);
1016 }
1017}
1018
1019template<typename ValueType>
1020std::vector<uint64_t> InternalAdd<DdType::Sylvan, ValueType>::decodeGroupLabels(std::vector<uint_fast64_t> const& ddGroupVariableIndices,
1021 storm::storage::BitVector const& ddLabelVariableIndices) const {
1022 std::vector<uint64_t> result;
1023 decodeGroupLabelsRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), result, ddGroupVariableIndices, ddLabelVariableIndices, 0,
1024 ddGroupVariableIndices.size(), 0);
1025 return result;
1026}
1027
1028template<typename ValueType>
1029void InternalAdd<DdType::Sylvan, ValueType>::decodeGroupLabelsRec(MTBDD dd, std::vector<uint64_t>& labels,
1030 std::vector<uint_fast64_t> const& ddGroupVariableIndices,
1031 storm::storage::BitVector const& ddLabelVariableIndices, uint_fast64_t currentLevel,
1032 uint_fast64_t maxLevel, uint64_t label) const {
1033 // For the empty DD, we do not need to create a group.
1034 if (mtbdd_isleaf(dd) && mtbdd_iszero(dd)) {
1035 return;
1036 }
1037
1038 if (currentLevel == maxLevel) {
1039 labels.push_back(label);
1040 } else {
1041 uint64_t elseLabel = label;
1042 uint64_t thenLabel = label;
1043
1044 if (ddLabelVariableIndices.get(currentLevel)) {
1045 elseLabel <<= 1;
1046 thenLabel = (thenLabel << 1) | 1;
1047 }
1048
1049 if (mtbdd_isleaf(dd) || ddGroupVariableIndices[currentLevel] < mtbdd_getvar(dd)) {
1050 decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, elseLabel);
1051 decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, thenLabel);
1052 } else {
1053 // Otherwise, we compute the ODDs for both the then- and else successors.
1054 MTBDD thenDdNode = mtbdd_gethigh(dd);
1055 MTBDD elseDdNode = mtbdd_getlow(dd);
1056
1057 decodeGroupLabelsRec(mtbdd_regular(elseDdNode), labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, elseLabel);
1058 decodeGroupLabelsRec(mtbdd_regular(thenDdNode), labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, thenLabel);
1059 }
1060 }
1061}
1062
1063template<typename ValueType>
1064std::vector<InternalAdd<DdType::Sylvan, ValueType>> InternalAdd<DdType::Sylvan, ValueType>::splitIntoGroups(
1065 std::vector<uint_fast64_t> const& ddGroupVariableIndices) const {
1066 std::vector<InternalAdd<DdType::Sylvan, ValueType>> result;
1067 splitIntoGroupsRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), mtbdd_hascomp(this->getSylvanMtbdd().GetMTBDD()), result, ddGroupVariableIndices, 0,
1068 ddGroupVariableIndices.size());
1069 return result;
1070}
1071
1072template<typename ValueType>
1073std::vector<std::pair<InternalAdd<DdType::Sylvan, ValueType>, InternalAdd<DdType::Sylvan, ValueType>>> InternalAdd<DdType::Sylvan, ValueType>::splitIntoGroups(
1074 InternalAdd<DdType::Sylvan, ValueType> vector, std::vector<uint_fast64_t> const& ddGroupVariableIndices) const {
1075 std::vector<std::pair<InternalAdd<DdType::Sylvan, ValueType>, InternalAdd<DdType::Sylvan, ValueType>>> result;
1076 splitIntoGroupsRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), mtbdd_hascomp(this->getSylvanMtbdd().GetMTBDD()),
1077 mtbdd_regular(vector.getSylvanMtbdd().GetMTBDD()), mtbdd_hascomp(vector.getSylvanMtbdd().GetMTBDD()), result, ddGroupVariableIndices, 0,
1078 ddGroupVariableIndices.size());
1079 return result;
1080}
1081
1082template<typename ValueType>
1083std::vector<std::vector<InternalAdd<DdType::Sylvan, ValueType>>> InternalAdd<DdType::Sylvan, ValueType>::splitIntoGroups(
1084 std::vector<InternalAdd<DdType::Sylvan, ValueType>> const& vectors, std::vector<uint_fast64_t> const& ddGroupVariableIndices) const {
1085 std::vector<std::vector<InternalAdd<DdType::Sylvan, ValueType>>> result;
1086 std::vector<MTBDD> dds;
1087 storm::storage::BitVector negatedDds(vectors.size() + 1);
1088 for (auto const& vector : vectors) {
1089 negatedDds.set(dds.size(), mtbdd_hascomp(vector.getSylvanMtbdd().GetMTBDD()));
1090 dds.push_back(mtbdd_regular(vector.getSylvanMtbdd().GetMTBDD()));
1091 }
1092 dds.push_back(this->getSylvanMtbdd().GetMTBDD());
1093 negatedDds.set(vectors.size(), mtbdd_hascomp(this->getSylvanMtbdd().GetMTBDD()));
1094
1095 splitIntoGroupsRec(dds, negatedDds, result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size());
1096 return result;
1097}
1098
1099template<typename ValueType>
1101 std::vector<uint_fast64_t> const& ddGroupVariableIndices, uint_fast64_t currentLevel,
1102 uint_fast64_t maxLevel) const {
1103 // For the empty DD, we do not need to create a group.
1104 if (mtbdd_isleaf(dd) && mtbdd_iszero(dd)) {
1105 return;
1106 }
1107
1108 if (currentLevel == maxLevel) {
1109 groups.push_back(InternalAdd<DdType::Sylvan, ValueType>(ddManager, negated ? sylvan::Mtbdd(dd).Negate() : sylvan::Mtbdd(dd)));
1110 } else if (mtbdd_isleaf(dd) || ddGroupVariableIndices[currentLevel] < mtbdd_getvar(dd)) {
1111 splitIntoGroupsRec(dd, negated, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
1112 splitIntoGroupsRec(dd, negated, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
1113 } else {
1114 // Otherwise, we compute the ODDs for both the then- and else successors.
1115 MTBDD thenDdNode = mtbdd_gethigh(dd);
1116 MTBDD elseDdNode = mtbdd_getlow(dd);
1117
1118 // Determine whether we have to evaluate the successors as if they were complemented.
1119 bool elseComplemented = mtbdd_hascomp(elseDdNode) ^ negated;
1120 bool thenComplemented = mtbdd_hascomp(thenDdNode) ^ negated;
1121
1122 // FIXME: We first traverse the else successor (unlike other variants of this method).
1123 // Otherwise, the GameBasedMdpModelCheckerTest would not terminate. See github issue #64
1124 splitIntoGroupsRec(mtbdd_regular(elseDdNode), elseComplemented, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
1125 splitIntoGroupsRec(mtbdd_regular(thenDdNode), thenComplemented, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
1126 }
1127}
1128
1129template<typename ValueType>
1130void InternalAdd<DdType::Sylvan, ValueType>::splitIntoGroupsRec(
1131 MTBDD dd1, bool negated1, MTBDD dd2, bool negated2,
1132 std::vector<std::pair<InternalAdd<DdType::Sylvan, ValueType>, InternalAdd<DdType::Sylvan, ValueType>>>& groups,
1133 std::vector<uint_fast64_t> const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const {
1134 // For the empty DD, we do not need to create a group.
1135 if (mtbdd_isleaf(dd1) && mtbdd_isleaf(dd2) && mtbdd_iszero(dd1) && mtbdd_iszero(dd2)) {
1136 return;
1137 }
1138
1139 if (currentLevel == maxLevel) {
1140 groups.push_back(std::make_pair(InternalAdd<DdType::Sylvan, ValueType>(ddManager, negated1 ? sylvan::Mtbdd(dd1).Negate() : sylvan::Mtbdd(dd1)),
1141 InternalAdd<DdType::Sylvan, ValueType>(ddManager, negated2 ? sylvan::Mtbdd(dd2).Negate() : sylvan::Mtbdd(dd2))));
1142 } else if (mtbdd_isleaf(dd1) || ddGroupVariableIndices[currentLevel] < mtbdd_getvar(dd1)) {
1143 if (mtbdd_isleaf(dd2) || ddGroupVariableIndices[currentLevel] < mtbdd_getvar(dd2)) {
1144 splitIntoGroupsRec(dd1, negated1, dd2, negated2, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
1145 splitIntoGroupsRec(dd1, negated1, dd2, negated2, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
1146 } else {
1147 MTBDD dd2ThenNode = mtbdd_gethigh(dd2);
1148 MTBDD dd2ElseNode = mtbdd_getlow(dd2);
1149
1150 // Determine whether we have to evaluate the successors as if they were complemented.
1151 bool elseComplemented = mtbdd_hascomp(dd2ElseNode) ^ negated2;
1152 bool thenComplemented = mtbdd_hascomp(dd2ThenNode) ^ negated2;
1153
1154 splitIntoGroupsRec(dd1, negated1, mtbdd_regular(dd2ThenNode), thenComplemented, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
1155 splitIntoGroupsRec(dd1, negated1, mtbdd_regular(dd2ElseNode), elseComplemented, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
1156 }
1157 } else if (mtbdd_isleaf(dd2) || ddGroupVariableIndices[currentLevel] < mtbdd_getvar(dd2)) {
1158 MTBDD dd1ThenNode = mtbdd_gethigh(dd1);
1159 MTBDD dd1ElseNode = mtbdd_getlow(dd1);
1160
1161 // Determine whether we have to evaluate the successors as if they were complemented.
1162 bool elseComplemented = mtbdd_hascomp(dd1ElseNode) ^ negated1;
1163 bool thenComplemented = mtbdd_hascomp(dd1ThenNode) ^ negated1;
1164
1165 splitIntoGroupsRec(mtbdd_regular(dd1ThenNode), thenComplemented, dd2, negated2, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
1166 splitIntoGroupsRec(mtbdd_regular(dd1ElseNode), elseComplemented, dd2, negated2, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
1167 } else {
1168 MTBDD dd1ThenNode = mtbdd_gethigh(dd1);
1169 MTBDD dd1ElseNode = mtbdd_getlow(dd1);
1170 MTBDD dd2ThenNode = mtbdd_gethigh(dd2);
1171 MTBDD dd2ElseNode = mtbdd_getlow(dd2);
1172
1173 // Determine whether we have to evaluate the successors as if they were complemented.
1174 bool dd1ElseComplemented = mtbdd_hascomp(dd1ElseNode) ^ negated1;
1175 bool dd1ThenComplemented = mtbdd_hascomp(dd1ThenNode) ^ negated1;
1176 bool dd2ElseComplemented = mtbdd_hascomp(dd2ElseNode) ^ negated2;
1177 bool dd2ThenComplemented = mtbdd_hascomp(dd2ThenNode) ^ negated2;
1178
1179 splitIntoGroupsRec(mtbdd_regular(dd1ThenNode), dd1ThenComplemented, mtbdd_regular(dd2ThenNode), dd2ThenComplemented, groups, ddGroupVariableIndices,
1180 currentLevel + 1, maxLevel);
1181 splitIntoGroupsRec(mtbdd_regular(dd1ElseNode), dd1ElseComplemented, mtbdd_regular(dd2ElseNode), dd2ElseComplemented, groups, ddGroupVariableIndices,
1182 currentLevel + 1, maxLevel);
1183 }
1184}
1185
1186template<typename ValueType>
1187void InternalAdd<DdType::Sylvan, ValueType>::splitIntoGroupsRec(std::vector<MTBDD> const& dds, storm::storage::BitVector const& negatedDds,
1188 std::vector<std::vector<InternalAdd<DdType::Sylvan, ValueType>>>& groups,
1189 std::vector<uint_fast64_t> const& ddGroupVariableIndices, uint_fast64_t currentLevel,
1190 uint_fast64_t maxLevel) const {
1191 // For the empty DD, we do not need to create a group.
1192 {
1193 bool emptyDd = true;
1194 for (auto const& dd : dds) {
1195 if (!(mtbdd_isleaf(dd) && mtbdd_iszero(dd))) {
1196 emptyDd = false;
1197 break;
1198 }
1199 }
1200 if (emptyDd) {
1201 return;
1202 }
1203 }
1204
1205 if (currentLevel == maxLevel) {
1206 std::vector<InternalAdd<DdType::Sylvan, ValueType>> newGroup;
1207 for (uint64_t ddIndex = 0; ddIndex < dds.size(); ++ddIndex) {
1208 newGroup.emplace_back(ddManager, negatedDds.get(ddIndex) ? sylvan::Mtbdd(dds[ddIndex]).Negate() : sylvan::Mtbdd(dds[ddIndex]));
1209 }
1210 groups.push_back(std::move(newGroup));
1211 } else {
1212 std::vector<MTBDD> thenSubDds(dds), elseSubDds(dds);
1213 storm::storage::BitVector thenNegatedSubDds(negatedDds), elseNegatedSubDds(negatedDds);
1214 for (uint64_t ddIndex = 0; ddIndex < dds.size(); ++ddIndex) {
1215 auto const& dd = dds[ddIndex];
1216 if (!mtbdd_isleaf(dd) && ddGroupVariableIndices[currentLevel] == mtbdd_getvar(dd)) {
1217 MTBDD ddThenNode = mtbdd_gethigh(dd);
1218 MTBDD ddElseNode = mtbdd_getlow(dd);
1219 thenSubDds[ddIndex] = mtbdd_regular(ddThenNode);
1220 elseSubDds[ddIndex] = mtbdd_regular(ddElseNode);
1221 // Determine whether we have to evaluate the successors as if they were complemented.
1222 thenNegatedSubDds.set(ddIndex, mtbdd_hascomp(ddThenNode) ^ negatedDds.get(ddIndex));
1223 elseNegatedSubDds.set(ddIndex, mtbdd_hascomp(ddElseNode) ^ negatedDds.get(ddIndex));
1224 }
1225 }
1226 splitIntoGroupsRec(thenSubDds, thenNegatedSubDds, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
1227 splitIntoGroupsRec(elseSubDds, elseNegatedSubDds, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
1228 }
1229}
1230
1231template<typename ValueType>
1232void InternalAdd<DdType::Sylvan, ValueType>::toMatrixComponents(std::vector<uint_fast64_t> const& rowGroupIndices, std::vector<uint_fast64_t>& rowIndications,
1233 std::vector<storm::storage::MatrixEntry<uint_fast64_t, ValueType>>& columnsAndValues,
1234 Odd const& rowOdd, Odd const& columnOdd, std::vector<uint_fast64_t> const& ddRowVariableIndices,
1235 std::vector<uint_fast64_t> const& ddColumnVariableIndices, bool writeValues) const {
1236 return toMatrixComponentsRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), mtbdd_hascomp(this->getSylvanMtbdd().GetMTBDD()), rowGroupIndices,
1237 rowIndications, columnsAndValues, rowOdd, columnOdd, 0, 0, ddRowVariableIndices.size() + ddColumnVariableIndices.size(), 0, 0,
1238 ddRowVariableIndices, ddColumnVariableIndices, writeValues);
1239}
1240
1241template<typename ValueType>
1242void InternalAdd<DdType::Sylvan, ValueType>::toMatrixComponentsRec(MTBDD dd, bool negated, std::vector<uint_fast64_t> const& rowGroupOffsets,
1243 std::vector<uint_fast64_t>& rowIndications,
1244 std::vector<storm::storage::MatrixEntry<uint_fast64_t, ValueType>>& columnsAndValues,
1245 Odd const& rowOdd, Odd const& columnOdd, uint_fast64_t currentRowLevel,
1246 uint_fast64_t currentColumnLevel, uint_fast64_t maxLevel, uint_fast64_t currentRowOffset,
1247 uint_fast64_t currentColumnOffset, std::vector<uint_fast64_t> const& ddRowVariableIndices,
1248 std::vector<uint_fast64_t> const& ddColumnVariableIndices, bool generateValues) const {
1249 // For the empty DD, we do not need to add any entries.
1250 if (mtbdd_isleaf(dd) && mtbdd_iszero(dd)) {
1251 return;
1252 }
1253
1254 // If we are at the maximal level, the value to be set is stored as a constant in the DD.
1255 if (currentRowLevel + currentColumnLevel == maxLevel) {
1256 if (generateValues) {
1257 columnsAndValues[rowIndications[rowGroupOffsets[currentRowOffset]]] =
1258 storm::storage::MatrixEntry<uint_fast64_t, ValueType>(currentColumnOffset, negated ? -getValue(dd) : getValue(dd));
1259 }
1260 ++rowIndications[rowGroupOffsets[currentRowOffset]];
1261 } else {
1262 MTBDD elseElse;
1263 MTBDD elseThen;
1264 MTBDD thenElse;
1265 MTBDD thenThen;
1266
1267 if (mtbdd_isleaf(dd) || ddColumnVariableIndices[currentColumnLevel] < mtbdd_getvar(dd)) {
1268 elseElse = elseThen = thenElse = thenThen = dd;
1269 } else if (ddRowVariableIndices[currentColumnLevel] < mtbdd_getvar(dd)) {
1270 elseElse = thenElse = mtbdd_getlow(dd);
1271 elseThen = thenThen = mtbdd_gethigh(dd);
1272 } else {
1273 MTBDD elseNode = mtbdd_getlow(dd);
1274 if (mtbdd_isleaf(elseNode) || ddColumnVariableIndices[currentColumnLevel] < mtbdd_getvar(elseNode)) {
1275 elseElse = elseThen = elseNode;
1276 } else {
1277 elseElse = mtbdd_getlow(elseNode);
1278 elseThen = mtbdd_gethigh(elseNode);
1279 }
1280
1281 MTBDD thenNode = mtbdd_gethigh(dd);
1282 if (mtbdd_isleaf(thenNode) || ddColumnVariableIndices[currentColumnLevel] < mtbdd_getvar(thenNode)) {
1283 thenElse = thenThen = thenNode;
1284 } else {
1285 thenElse = mtbdd_getlow(thenNode);
1286 thenThen = mtbdd_gethigh(thenNode);
1287 }
1288 }
1289
1290 // Visit else-else.
1291 toMatrixComponentsRec(mtbdd_regular(elseElse), mtbdd_hascomp(elseElse) ^ negated, rowGroupOffsets, rowIndications, columnsAndValues,
1292 rowOdd.getElseSuccessor(), columnOdd.getElseSuccessor(), currentRowLevel + 1, currentColumnLevel + 1, maxLevel, currentRowOffset,
1293 currentColumnOffset, ddRowVariableIndices, ddColumnVariableIndices, generateValues);
1294 // Visit else-then.
1295 toMatrixComponentsRec(mtbdd_regular(elseThen), mtbdd_hascomp(elseThen) ^ negated, rowGroupOffsets, rowIndications, columnsAndValues,
1296 rowOdd.getElseSuccessor(), columnOdd.getThenSuccessor(), currentRowLevel + 1, currentColumnLevel + 1, maxLevel, currentRowOffset,
1297 currentColumnOffset + columnOdd.getElseOffset(), ddRowVariableIndices, ddColumnVariableIndices, generateValues);
1298 // Visit then-else.
1299 toMatrixComponentsRec(mtbdd_regular(thenElse), mtbdd_hascomp(thenElse) ^ negated, rowGroupOffsets, rowIndications, columnsAndValues,
1300 rowOdd.getThenSuccessor(), columnOdd.getElseSuccessor(), currentRowLevel + 1, currentColumnLevel + 1, maxLevel,
1301 currentRowOffset + rowOdd.getElseOffset(), currentColumnOffset, ddRowVariableIndices, ddColumnVariableIndices, generateValues);
1302 // Visit then-then.
1303 toMatrixComponentsRec(mtbdd_regular(thenThen), mtbdd_hascomp(thenThen) ^ negated, rowGroupOffsets, rowIndications, columnsAndValues,
1304 rowOdd.getThenSuccessor(), columnOdd.getThenSuccessor(), currentRowLevel + 1, currentColumnLevel + 1, maxLevel,
1305 currentRowOffset + rowOdd.getElseOffset(), currentColumnOffset + columnOdd.getElseOffset(), ddRowVariableIndices,
1306 ddColumnVariableIndices, generateValues);
1307 }
1308}
1309
1310template<typename ValueType>
1312 std::vector<ValueType> const& values, storm::dd::Odd const& odd,
1313 std::vector<uint_fast64_t> const& ddVariableIndices) {
1314 uint_fast64_t offset = 0;
1315 return InternalAdd<DdType::Sylvan, ValueType>(ddManager, sylvan::Mtbdd(fromVectorRec(offset, 0, ddVariableIndices.size(), values, odd, ddVariableIndices)));
1316}
1317
1318template<typename ValueType>
1319MTBDD InternalAdd<DdType::Sylvan, ValueType>::fromVectorRec(uint_fast64_t& currentOffset, uint_fast64_t currentLevel, uint_fast64_t maxLevel,
1320 std::vector<ValueType> const& values, Odd const& odd,
1321 std::vector<uint_fast64_t> const& ddVariableIndices) {
1322 if (currentLevel == maxLevel) {
1323 // If we are in a terminal node of the ODD, we need to check whether the then-offset of the ODD is one
1324 // (meaning the encoding is a valid one) or zero (meaning the encoding is not valid). Consequently, we
1325 // need to copy the next value of the vector iff the then-offset is greater than zero.
1326 if (odd.getThenOffset() > 0) {
1327 return getLeaf(values[currentOffset++]);
1328 } else {
1329 return getLeaf(storm::utility::zero<ValueType>());
1330 }
1331 } else {
1332 // If the total offset is zero, we can just return the constant zero DD.
1333 if (odd.getThenOffset() + odd.getElseOffset() == 0) {
1334 return getLeaf(storm::utility::zero<ValueType>());
1335 }
1336
1337 // Determine the new else-successor.
1338 MTBDD elseSuccessor;
1339 if (odd.getElseOffset() > 0) {
1340 elseSuccessor = fromVectorRec(currentOffset, currentLevel + 1, maxLevel, values, odd.getElseSuccessor(), ddVariableIndices);
1341 } else {
1342 elseSuccessor = getLeaf(storm::utility::zero<ValueType>());
1343 }
1344 mtbdd_refs_push(elseSuccessor);
1345
1346 // Determine the new then-successor.
1347 MTBDD thenSuccessor;
1348 if (odd.getThenOffset() > 0) {
1349 thenSuccessor = fromVectorRec(currentOffset, currentLevel + 1, maxLevel, values, odd.getThenSuccessor(), ddVariableIndices);
1350 } else {
1351 thenSuccessor = getLeaf(storm::utility::zero<ValueType>());
1352 }
1353 mtbdd_refs_push(thenSuccessor);
1354
1355 // Create a node representing ITE(currentVar, thenSuccessor, elseSuccessor);
1356 MTBDD currentVar = mtbdd_makenode(ddVariableIndices[currentLevel], mtbdd_false, mtbdd_true);
1357 mtbdd_refs_push(thenSuccessor);
1358 MTBDD result = mtbdd_ite(currentVar, thenSuccessor, elseSuccessor);
1359
1360 // Dispose of the intermediate results
1361 mtbdd_refs_pop(3);
1362
1363 return result;
1364 }
1365}
1366
1367template<typename ValueType>
1368MTBDD InternalAdd<DdType::Sylvan, ValueType>::getLeaf(double value) {
1369 return mtbdd_double(value);
1370}
1371
1372template<typename ValueType>
1373MTBDD InternalAdd<DdType::Sylvan, ValueType>::getLeaf(uint_fast64_t value) {
1374 return mtbdd_int64(value);
1375}
1376
1377template<typename ValueType>
1378MTBDD InternalAdd<DdType::Sylvan, ValueType>::getLeaf(storm::RationalFunction const& value) {
1379 storm_rational_function_ptr ptr = (storm_rational_function_ptr)(&value);
1380 return mtbdd_storm_rational_function(ptr);
1381}
1382
1383template<typename ValueType>
1384MTBDD InternalAdd<DdType::Sylvan, ValueType>::getLeaf(storm::RationalNumber const& value) {
1385 storm_rational_function_ptr ptr = (storm_rational_number_ptr)(&value);
1386 return mtbdd_storm_rational_number(ptr);
1387}
1388
1389template<typename ValueType>
1391 return sylvanMtbdd;
1392}
1393
1394template<typename ValueType>
1396 std::stringstream ss;
1397 ss << this->getSylvanMtbdd().GetMTBDD();
1398 return ss.str();
1399}
1400
1403
1405
1406#ifdef STORM_HAVE_CARL
1408#endif
1409} // namespace dd
1410} // namespace storm
InternalAdd< DdType::Sylvan, double > toValueType() const
InternalAdd< DdType::Sylvan, storm::RationalNumber > operator+(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &other) const
InternalAdd< DdType::Sylvan, storm::RationalNumber > multiplyMatrix(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &otherMatrix, std::vector< InternalBdd< DdType::Sylvan > > const &summationDdVariables) const
storm::RationalNumber getValue(MTBDD const &node)
InternalBdd< DdType::CUDD > lessOrEqual(storm::RationalNumber const &value) const
InternalAdd< DdType::Sylvan, storm::RationalNumber > maximum(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &other) const
storm::RationalNumber getMin() const
InternalAdd< DdType::Sylvan, storm::RationalNumber > & operator+=(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &other)
InternalAdd< DdType::Sylvan, storm::RationalNumber > & operator-=(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &other)
InternalAdd< DdType::Sylvan, storm::RationalNumber > operator*(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &other) const
InternalAdd< DdType::Sylvan, storm::RationalNumber > & operator/=(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &other)
InternalBdd< DdType::CUDD > greaterOrEqual(storm::RationalNumber const &value) const
InternalBdd< DdType::Sylvan > maxAbstractRepresentative(InternalBdd< DdType::Sylvan > const &cube) const
InternalAdd< DdType::Sylvan, storm::RationalNumber > & operator*=(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &other)
InternalBdd< DdType::Sylvan > equals(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &other) const
storm::RationalNumber getMax() const
InternalBdd< DdType::Sylvan > minAbstractRepresentative(InternalBdd< DdType::Sylvan > const &cube) const
InternalAdd< DdType::Sylvan, storm::RationalNumber > operator-(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &other) const
InternalAdd< DdType::Sylvan, storm::RationalNumber > ceil() const
InternalAdd< DdType::Sylvan, storm::RationalNumber > sumAbstract(InternalBdd< DdType::Sylvan > const &cube) const
InternalAdd< DdType::Sylvan, storm::RationalNumber > floor() const
InternalAdd< DdType::Sylvan, storm::RationalNumber > pow(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &other) const
bool equalModuloPrecision(InternalAdd< DdType::CUDD, storm::RationalNumber > const &, storm::RationalNumber const &, bool) const
InternalAdd< DdType::Sylvan, storm::RationalNumber > maxAbstract(InternalBdd< DdType::Sylvan > const &cube) const
InternalAdd< DdType::Sylvan, storm::RationalNumber > minAbstract(InternalBdd< DdType::Sylvan > const &cube) const
InternalBdd< DdType::CUDD > less(storm::RationalNumber const &value) const
InternalAdd< DdType::Sylvan, storm::RationalNumber > logxy(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &) const
DdNode * fromVectorRec(::DdManager *manager, uint_fast64_t &currentOffset, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector< storm::RationalNumber > const &values, Odd const &odd, std::vector< uint_fast64_t > const &ddVariableIndices)
InternalAdd< DdType::Sylvan, storm::RationalNumber > operator/(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &other) const
InternalAdd< DdType::Sylvan, storm::RationalNumber > minimum(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &other) const
InternalAdd< DdType::Sylvan, storm::RationalNumber > mod(InternalAdd< DdType::Sylvan, storm::RationalNumber > const &other) const
InternalBdd< DdType::CUDD > greater(storm::RationalNumber const &value) const
Odd const & getThenSuccessor() const
Retrieves the then-successor of this ODD node.
Definition Odd.cpp:23
uint_fast64_t getElseOffset() const
Retrieves the else-offset of this ODD node.
Definition Odd.cpp:31
Odd const & getElseSuccessor() const
Retrieves the else-successor of this ODD node.
Definition Odd.cpp:27
uint_fast64_t getThenOffset() const
Retrieves the then-offset of this ODD node.
Definition Odd.cpp:39
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:18
void set(uint_fast64_t index, bool value=true)
Sets the given truth value at the given index.
size_t size() const
Retrieves the number of bits this bit vector can store.
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)
Definition logging.h:31
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
SFTBDDChecker::ValueType ValueType
LabParser.cpp.
Definition cli.cpp:18