Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
InternalSylvanBdd.cpp
Go to the documentation of this file.
2
3#include <boost/functional/hash.hpp>
4
14
15namespace storm {
16namespace dd {
17
18#ifdef STORM_HAVE_SYLVAN
19InternalBdd<DdType::Sylvan>::InternalBdd() : ddManager(nullptr), sylvanBdd() {
20 // Intentionally left empty.
21}
22
23InternalBdd<DdType::Sylvan>::InternalBdd(InternalDdManager<DdType::Sylvan> const* ddManager, sylvan::Bdd const& sylvanBdd)
24 : ddManager(ddManager), sylvanBdd(sylvanBdd) {
25 // Intentionally left empty.
26}
27
28InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::fromVector(InternalDdManager<DdType::Sylvan> const* ddManager, Odd const& odd,
29 std::vector<uint_fast64_t> const& sortedDdVariableIndices,
30 std::function<bool(uint64_t)> const& filter) {
31 uint_fast64_t offset = 0;
32 return InternalBdd<DdType::Sylvan>(ddManager, sylvan::Bdd(fromVectorRec(offset, 0, sortedDdVariableIndices.size(), odd, sortedDdVariableIndices, filter)));
33}
34
35BDD InternalBdd<DdType::Sylvan>::fromVectorRec(uint_fast64_t& currentOffset, uint_fast64_t currentLevel, uint_fast64_t maxLevel, Odd const& odd,
36 std::vector<uint_fast64_t> const& ddVariableIndices, std::function<bool(uint64_t)> const& filter) {
37 if (currentLevel == maxLevel) {
38 // If we are in a terminal node of the ODD, we need to check whether the then-offset of the ODD is one
39 // (meaning the encoding is a valid one) or zero (meaning the encoding is not valid). Consequently, we
40 // need to copy the next value of the vector iff the then-offset is greater than zero.
41 if (odd.getThenOffset() > 0) {
42 if (filter(currentOffset++)) {
43 return sylvan_true;
44 } else {
45 return sylvan_false;
46 }
47 } else {
48 return sylvan_false;
49 }
50 } else {
51 // If the total offset is zero, we can just return the constant zero DD.
52 if (odd.getThenOffset() + odd.getElseOffset() == 0) {
53 return sylvan_false;
54 }
55
56 // Determine the new else-successor.
57 BDD elseSuccessor;
58 if (odd.getElseOffset() > 0) {
59 elseSuccessor = fromVectorRec(currentOffset, currentLevel + 1, maxLevel, odd.getElseSuccessor(), ddVariableIndices, filter);
60 } else {
61 elseSuccessor = sylvan_false;
62 }
63 bdd_refs_push(elseSuccessor);
64
65 // Determine the new then-successor.
66 BDD thenSuccessor;
67 if (odd.getThenOffset() > 0) {
68 thenSuccessor = fromVectorRec(currentOffset, currentLevel + 1, maxLevel, odd.getThenSuccessor(), ddVariableIndices, filter);
69 } else {
70 thenSuccessor = sylvan_false;
71 }
72 bdd_refs_push(thenSuccessor);
73
74 // Create a node representing ITE(currentVar, thenSuccessor, elseSuccessor);
75 BDD currentVar = sylvan_ithvar(static_cast<BDDVAR>(ddVariableIndices[currentLevel]));
76 bdd_refs_push(currentVar);
77
78 BDD result = sylvan_ite(currentVar, thenSuccessor, elseSuccessor);
79
80 // Dispose of the intermediate results.
81 bdd_refs_pop(3);
82
83 return result;
84 }
85}
86
87bool InternalBdd<DdType::Sylvan>::operator==(InternalBdd<DdType::Sylvan> const& other) const {
88 return sylvanBdd == other.sylvanBdd;
89}
90
91bool InternalBdd<DdType::Sylvan>::operator!=(InternalBdd<DdType::Sylvan> const& other) const {
92 return sylvanBdd != other.sylvanBdd;
93}
94
95InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::relationalProduct(InternalBdd<DdType::Sylvan> const& relation,
96 std::vector<InternalBdd<DdType::Sylvan>> const&,
97 std::vector<InternalBdd<DdType::Sylvan>> const&) const {
98 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanBdd.RelNext(relation.sylvanBdd, sylvan::Bdd(sylvan_false)));
99}
100
101InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::inverseRelationalProduct(InternalBdd<DdType::Sylvan> const& relation,
102 std::vector<InternalBdd<DdType::Sylvan>> const&,
103 std::vector<InternalBdd<DdType::Sylvan>> const&) const {
104 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanBdd.RelPrev(relation.sylvanBdd, sylvan::Bdd(sylvan_false)));
105}
106
107InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::inverseRelationalProductWithExtendedRelation(
108 InternalBdd<DdType::Sylvan> const& relation, std::vector<InternalBdd<DdType::Sylvan>> const& rowVariables,
109 std::vector<InternalBdd<DdType::Sylvan>> const& columnVariables) const {
110 // Currently, there is no specialized version to perform this operation, so we fall back to the regular operations.
111
112 InternalBdd<DdType::Sylvan> columnCube = ddManager->getBddOne();
113 for (auto const& variable : columnVariables) {
114 columnCube &= variable;
115 }
116
117 return this->swapVariables(rowVariables, columnVariables).andExists(relation, columnCube);
118}
119
120InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::ite(InternalBdd<DdType::Sylvan> const& thenDd, InternalBdd<DdType::Sylvan> const& elseDd) const {
121 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanBdd.Ite(thenDd.sylvanBdd, elseDd.sylvanBdd));
122}
123
124template<typename ValueType>
125InternalAdd<DdType::Sylvan, ValueType> InternalBdd<DdType::Sylvan>::ite(InternalAdd<DdType::Sylvan, ValueType> const& thenAdd,
126 InternalAdd<DdType::Sylvan, ValueType> const& elseAdd) const {
127 return InternalAdd<DdType::Sylvan, ValueType>(ddManager, this->sylvanBdd.Ite(thenAdd.getSylvanMtbdd(), elseAdd.getSylvanMtbdd()));
128}
129
130InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::operator||(InternalBdd<DdType::Sylvan> const& other) const {
131 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanBdd | other.sylvanBdd);
132}
133
134InternalBdd<DdType::Sylvan>& InternalBdd<DdType::Sylvan>::operator|=(InternalBdd<DdType::Sylvan> const& other) {
135 this->sylvanBdd |= other.sylvanBdd;
136 return *this;
137}
138
139InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::operator&&(InternalBdd<DdType::Sylvan> const& other) const {
140 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanBdd & other.sylvanBdd);
141}
142
143InternalBdd<DdType::Sylvan>& InternalBdd<DdType::Sylvan>::operator&=(InternalBdd<DdType::Sylvan> const& other) {
144 this->sylvanBdd &= other.sylvanBdd;
145 return *this;
146}
147
148InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::iff(InternalBdd<DdType::Sylvan> const& other) const {
149 return InternalBdd<DdType::Sylvan>(ddManager, !(this->sylvanBdd ^ other.sylvanBdd));
150}
151
152InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::exclusiveOr(InternalBdd<DdType::Sylvan> const& other) const {
153 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanBdd ^ other.sylvanBdd);
154}
155
156InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::implies(InternalBdd<DdType::Sylvan> const& other) const {
157 return InternalBdd<DdType::Sylvan>(ddManager, (!this->sylvanBdd) | other.sylvanBdd);
158}
159
160InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::operator!() const {
161 return InternalBdd<DdType::Sylvan>(ddManager, !this->sylvanBdd);
162}
163
164InternalBdd<DdType::Sylvan>& InternalBdd<DdType::Sylvan>::complement() {
165 this->sylvanBdd = !this->sylvanBdd;
166 return *this;
167}
168
169InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::existsAbstract(InternalBdd<DdType::Sylvan> const& cube) const {
170 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanBdd.ExistAbstract(cube.sylvanBdd));
171}
172
173InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::existsAbstractRepresentative(InternalBdd<DdType::Sylvan> const& cube) const {
174 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanBdd.ExistAbstractRepresentative(cube.sylvanBdd));
175}
176
177InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::universalAbstract(InternalBdd<DdType::Sylvan> const& cube) const {
178 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanBdd.UnivAbstract(cube.sylvanBdd));
179}
180
181InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::andExists(InternalBdd<DdType::Sylvan> const& other, InternalBdd<DdType::Sylvan> const& cube) const {
182 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanBdd.AndAbstract(other.sylvanBdd, cube.sylvanBdd));
183}
184
185InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::constrain(InternalBdd<DdType::Sylvan> const& constraint) const {
186 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanBdd.Constrain(constraint.sylvanBdd));
187}
188
189InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::restrict(InternalBdd<DdType::Sylvan> const& constraint) const {
190 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanBdd.Restrict(constraint.sylvanBdd));
191}
192
193InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::swapVariables(std::vector<InternalBdd<DdType::Sylvan>> const& from,
194 std::vector<InternalBdd<DdType::Sylvan>> const& to) const {
195 std::vector<uint32_t> fromIndices;
196 std::vector<uint32_t> toIndices;
197 for (auto it1 = from.begin(), ite1 = from.end(), it2 = to.begin(); it1 != ite1; ++it1, ++it2) {
198 fromIndices.push_back(it1->getIndex());
199 fromIndices.push_back(it2->getIndex());
200 toIndices.push_back(it2->getIndex());
201 toIndices.push_back(it1->getIndex());
202 }
203 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanBdd.Permute(fromIndices, toIndices));
204}
205
206InternalBdd<DdType::Sylvan> InternalBdd<DdType::Sylvan>::getSupport() const {
207 return InternalBdd<DdType::Sylvan>(ddManager, this->sylvanBdd.Support());
208}
209
210uint_fast64_t InternalBdd<DdType::Sylvan>::getNonZeroCount(uint_fast64_t numberOfDdVariables) const {
211 if (numberOfDdVariables == 0) {
212 return 0;
213 }
214 return static_cast<uint_fast64_t>(this->sylvanBdd.SatCount(numberOfDdVariables));
215}
216
217uint_fast64_t InternalBdd<DdType::Sylvan>::getLeafCount() const {
218 // For BDDs, the leaf count is always one, because the only leaf is the false leaf (and true is represented
219 // by a negation edge to false).
220 return 1;
221}
222
223uint_fast64_t InternalBdd<DdType::Sylvan>::getNodeCount() const {
224 // We have to add one to also count the false-leaf, which is the only leaf appearing in BDDs.
225 return static_cast<uint_fast64_t>(this->sylvanBdd.NodeCount());
226}
227
228bool InternalBdd<DdType::Sylvan>::isOne() const {
229 return this->sylvanBdd.isOne();
230}
231
232bool InternalBdd<DdType::Sylvan>::isZero() const {
233 return this->sylvanBdd.isZero();
234}
235
236uint_fast64_t InternalBdd<DdType::Sylvan>::getIndex() const {
237 return static_cast<uint_fast64_t>(this->sylvanBdd.TopVar());
238}
239
240uint_fast64_t InternalBdd<DdType::Sylvan>::getLevel() const {
241 return this->getIndex();
242}
243
244void InternalBdd<DdType::Sylvan>::exportToDot(std::string const& filename, std::vector<std::string> const&, bool) const {
245 FILE* filePointer = fopen(filename.c_str(), "a+");
246 // fopen returns a nullptr on failure
247 if (filePointer == nullptr) {
248 STORM_LOG_ERROR("Failure to open file: " << filename);
249 } else {
250 this->sylvanBdd.PrintDot(filePointer);
251 fclose(filePointer);
252 }
253}
254
255void InternalBdd<DdType::Sylvan>::exportToText(std::string const& filename) const {
256 FILE* filePointer = fopen(filename.c_str(), "a+");
257 // fopen returns a nullptr on failure
258 if (filePointer == nullptr) {
259 STORM_LOG_ERROR("Failure to open file: " << filename);
260 } else {
261 this->sylvanBdd.PrintText(filePointer);
262 fclose(filePointer);
263 }
264}
265
266sylvan::Bdd& InternalBdd<DdType::Sylvan>::getSylvanBdd() {
267 return sylvanBdd;
268}
269
270sylvan::Bdd const& InternalBdd<DdType::Sylvan>::getSylvanBdd() const {
271 return sylvanBdd;
272}
273
274template<typename ValueType>
275InternalAdd<DdType::Sylvan, ValueType> InternalBdd<DdType::Sylvan>::toAdd() const {
276 if (std::is_same<ValueType, double>::value) {
277 return InternalAdd<DdType::Sylvan, ValueType>(ddManager, this->sylvanBdd.toDoubleMtbdd());
278 } else if (std::is_same<ValueType, uint_fast64_t>::value) {
279 return InternalAdd<DdType::Sylvan, ValueType>(ddManager, this->sylvanBdd.toInt64Mtbdd());
280 } else if (std::is_same<ValueType, storm::RationalNumber>::value) {
281 return InternalAdd<DdType::Sylvan, ValueType>(ddManager, this->sylvanBdd.toStormRationalNumberMtbdd());
282 } else if (std::is_same<ValueType, storm::RationalFunction>::value) {
283 return InternalAdd<DdType::Sylvan, ValueType>(ddManager, this->sylvanBdd.toStormRationalFunctionMtbdd());
284 } else {
285 STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Illegal ADD type.");
286 }
287}
288
289storm::storage::BitVector InternalBdd<DdType::Sylvan>::toVector(storm::dd::Odd const& rowOdd, std::vector<uint_fast64_t> const& ddVariableIndices) const {
291 this->toVectorRec(bdd_regular(this->getSylvanBdd().GetBDD()), result, rowOdd, bdd_isnegated(this->getSylvanBdd().GetBDD()), 0, ddVariableIndices.size(), 0,
292 ddVariableIndices);
293 return result;
294}
295
296void InternalBdd<DdType::Sylvan>::toVectorRec(BDD dd, storm::storage::BitVector& result, Odd const& rowOdd, bool complement, uint_fast64_t currentRowLevel,
297 uint_fast64_t maxLevel, uint_fast64_t currentRowOffset,
298 std::vector<uint_fast64_t> const& ddRowVariableIndices) const {
299 // If there are no more values to select, we can directly return.
300 if (dd == sylvan_false && !complement) {
301 return;
302 } else if (dd == sylvan_true && complement) {
303 return;
304 }
305
306 // If we are at the maximal level, the value to be set is stored as a constant in the DD.
307 if (currentRowLevel == maxLevel) {
308 result.set(currentRowOffset, true);
309 } else if (bdd_isterminal(dd) || ddRowVariableIndices[currentRowLevel] < sylvan_var(dd)) {
310 toVectorRec(dd, result, rowOdd.getElseSuccessor(), complement, currentRowLevel + 1, maxLevel, currentRowOffset, ddRowVariableIndices);
311 toVectorRec(dd, result, rowOdd.getThenSuccessor(), complement, currentRowLevel + 1, maxLevel, currentRowOffset + rowOdd.getElseOffset(),
312 ddRowVariableIndices);
313 } else {
314 // Otherwise, we compute the ODDs for both the then- and else successors.
315 BDD elseDdNode = sylvan_low(dd);
316 BDD thenDdNode = sylvan_high(dd);
317
318 // Determine whether we have to evaluate the successors as if they were complemented.
319 bool elseComplemented = bdd_isnegated(elseDdNode) ^ complement;
320 bool thenComplemented = bdd_isnegated(thenDdNode) ^ complement;
321
322 toVectorRec(bdd_regular(elseDdNode), result, rowOdd.getElseSuccessor(), elseComplemented, currentRowLevel + 1, maxLevel, currentRowOffset,
323 ddRowVariableIndices);
324 toVectorRec(bdd_regular(thenDdNode), result, rowOdd.getThenSuccessor(), thenComplemented, currentRowLevel + 1, maxLevel,
325 currentRowOffset + rowOdd.getElseOffset(), ddRowVariableIndices);
326 }
327}
328
329Odd InternalBdd<DdType::Sylvan>::createOdd(std::vector<uint_fast64_t> const& ddVariableIndices) const {
330 // Prepare a unique table for each level that keeps the constructed ODD nodes unique.
331 std::vector<std::unordered_map<std::pair<BDD, bool>, std::shared_ptr<Odd>, HashFunctor>> uniqueTableForLevels(ddVariableIndices.size() + 1);
332
333 // Now construct the ODD structure from the BDD.
334 std::shared_ptr<Odd> rootOdd = createOddRec(bdd_regular(this->getSylvanBdd().GetBDD()), bdd_isnegated(this->getSylvanBdd().GetBDD()), 0,
335 ddVariableIndices.size(), ddVariableIndices, uniqueTableForLevels);
336
337 // Return a copy of the root node to remove the shared_ptr encapsulation.
338 return Odd(*rootOdd);
339}
340
341std::size_t InternalBdd<DdType::Sylvan>::HashFunctor::operator()(std::pair<BDD, bool> const& key) const {
342 std::size_t result = 0;
343 boost::hash_combine(result, key.first);
344 boost::hash_combine(result, key.second);
345 return result;
346}
347
348std::shared_ptr<Odd> InternalBdd<DdType::Sylvan>::createOddRec(
349 BDD dd, bool complement, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices,
350 std::vector<std::unordered_map<std::pair<BDD, bool>, std::shared_ptr<Odd>, HashFunctor>>& uniqueTableForLevels) {
351 // Check whether the ODD for this node has already been computed (for this level) and if so, return this instead.
352 auto const& iterator = uniqueTableForLevels[currentLevel].find(std::make_pair(dd, complement));
353 if (iterator != uniqueTableForLevels[currentLevel].end()) {
354 return iterator->second;
355 } else {
356 // Otherwise, we need to recursively compute the ODD.
357
358 // If we are already at the maximal level that is to be considered, we can simply create an Odd without
359 // successors.
360 if (currentLevel == maxLevel) {
361 uint_fast64_t elseOffset = 0;
362 uint_fast64_t thenOffset = 0;
363
364 // If the DD is not the zero leaf, then the then-offset is 1.
365 if (dd != mtbdd_false) {
366 thenOffset = 1;
367 }
368
369 // If we need to complement the 'terminal' node, we need to negate its offset.
370 if (complement) {
371 thenOffset = 1 - thenOffset;
372 }
373
374 auto oddNode = std::make_shared<Odd>(nullptr, elseOffset, nullptr, thenOffset);
375 uniqueTableForLevels[currentLevel].emplace(std::make_pair(dd, complement), oddNode);
376 return oddNode;
377 } else if (bdd_isterminal(dd) || ddVariableIndices[currentLevel] < sylvan_var(dd)) {
378 // If we skipped the level in the DD, we compute the ODD just for the else-successor and use the same
379 // node for the then-successor as well.
380 std::shared_ptr<Odd> elseNode = createOddRec(dd, complement, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels);
381 std::shared_ptr<Odd> thenNode = elseNode;
382 uint_fast64_t totalOffset = elseNode->getElseOffset() + elseNode->getThenOffset();
383 auto oddNode = std::make_shared<Odd>(elseNode, totalOffset, thenNode, totalOffset);
384 uniqueTableForLevels[currentLevel].emplace(std::make_pair(dd, complement), oddNode);
385 return oddNode;
386 } else {
387 // Otherwise, we compute the ODDs for both the then- and else successors.
388 BDD thenDdNode = sylvan_high(dd);
389 BDD elseDdNode = sylvan_low(dd);
390
391 // Determine whether we have to evaluate the successors as if they were complemented.
392 bool elseComplemented = bdd_isnegated(elseDdNode) ^ complement;
393 bool thenComplemented = bdd_isnegated(thenDdNode) ^ complement;
394
395 std::shared_ptr<Odd> elseNode =
396 createOddRec(bdd_regular(elseDdNode), elseComplemented, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels);
397 std::shared_ptr<Odd> thenNode =
398 createOddRec(bdd_regular(thenDdNode), thenComplemented, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels);
399
400 auto oddNode = std::make_shared<Odd>(elseNode, elseNode->getElseOffset() + elseNode->getThenOffset(), thenNode,
401 thenNode->getElseOffset() + thenNode->getThenOffset());
402 uniqueTableForLevels[currentLevel].emplace(std::make_pair(dd, complement), oddNode);
403 return oddNode;
404 }
405 }
406}
407
408template<typename ValueType>
409void InternalBdd<DdType::Sylvan>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
410 std::vector<ValueType> const& sourceValues, std::vector<ValueType>& targetValues) const {
411 uint_fast64_t currentIndex = 0;
412 filterExplicitVectorRec(bdd_regular(this->getSylvanBdd().GetBDD()), 0, bdd_isnegated(this->getSylvanBdd().GetBDD()), ddVariableIndices.size(),
413 ddVariableIndices, 0, odd, targetValues, currentIndex, sourceValues);
414}
415
416template<typename ValueType>
417void InternalBdd<DdType::Sylvan>::filterExplicitVectorRec(BDD dd, uint_fast64_t currentLevel, bool complement, uint_fast64_t maxLevel,
418 std::vector<uint_fast64_t> const& ddVariableIndices, uint_fast64_t currentOffset,
419 storm::dd::Odd const& odd, std::vector<ValueType>& result, uint_fast64_t& currentIndex,
420 std::vector<ValueType> const& values) {
421 // If there are no more values to select, we can directly return.
422 if (dd == sylvan_false && !complement) {
423 return;
424 } else if (dd == sylvan_true && complement) {
425 return;
426 }
427
428 if (currentLevel == maxLevel) {
429 result[currentIndex++] = values[currentOffset];
430 } else if (bdd_isterminal(dd) || ddVariableIndices[currentLevel] < sylvan_var(dd)) {
431 // If we skipped a level, we need to enumerate the explicit entries for the case in which the bit is set
432 // and for the one in which it is not set.
433 filterExplicitVectorRec(dd, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset, odd.getElseSuccessor(), result, currentIndex,
434 values);
435 filterExplicitVectorRec(dd, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(),
436 result, currentIndex, values);
437 } else {
438 // Otherwise, we compute the ODDs for both the then- and else successors.
439 BDD thenDdNode = sylvan_high(dd);
440 BDD elseDdNode = sylvan_low(dd);
441
442 // Determine whether we have to evaluate the successors as if they were complemented.
443 bool elseComplemented = bdd_isnegated(elseDdNode) ^ complement;
444 bool thenComplemented = bdd_isnegated(thenDdNode) ^ complement;
445
446 filterExplicitVectorRec(bdd_regular(elseDdNode), currentLevel + 1, elseComplemented, maxLevel, ddVariableIndices, currentOffset, odd.getElseSuccessor(),
447 result, currentIndex, values);
448 filterExplicitVectorRec(bdd_regular(thenDdNode), currentLevel + 1, thenComplemented, maxLevel, ddVariableIndices, currentOffset + odd.getElseOffset(),
449 odd.getThenSuccessor(), result, currentIndex, values);
450 }
451}
452
453void InternalBdd<DdType::Sylvan>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
454 storm::storage::BitVector const& sourceValues, storm::storage::BitVector& targetValues) const {
455 uint_fast64_t currentIndex = 0;
456 filterExplicitVectorRec(bdd_regular(this->getSylvanBdd().GetBDD()), 0, bdd_isnegated(this->getSylvanBdd().GetBDD()), ddVariableIndices.size(),
457 ddVariableIndices, 0, odd, targetValues, currentIndex, sourceValues);
458}
459
460void InternalBdd<DdType::Sylvan>::filterExplicitVectorRec(BDD dd, uint_fast64_t currentLevel, bool complement, uint_fast64_t maxLevel,
461 std::vector<uint_fast64_t> const& ddVariableIndices, uint_fast64_t currentOffset,
462 storm::dd::Odd const& odd, storm::storage::BitVector& result, uint_fast64_t& currentIndex,
463 storm::storage::BitVector const& values) {
464 // If there are no more values to select, we can directly return.
465 if (dd == sylvan_false && !complement) {
466 return;
467 } else if (dd == sylvan_true && complement) {
468 return;
469 }
470
471 if (currentLevel == maxLevel) {
472 result.set(currentIndex++, values.get(currentOffset));
473 } else if (bdd_isterminal(dd) || ddVariableIndices[currentLevel] < sylvan_var(dd)) {
474 // If we skipped a level, we need to enumerate the explicit entries for the case in which the bit is set
475 // and for the one in which it is not set.
476 filterExplicitVectorRec(dd, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset, odd.getElseSuccessor(), result, currentIndex,
477 values);
478 filterExplicitVectorRec(dd, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(),
479 result, currentIndex, values);
480 } else {
481 // Otherwise, we compute the ODDs for both the then- and else successors.
482 BDD thenDdNode = sylvan_high(dd);
483 BDD elseDdNode = sylvan_low(dd);
484
485 // Determine whether we have to evaluate the successors as if they were complemented.
486 bool elseComplemented = bdd_isnegated(elseDdNode) ^ complement;
487 bool thenComplemented = bdd_isnegated(thenDdNode) ^ complement;
488
489 filterExplicitVectorRec(bdd_regular(elseDdNode), currentLevel + 1, elseComplemented, maxLevel, ddVariableIndices, currentOffset, odd.getElseSuccessor(),
490 result, currentIndex, values);
491 filterExplicitVectorRec(bdd_regular(thenDdNode), currentLevel + 1, thenComplemented, maxLevel, ddVariableIndices, currentOffset + odd.getElseOffset(),
492 odd.getThenSuccessor(), result, currentIndex, values);
493 }
494}
495
496std::vector<InternalBdd<DdType::Sylvan>> InternalBdd<DdType::Sylvan>::splitIntoGroups(std::vector<uint_fast64_t> const& ddGroupVariableIndices) const {
497 std::vector<InternalBdd<DdType::Sylvan>> result;
498 splitIntoGroupsRec(this->getSylvanBdd().GetBDD(), result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size());
499 return result;
500}
501
502void InternalBdd<DdType::Sylvan>::splitIntoGroupsRec(BDD dd, std::vector<InternalBdd<DdType::Sylvan>>& groups,
503 std::vector<uint_fast64_t> const& ddGroupVariableIndices, uint_fast64_t currentLevel,
504 uint_fast64_t maxLevel) const {
505 // For the empty DD, we do not need to create a group.
506 if (dd == sylvan_false) {
507 return;
508 }
509
510 if (currentLevel == maxLevel) {
511 groups.push_back(InternalBdd<DdType::Sylvan>(ddManager, sylvan::Bdd(dd)));
512 } else if (bdd_isterminal(dd) || ddGroupVariableIndices[currentLevel] < sylvan_var(dd)) {
513 splitIntoGroupsRec(dd, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
514 splitIntoGroupsRec(dd, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
515 } else {
516 // Otherwise, we compute the ODDs for both the then- and else successors.
517 BDD thenDdNode = sylvan_high(dd);
518 BDD elseDdNode = sylvan_low(dd);
519
520 splitIntoGroupsRec(elseDdNode, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
521 splitIntoGroupsRec(thenDdNode, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
522 }
523}
524
525std::pair<std::vector<storm::expressions::Expression>, std::unordered_map<uint_fast64_t, storm::expressions::Variable>>
526InternalBdd<DdType::Sylvan>::toExpression(storm::expressions::ExpressionManager& manager) const {
527 std::pair<std::vector<storm::expressions::Expression>, std::unordered_map<uint_fast64_t, storm::expressions::Variable>> result;
528
529 // Create (and maintain) a mapping from the DD nodes to a counter that says the how-many-th node (within the
530 // nodes of equal index) the node was.
531 std::unordered_map<BDD, uint_fast64_t> nodeToCounterMap;
532 std::vector<uint_fast64_t> nextCounterForIndex(ddManager->getNumberOfDdVariables(), 0);
533 std::unordered_map<std::pair<uint_fast64_t, uint_fast64_t>, storm::expressions::Variable> countIndexToVariablePair;
534
535 bool negated = bdd_isnegated(this->getSylvanBdd().GetBDD());
536
537 // Translate from the top node downwards.
538 storm::expressions::Variable topVariable = this->toExpressionRec(bdd_regular(this->getSylvanBdd().GetBDD()), manager, result.first, result.second,
539 countIndexToVariablePair, nodeToCounterMap, nextCounterForIndex);
540
541 // Create the final expression.
542 if (negated) {
543 result.first.push_back(!topVariable);
544 } else {
545 result.first.push_back(topVariable);
546 }
547
548 return result;
549}
550
551storm::expressions::Variable InternalBdd<DdType::Sylvan>::toExpressionRec(
552 BDD dd, storm::expressions::ExpressionManager& manager, std::vector<storm::expressions::Expression>& expressions,
553 std::unordered_map<uint_fast64_t, storm::expressions::Variable>& indexToVariableMap,
554 std::unordered_map<std::pair<uint_fast64_t, uint_fast64_t>, storm::expressions::Variable>& countIndexToVariablePair,
555 std::unordered_map<BDD, uint_fast64_t>& nodeToCounterMap, std::vector<uint_fast64_t>& nextCounterForIndex) {
556 STORM_LOG_ASSERT(!bdd_isnegated(dd), "Expected non-negated BDD node.");
557
558 // First, try to look up the current node if it's not a terminal node.
559 auto nodeCounterIt = nodeToCounterMap.find(dd);
560 if (nodeCounterIt != nodeToCounterMap.end()) {
561 // If we have found the node, this means we can look up the counter-index pair and get the corresponding variable.
562 auto variableIt = countIndexToVariablePair.find(std::make_pair(nodeCounterIt->second, sylvan_var(dd)));
563 STORM_LOG_ASSERT(variableIt != countIndexToVariablePair.end(), "Unable to find node.");
564 return variableIt->second;
565 }
566
567 // If the node was not yet encountered, we create a variable and associate it with the appropriate expression.
568 storm::expressions::Variable newNodeVariable = manager.declareFreshBooleanVariable();
569
570 // Since we want to reuse the variable whenever possible, we insert the appropriate entries in the hash table.
571 if (!bdd_isterminal(dd)) {
572 // If we are dealing with a non-terminal node, we count it as a new node with this index.
573 nodeToCounterMap[dd] = nextCounterForIndex[sylvan_var(dd)];
574 countIndexToVariablePair[std::make_pair(nextCounterForIndex[sylvan_var(dd)], sylvan_var(dd))] = newNodeVariable;
575 ++nextCounterForIndex[sylvan_var(dd)];
576 } else {
577 // If it's a terminal node, it is the one leaf and there's no need to keep track of a counter for this level.
578 nodeToCounterMap[dd] = 0;
579 countIndexToVariablePair[std::make_pair(0, sylvan_var(dd))] = newNodeVariable;
580 }
581
582 // In the terminal case, we can only have a one since we are considering non-negated nodes only.
583 if (bdd_isterminal(dd)) {
584 if (dd == sylvan_true) {
585 expressions.push_back(storm::expressions::iff(manager.boolean(true), newNodeVariable));
586 } else {
587 expressions.push_back(storm::expressions::iff(manager.boolean(false), newNodeVariable));
588 }
589 } else {
590 // In the non-terminal case, we recursively translate the children nodes and then construct and appropriate ite-expression.
591 BDD t = sylvan_high(dd);
592 BDD e = sylvan_low(dd);
593 BDD T = bdd_regular(t);
594 BDD E = bdd_regular(e);
595 storm::expressions::Variable thenVariable =
596 toExpressionRec(T, manager, expressions, indexToVariableMap, countIndexToVariablePair, nodeToCounterMap, nextCounterForIndex);
597 storm::expressions::Variable elseVariable =
598 toExpressionRec(E, manager, expressions, indexToVariableMap, countIndexToVariablePair, nodeToCounterMap, nextCounterForIndex);
599
600 // Create the appropriate expression.
601 // Create the appropriate expression.
602 auto indexVariable = indexToVariableMap.find(sylvan_var(dd));
603 storm::expressions::Variable levelVariable;
604 if (indexVariable == indexToVariableMap.end()) {
605 levelVariable = manager.declareFreshBooleanVariable();
606 indexToVariableMap[sylvan_var(dd)] = levelVariable;
607 } else {
608 levelVariable = indexVariable->second;
609 }
610 expressions.push_back(storm::expressions::iff(
611 newNodeVariable, storm::expressions::ite(levelVariable, t == T ? thenVariable : !thenVariable, e == E ? elseVariable : !elseVariable)));
612 }
613
614 // Return the variable for this node.
615 return newNodeVariable;
616}
617#else
619 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
620 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
621 "version of Storm with Sylvan support.");
622}
623
625 std::vector<uint_fast64_t> const& sortedDdVariableIndices,
626 std::function<bool(uint64_t)> const& filter) {
627 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
628 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
629 "version of Storm with Sylvan support.");
630}
631
633 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
634 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
635 "version of Storm with Sylvan support.");
636}
637
639 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
640 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
641 "version of Storm with Sylvan support.");
642}
643
645 std::vector<InternalBdd<DdType::Sylvan>> const&,
646 std::vector<InternalBdd<DdType::Sylvan>> const&) const {
647 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
648 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
649 "version of Storm with Sylvan support.");
650}
651
653 std::vector<InternalBdd<DdType::Sylvan>> const&,
654 std::vector<InternalBdd<DdType::Sylvan>> const&) const {
655 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
656 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
657 "version of Storm with Sylvan support.");
658}
659
661 InternalBdd<DdType::Sylvan> const& relation, std::vector<InternalBdd<DdType::Sylvan>> const& rowVariables,
662 std::vector<InternalBdd<DdType::Sylvan>> const& columnVariables) const {
663 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
664 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
665 "version of Storm with Sylvan support.");
666}
667
669 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
670 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
671 "version of Storm with Sylvan support.");
672}
673
674template<typename ValueType>
676 InternalAdd<DdType::Sylvan, ValueType> const& elseAdd) const {
677 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
678 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
679 "version of Storm with Sylvan support.");
680}
681
683 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
684 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
685 "version of Storm with Sylvan support.");
686}
687
689 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
690 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
691 "version of Storm with Sylvan support.");
692}
693
695 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
696 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
697 "version of Storm with Sylvan support.");
698}
699
701 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
702 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
703 "version of Storm with Sylvan support.");
704}
705
707 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
708 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
709 "version of Storm with Sylvan support.");
710}
711
713 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
714 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
715 "version of Storm with Sylvan support.");
716}
717
719 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
720 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
721 "version of Storm with Sylvan support.");
722}
723
725 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
726 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
727 "version of Storm with Sylvan support.");
728}
729
731 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
732 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
733 "version of Storm with Sylvan support.");
734}
735
737 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
738 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
739 "version of Storm with Sylvan support.");
740}
741
743 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
744 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
745 "version of Storm with Sylvan support.");
746}
747
749 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
750 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
751 "version of Storm with Sylvan support.");
752}
753
755 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
756 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
757 "version of Storm with Sylvan support.");
758}
759
761 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
762 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
763 "version of Storm with Sylvan support.");
764}
765
767 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
768 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
769 "version of Storm with Sylvan support.");
770}
771
773 std::vector<InternalBdd<DdType::Sylvan>> const& to) const {
774 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
775 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
776 "version of Storm with Sylvan support.");
777}
778
780 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
781 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
782 "version of Storm with Sylvan support.");
783}
784
785uint_fast64_t InternalBdd<DdType::Sylvan>::getNonZeroCount(uint_fast64_t numberOfDdVariables) const {
786 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
787 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
788 "version of Storm with Sylvan support.");
789}
790
792 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
793 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
794 "version of Storm with Sylvan support.");
795}
796
798 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
799 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
800 "version of Storm with Sylvan support.");
801}
802
804 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
805 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
806 "version of Storm with Sylvan support.");
807}
808
810 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
811 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
812 "version of Storm with Sylvan support.");
813}
814
816 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
817 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
818 "version of Storm with Sylvan support.");
819}
820
822 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
823 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
824 "version of Storm with Sylvan support.");
825}
826
827void InternalBdd<DdType::Sylvan>::exportToDot(std::string const& filename, std::vector<std::string> const&, bool) const {
828 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
829 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
830 "version of Storm with Sylvan support.");
831}
832
833void InternalBdd<DdType::Sylvan>::exportToText(std::string const& filename) const {
834 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
835 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
836 "version of Storm with Sylvan support.");
837}
838
839template<typename ValueType>
841 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
842 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
843 "version of Storm with Sylvan support.");
844}
845
846storm::storage::BitVector InternalBdd<DdType::Sylvan>::toVector(storm::dd::Odd const& rowOdd, std::vector<uint_fast64_t> const& ddVariableIndices) const {
847 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
848 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
849 "version of Storm with Sylvan support.");
850}
851
852Odd InternalBdd<DdType::Sylvan>::createOdd(std::vector<uint_fast64_t> const& ddVariableIndices) const {
853 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
854 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
855 "version of Storm with Sylvan support.");
856}
857
858template<typename ValueType>
859void InternalBdd<DdType::Sylvan>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
860 std::vector<ValueType> const& sourceValues, std::vector<ValueType>& targetValues) const {
861 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
862 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
863 "version of Storm with Sylvan support.");
864}
865
866void InternalBdd<DdType::Sylvan>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
867 storm::storage::BitVector const& sourceValues, storm::storage::BitVector& targetValues) const {
868 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
869 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
870 "version of Storm with Sylvan support.");
871}
872
873std::vector<InternalBdd<DdType::Sylvan>> InternalBdd<DdType::Sylvan>::splitIntoGroups(std::vector<uint_fast64_t> const& ddGroupVariableIndices) const {
874 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
875 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
876 "version of Storm with Sylvan support.");
877}
878
879std::pair<std::vector<storm::expressions::Expression>, std::unordered_map<uint_fast64_t, storm::expressions::Variable>>
881 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
882 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
883 "version of Storm with Sylvan support.");
884}
885#endif
886
891
892template void InternalBdd<DdType::Sylvan>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
893 std::vector<double> const& sourceValues, std::vector<double>& targetValues) const;
894template void InternalBdd<DdType::Sylvan>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
895 std::vector<uint_fast64_t> const& sourceValues, std::vector<uint_fast64_t>& targetValues) const;
896template void InternalBdd<DdType::Sylvan>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
897 std::vector<storm::RationalNumber> const& sourceValues,
898 std::vector<storm::RationalNumber>& targetValues) const;
899template void InternalBdd<DdType::Sylvan>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
900 std::vector<storm::RationalFunction> const& sourceValues,
901 std::vector<storm::RationalFunction>& targetValues) const;
902
904 InternalAdd<DdType::Sylvan, double> const& elseAdd) const;
906 InternalAdd<DdType::Sylvan, uint_fast64_t> const& elseAdd) const;
911} // namespace dd
912} // namespace storm
Odd const & getThenSuccessor() const
Retrieves the then-successor of this ODD node.
Definition Odd.cpp:21
uint_fast64_t getTotalOffset() const
Retrieves the total offset, i.e., the sum of the then- and else-offset.
Definition Odd.cpp:45
uint_fast64_t getElseOffset() const
Retrieves the else-offset of this ODD node.
Definition Odd.cpp:29
Odd const & getElseSuccessor() const
Retrieves the else-successor of this ODD node.
Definition Odd.cpp:25
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.
Definition BitVector.h:16
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
bool get(uint64_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:26
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
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.
storm::storage::BitVector filter(std::vector< T > const &values, std::function< bool(T const &value)> const &function)
Retrieves a bit vector containing all the indices for which the value at this position makes the give...
Definition vector.h:490