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