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