Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
InternalCuddBdd.cpp
Go to the documentation of this file.
2
3#include <boost/functional/hash.hpp>
4
7
10
13
14namespace storm {
15namespace dd {
16InternalBdd<DdType::CUDD>::InternalBdd(InternalDdManager<DdType::CUDD> const* ddManager, cudd::BDD cuddBdd) : ddManager(ddManager), cuddBdd(cuddBdd) {
17 // Intentionally left empty.
18}
19
21 std::vector<uint_fast64_t> const& sortedDdVariableIndices,
22 std::function<bool(uint64_t)> const& filter) {
23 uint_fast64_t offset = 0;
25 ddManager, cudd::BDD(ddManager->getCuddManager(), fromVectorRec(ddManager->getCuddManager().getManager(), offset, 0, sortedDdVariableIndices.size(),
26 odd, sortedDdVariableIndices, filter)));
27}
28
30 return this->getCuddBdd() == other.getCuddBdd();
31}
32
34 return !(*this == other);
35}
36
38 std::vector<InternalBdd<DdType::CUDD>> const& rowVariables,
39 std::vector<InternalBdd<DdType::CUDD>> const& columnVariables) const {
40 InternalBdd<DdType::CUDD> cube = ddManager->getBddOne();
41 for (auto const& variable : rowVariables) {
42 cube &= variable;
43 }
44
45 InternalBdd<DdType::CUDD> result = this->andExists(relation, cube);
46 result = result.swapVariables(rowVariables, columnVariables);
47 return result;
48}
49
51 std::vector<InternalBdd<DdType::CUDD>> const& rowVariables,
52 std::vector<InternalBdd<DdType::CUDD>> const& columnVariables) const {
53 InternalBdd<DdType::CUDD> cube = ddManager->getBddOne();
54 for (auto const& variable : columnVariables) {
55 cube &= variable;
56 }
57
58 InternalBdd<DdType::CUDD> result = this->swapVariables(rowVariables, columnVariables).andExists(relation, cube);
59 return result;
60}
61
63 InternalBdd<DdType::CUDD> const& relation, std::vector<InternalBdd<DdType::CUDD>> const& rowVariables,
64 std::vector<InternalBdd<DdType::CUDD>> const& columnVariables) const {
65 return this->inverseRelationalProduct(relation, rowVariables, columnVariables);
66}
67
69 return InternalBdd<DdType::CUDD>(ddManager, this->getCuddBdd().Ite(thenDd.getCuddBdd(), elseDd.getCuddBdd()));
70}
71
72template<typename ValueType>
74 InternalAdd<DdType::CUDD, ValueType> const& elseAdd) const {
75 return InternalAdd<DdType::CUDD, ValueType>(ddManager, this->getCuddBdd().Add().Ite(thenAdd.getCuddAdd(), elseAdd.getCuddAdd()));
76}
77
79 InternalBdd<DdType::CUDD> result(*this);
80 result |= other;
81 return result;
82}
83
85 this->cuddBdd = this->getCuddBdd() | other.getCuddBdd();
86 return *this;
87}
88
90 InternalBdd<DdType::CUDD> result(*this);
91 result &= other;
92 return result;
93}
94
96 this->cuddBdd = this->getCuddBdd() & other.getCuddBdd();
97 return *this;
98}
99
101 return InternalBdd<DdType::CUDD>(ddManager, this->getCuddBdd().Xnor(other.getCuddBdd()));
102}
103
105 return InternalBdd<DdType::CUDD>(ddManager, this->getCuddBdd().Xor(other.getCuddBdd()));
106}
107
109 return InternalBdd<DdType::CUDD>(ddManager, this->getCuddBdd().Ite(other.getCuddBdd(), ddManager->getBddOne().getCuddBdd()));
110}
111
113 InternalBdd<DdType::CUDD> result(*this);
114 result.complement();
115 return result;
116}
117
119 this->cuddBdd = ~this->getCuddBdd();
120 return *this;
121}
122
124 return InternalBdd<DdType::CUDD>(ddManager, this->getCuddBdd().ExistAbstract(cube.getCuddBdd()));
125}
126
128 return InternalBdd<DdType::CUDD>(ddManager, this->getCuddBdd().ExistAbstractRepresentative(cube.getCuddBdd()));
129}
130
132 return InternalBdd<DdType::CUDD>(ddManager, this->getCuddBdd().UnivAbstract(cube.getCuddBdd()));
133}
134
136 return InternalBdd<DdType::CUDD>(ddManager, this->getCuddBdd().AndAbstract(other.getCuddBdd(), cube.getCuddBdd()));
137}
138
140 return InternalBdd<DdType::CUDD>(ddManager, this->getCuddBdd().Constrain(constraint.getCuddBdd()));
141}
142
144 return InternalBdd<DdType::CUDD>(ddManager, this->getCuddBdd().Restrict(constraint.getCuddBdd()));
145}
146
148 std::vector<InternalBdd<DdType::CUDD>> const& to) const {
149 std::vector<cudd::BDD> fromBdd;
150 std::vector<cudd::BDD> toBdd;
151 for (auto it1 = from.begin(), ite1 = from.end(), it2 = to.begin(); it1 != ite1; ++it1, ++it2) {
152 fromBdd.push_back(it1->getCuddBdd());
153 toBdd.push_back(it2->getCuddBdd());
154 }
155 return InternalBdd<DdType::CUDD>(ddManager, this->getCuddBdd().SwapVariables(fromBdd, toBdd));
156}
157
159 return InternalBdd<DdType::CUDD>(ddManager, this->getCuddBdd().Support());
160}
161
162uint_fast64_t InternalBdd<DdType::CUDD>::getNonZeroCount(uint_fast64_t numberOfDdVariables) const {
163 // If the number of DD variables is zero, CUDD returns a number greater 0 for constant nodes different from
164 // zero, which is not the behaviour we expect.
165 if (numberOfDdVariables == 0) {
166 return 0;
167 }
168 return static_cast<uint_fast64_t>(this->getCuddBdd().CountMinterm(static_cast<int>(numberOfDdVariables)));
169}
170
172 return static_cast<uint_fast64_t>(this->getCuddBdd().CountLeaves());
173}
174
176 return static_cast<uint_fast64_t>(this->getCuddBdd().nodeCount());
177}
178
180 return this->getCuddBdd().IsOne();
181}
182
184 return this->getCuddBdd().IsZero();
185}
186
188 return static_cast<uint_fast64_t>(this->getCuddBdd().NodeReadIndex());
189}
190
192 return static_cast<uint_fast64_t>(ddManager->getCuddManager().ReadPerm(this->getIndex()));
193}
194
195void InternalBdd<DdType::CUDD>::exportToDot(std::string const& filename, std::vector<std::string> const& ddVariableNamesAsStrings,
196 bool showVariablesIfPossible) const {
197 // Build the name input of the DD.
198 std::vector<char*> ddNames;
199 std::string ddName("f");
200 ddNames.push_back(new char[ddName.size() + 1]);
201 std::copy(ddName.c_str(), ddName.c_str() + 2, ddNames.back());
202
203 // Now build the variables names.
204 std::vector<char*> ddVariableNames;
205 for (auto const& element : ddVariableNamesAsStrings) {
206 ddVariableNames.push_back(new char[element.size() + 1]);
207 std::copy(element.c_str(), element.c_str() + element.size() + 1, ddVariableNames.back());
208 }
209
210 // Open the file, dump the DD and close it again.
211 std::vector<cudd::BDD> cuddBddVector = {this->getCuddBdd()};
212 FILE* filePointer = fopen(filename.c_str(), "a+");
213 if (showVariablesIfPossible) {
214 ddManager->getCuddManager().DumpDot(cuddBddVector, ddVariableNames.data(), &ddNames[0], filePointer);
215 } else {
216 ddManager->getCuddManager().DumpDot(cuddBddVector, nullptr, &ddNames[0], filePointer);
217 }
218 fclose(filePointer);
219
220 // Finally, delete the names.
221 for (char* element : ddNames) {
222 delete element;
223 }
224 for (char* element : ddVariableNames) {
225 delete element;
226 }
227}
228
229void InternalBdd<DdType::CUDD>::exportToText(std::string const&) const {
230 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Operation not supported");
231}
232
234 return this->cuddBdd;
235}
236
238 return this->getCuddBdd().getNode();
239}
240
241template<typename ValueType>
245
246DdNode* InternalBdd<DdType::CUDD>::fromVectorRec(::DdManager* manager, uint_fast64_t& currentOffset, uint_fast64_t currentLevel, uint_fast64_t maxLevel,
247 Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
248 std::function<bool(uint64_t)> const& filter) {
249 if (currentLevel == maxLevel) {
250 // If we are in a terminal node of the ODD, we need to check whether the then-offset of the ODD is one
251 // (meaning the encoding is a valid one) or zero (meaning the encoding is not valid). Consequently, we
252 // need to copy the next value of the vector iff the then-offset is greater than zero.
253 if (odd.getThenOffset() > 0) {
254 if (filter(currentOffset++)) {
255 return Cudd_ReadOne(manager);
256 } else {
257 return Cudd_ReadLogicZero(manager);
258 }
259 } else {
260 return Cudd_ReadZero(manager);
261 }
262 } else {
263 // If the total offset is zero, we can just return the constant zero DD.
264 if (odd.getThenOffset() + odd.getElseOffset() == 0) {
265 return Cudd_ReadZero(manager);
266 }
267
268 // Determine the new else-successor.
269 DdNode* elseSuccessor = nullptr;
270 if (odd.getElseOffset() > 0) {
271 elseSuccessor = fromVectorRec(manager, currentOffset, currentLevel + 1, maxLevel, odd.getElseSuccessor(), ddVariableIndices, filter);
272 } else {
273 elseSuccessor = Cudd_ReadLogicZero(manager);
274 }
275 Cudd_Ref(elseSuccessor);
276
277 // Determine the new then-successor.
278 DdNode* thenSuccessor = nullptr;
279 if (odd.getThenOffset() > 0) {
280 thenSuccessor = fromVectorRec(manager, currentOffset, currentLevel + 1, maxLevel, odd.getThenSuccessor(), ddVariableIndices, filter);
281 } else {
282 thenSuccessor = Cudd_ReadLogicZero(manager);
283 }
284 Cudd_Ref(thenSuccessor);
285
286 // Create a node representing ITE(currentVar, thenSuccessor, elseSuccessor);
287 DdNode* currentVar = Cudd_bddIthVar(manager, static_cast<int>(ddVariableIndices[currentLevel]));
288 Cudd_Ref(currentVar);
289 DdNode* result = Cudd_bddIte(manager, currentVar, thenSuccessor, elseSuccessor);
290 Cudd_Ref(result);
291
292 // Dispose of the intermediate results
293 Cudd_RecursiveDeref(manager, currentVar);
294 Cudd_RecursiveDeref(manager, thenSuccessor);
295 Cudd_RecursiveDeref(manager, elseSuccessor);
296
297 // Before returning, we remove the protection imposed by the previous call to Cudd_Ref.
298 Cudd_Deref(result);
299
300 return result;
301 }
302}
303
304storm::storage::BitVector InternalBdd<DdType::CUDD>::toVector(storm::dd::Odd const& rowOdd, std::vector<uint_fast64_t> const& ddVariableIndices) const {
306 this->toVectorRec(Cudd_Regular(this->getCuddDdNode()), ddManager->getCuddManager(), result, rowOdd, Cudd_IsComplement(this->getCuddDdNode()), 0,
307 ddVariableIndices.size(), 0, ddVariableIndices);
308 return result;
309}
310
311void InternalBdd<DdType::CUDD>::toVectorRec(DdNode const* dd, cudd::Cudd const& manager, storm::storage::BitVector& result, Odd const& rowOdd, bool complement,
312 uint_fast64_t currentRowLevel, uint_fast64_t maxLevel, uint_fast64_t currentRowOffset,
313 std::vector<uint_fast64_t> const& ddRowVariableIndices) const {
314 // If there are no more values to select, we can directly return.
315 if (dd == Cudd_ReadLogicZero(manager.getManager()) && !complement) {
316 return;
317 } else if (dd == Cudd_ReadOne(manager.getManager()) && complement) {
318 return;
319 }
320
321 // If we are at the maximal level, the value to be set is stored as a constant in the DD.
322 if (currentRowLevel == maxLevel) {
323 result.set(currentRowOffset, true);
324 } else if (ddRowVariableIndices[currentRowLevel] < Cudd_NodeReadIndex(dd)) {
325 toVectorRec(dd, manager, result, rowOdd.getElseSuccessor(), complement, currentRowLevel + 1, maxLevel, currentRowOffset, ddRowVariableIndices);
326 toVectorRec(dd, manager, result, rowOdd.getThenSuccessor(), complement, currentRowLevel + 1, maxLevel, currentRowOffset + rowOdd.getElseOffset(),
327 ddRowVariableIndices);
328 } else {
329 // Otherwise, we compute the ODDs for both the then- and else successors.
330 DdNode const* elseDdNode = Cudd_E_const(dd);
331 DdNode const* thenDdNode = Cudd_T_const(dd);
332
333 // Determine whether we have to evaluate the successors as if they were complemented.
334 bool elseComplemented = Cudd_IsComplement(elseDdNode) ^ complement;
335 bool thenComplemented = Cudd_IsComplement(thenDdNode) ^ complement;
336
337 toVectorRec(Cudd_Regular(elseDdNode), manager, result, rowOdd.getElseSuccessor(), elseComplemented, currentRowLevel + 1, maxLevel, currentRowOffset,
338 ddRowVariableIndices);
339 toVectorRec(Cudd_Regular(thenDdNode), manager, result, rowOdd.getThenSuccessor(), thenComplemented, currentRowLevel + 1, maxLevel,
340 currentRowOffset + rowOdd.getElseOffset(), ddRowVariableIndices);
341 }
342}
343
344Odd InternalBdd<DdType::CUDD>::createOdd(std::vector<uint_fast64_t> const& ddVariableIndices) const {
345 // Prepare a unique table for each level that keeps the constructed ODD nodes unique.
346 std::vector<std::unordered_map<DdNode const*, std::shared_ptr<Odd>>> uniqueTableForLevels(ddVariableIndices.size() + 1);
347
348 // Now construct the ODD structure from the BDD.
349 std::shared_ptr<Odd> rootOdd =
350 createOddRec(this->getCuddDdNode(), ddManager->getCuddManager(), 0, ddVariableIndices.size(), ddVariableIndices, uniqueTableForLevels);
351
352 // Return a copy of the root node to remove the shared_ptr encapsulation.
353 return Odd(*rootOdd);
354}
355
356std::size_t InternalBdd<DdType::CUDD>::HashFunctor::operator()(std::pair<DdNode const*, bool> const& key) const {
357 std::size_t result = 0;
358 boost::hash_combine(result, key.first);
359 boost::hash_combine(result, key.second);
360 return result;
361}
362
363std::shared_ptr<Odd> InternalBdd<DdType::CUDD>::createOddRec(DdNode const* dd, cudd::Cudd const& manager, uint_fast64_t currentLevel, uint_fast64_t maxLevel,
364 std::vector<uint_fast64_t> const& ddVariableIndices,
365 std::vector<std::unordered_map<DdNode const*, std::shared_ptr<Odd>>>& uniqueTableForLevels) {
366 // Check whether the ODD for this node has already been computed (for this level) and if so, return this instead.
367 auto it = uniqueTableForLevels[currentLevel].find(dd);
368 if (it != uniqueTableForLevels[currentLevel].end()) {
369 return it->second;
370 } else {
371 // Otherwise, we need to recursively compute the ODD.
372
373 // If we are already at the maximal level that is to be considered, we can simply create an Odd without
374 // successors
375 if (currentLevel == maxLevel) {
376 auto oddNode = std::make_shared<Odd>(nullptr, 0, nullptr, dd != Cudd_ReadLogicZero(manager.getManager()) ? 1 : 0);
377 uniqueTableForLevels[currentLevel].emplace(dd, oddNode);
378 return oddNode;
379 } else if (ddVariableIndices[currentLevel] < Cudd_NodeReadIndex(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, manager, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels);
383 std::shared_ptr<Odd> thenNode = elseNode;
384
385 auto oddNode = std::make_shared<Odd>(elseNode, elseNode->getTotalOffset(), thenNode, elseNode->getTotalOffset());
386 uniqueTableForLevels[currentLevel].emplace(dd, oddNode);
387 return oddNode;
388 } else {
389 // Otherwise, we compute the ODDs for both the then- and else successors.
390 DdNode const* thenDdNode = Cudd_T_const(dd);
391 DdNode const* elseDdNode = Cudd_E_const(dd);
392
393 if (Cudd_IsComplement(dd)) {
394 thenDdNode = Cudd_Not(thenDdNode);
395 elseDdNode = Cudd_Not(elseDdNode);
396 }
397
398 std::shared_ptr<Odd> elseNode = createOddRec(elseDdNode, manager, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels);
399 std::shared_ptr<Odd> thenNode = createOddRec(thenDdNode, manager, currentLevel + 1, maxLevel, ddVariableIndices, uniqueTableForLevels);
400
401 auto oddNode = std::make_shared<Odd>(elseNode, elseNode->getTotalOffset(), thenNode, thenNode->getTotalOffset());
402 uniqueTableForLevels[currentLevel].emplace(dd, oddNode);
403 return oddNode;
404 }
405 }
406}
407
408template<typename ValueType>
409void InternalBdd<DdType::CUDD>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
410 std::vector<ValueType> const& sourceValues, std::vector<ValueType>& targetValues) const {
411 uint_fast64_t currentIndex = 0;
412 filterExplicitVectorRec(Cudd_Regular(this->getCuddDdNode()), ddManager->getCuddManager(), 0, Cudd_IsComplement(this->getCuddDdNode()),
413 ddVariableIndices.size(), ddVariableIndices, 0, odd, targetValues, currentIndex, sourceValues);
414}
415
416template<typename ValueType>
417void InternalBdd<DdType::CUDD>::filterExplicitVectorRec(DdNode const* dd, cudd::Cudd const& manager, uint_fast64_t currentLevel, bool complement,
418 uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices,
419 uint_fast64_t currentOffset, storm::dd::Odd const& odd, std::vector<ValueType>& result,
420 uint_fast64_t& currentIndex, std::vector<ValueType> const& values) {
421 // If there are no more values to select, we can directly return.
422 if (dd == Cudd_ReadLogicZero(manager.getManager()) && !complement) {
423 return;
424 } else if (dd == Cudd_ReadOne(manager.getManager()) && complement) {
425 return;
426 }
427
428 if (currentLevel == maxLevel) {
429 result[currentIndex++] = values[currentOffset];
430 } else if (ddVariableIndices[currentLevel] < Cudd_NodeReadIndex(dd)) {
431 // If we skipped a level, we need to enumerate the explicit entries for the case in which the bit is set
432 // and for the one in which it is not set.
433 filterExplicitVectorRec(dd, manager, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset, odd.getElseSuccessor(), result,
434 currentIndex, values);
435 filterExplicitVectorRec(dd, manager, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset + odd.getElseOffset(),
436 odd.getThenSuccessor(), result, currentIndex, values);
437 } else {
438 // Otherwise, we compute the ODDs for both the then- and else successors.
439 DdNode const* thenDdNode = Cudd_T_const(dd);
440 DdNode const* elseDdNode = Cudd_E_const(dd);
441
442 // Determine whether we have to evaluate the successors as if they were complemented.
443 bool elseComplemented = Cudd_IsComplement(elseDdNode) ^ complement;
444 bool thenComplemented = Cudd_IsComplement(thenDdNode) ^ complement;
445
446 filterExplicitVectorRec(Cudd_Regular(elseDdNode), manager, currentLevel + 1, elseComplemented, maxLevel, ddVariableIndices, currentOffset,
447 odd.getElseSuccessor(), result, currentIndex, values);
448 filterExplicitVectorRec(Cudd_Regular(thenDdNode), manager, currentLevel + 1, thenComplemented, maxLevel, ddVariableIndices,
449 currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), result, currentIndex, values);
450 }
451}
452
453std::vector<InternalBdd<DdType::CUDD>> InternalBdd<DdType::CUDD>::splitIntoGroups(std::vector<uint_fast64_t> const& ddGroupVariableIndices) const {
454 std::vector<InternalBdd<DdType::CUDD>> result;
455 splitIntoGroupsRec(Cudd_Regular(this->getCuddDdNode()), Cudd_IsComplement(this->getCuddDdNode()), result, ddGroupVariableIndices, 0,
456 ddGroupVariableIndices.size());
457 return result;
458}
459
460void InternalBdd<DdType::CUDD>::splitIntoGroupsRec(DdNode* dd, bool negated, std::vector<InternalBdd<DdType::CUDD>>& groups,
461 std::vector<uint_fast64_t> const& ddGroupVariableIndices, uint_fast64_t currentLevel,
462 uint_fast64_t maxLevel) const {
463 // For the empty DD, we do not need to create a group.
464 if (negated && dd == Cudd_ReadOne(ddManager->getCuddManager().getManager())) {
465 return;
466 }
467
468 if (currentLevel == maxLevel) {
469 groups.push_back(InternalBdd<DdType::CUDD>(ddManager, cudd::BDD(ddManager->getCuddManager(), negated ? Cudd_Complement(dd) : dd)));
470 } else if (ddGroupVariableIndices[currentLevel] < Cudd_NodeReadIndex(dd)) {
471 splitIntoGroupsRec(dd, negated, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
472 splitIntoGroupsRec(dd, negated, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
473 } else {
474 DdNode* elseNode = Cudd_E(dd);
475 DdNode* thenNode = Cudd_T(dd);
476
477 splitIntoGroupsRec(elseNode, negated ^ Cudd_IsComplement(elseNode), groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
478 splitIntoGroupsRec(thenNode, negated ^ Cudd_IsComplement(thenNode), groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
479 }
480}
481
482void InternalBdd<DdType::CUDD>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
483 storm::storage::BitVector const& sourceValues, storm::storage::BitVector& targetValues) const {
484 uint_fast64_t currentIndex = 0;
485 filterExplicitVectorRec(Cudd_Regular(this->getCuddDdNode()), ddManager->getCuddManager(), 0, Cudd_IsComplement(this->getCuddDdNode()),
486 ddVariableIndices.size(), ddVariableIndices, 0, odd, targetValues, currentIndex, sourceValues);
487}
488
489void InternalBdd<DdType::CUDD>::filterExplicitVectorRec(DdNode const* dd, cudd::Cudd const& manager, uint_fast64_t currentLevel, bool complement,
490 uint_fast64_t maxLevel, std::vector<uint_fast64_t> const& ddVariableIndices,
491 uint_fast64_t currentOffset, storm::dd::Odd const& odd, storm::storage::BitVector& result,
492 uint_fast64_t& currentIndex, storm::storage::BitVector const& values) {
493 // If there are no more values to select, we can directly return.
494 if (dd == Cudd_ReadLogicZero(manager.getManager()) && !complement) {
495 return;
496 } else if (dd == Cudd_ReadOne(manager.getManager()) && complement) {
497 return;
498 }
499
500 if (currentLevel == maxLevel) {
501 result.set(currentIndex++, values.get(currentOffset));
502 } else if (ddVariableIndices[currentLevel] < Cudd_NodeReadIndex(dd)) {
503 // If we skipped a level, we need to enumerate the explicit entries for the case in which the bit is set
504 // and for the one in which it is not set.
505 filterExplicitVectorRec(dd, manager, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset, odd.getElseSuccessor(), result,
506 currentIndex, values);
507 filterExplicitVectorRec(dd, manager, currentLevel + 1, complement, maxLevel, ddVariableIndices, currentOffset + odd.getElseOffset(),
508 odd.getThenSuccessor(), result, currentIndex, values);
509 } else {
510 // Otherwise, we compute the ODDs for both the then- and else successors.
511 DdNode const* thenDdNode = Cudd_T_const(dd);
512 DdNode const* elseDdNode = Cudd_E_const(dd);
513
514 // Determine whether we have to evaluate the successors as if they were complemented.
515 bool elseComplemented = Cudd_IsComplement(elseDdNode) ^ complement;
516 bool thenComplemented = Cudd_IsComplement(thenDdNode) ^ complement;
517
518 filterExplicitVectorRec(Cudd_Regular(elseDdNode), manager, currentLevel + 1, elseComplemented, maxLevel, ddVariableIndices, currentOffset,
519 odd.getElseSuccessor(), result, currentIndex, values);
520 filterExplicitVectorRec(Cudd_Regular(thenDdNode), manager, currentLevel + 1, thenComplemented, maxLevel, ddVariableIndices,
521 currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), result, currentIndex, values);
522 }
523}
524
525std::pair<std::vector<storm::expressions::Expression>, std::unordered_map<uint_fast64_t, storm::expressions::Variable>> InternalBdd<DdType::CUDD>::toExpression(
527 std::pair<std::vector<storm::expressions::Expression>, std::unordered_map<uint_fast64_t, storm::expressions::Variable>> result;
528
529 // Create (and maintain) a mapping from the DD nodes to a counter that says the how-many-th node (within the
530 // nodes of equal index) the node was.
531 std::unordered_map<DdNode const*, uint_fast64_t> nodeToCounterMap;
532 std::vector<uint_fast64_t> nextCounterForIndex(ddManager->getNumberOfDdVariables(), 0);
533 std::unordered_map<std::pair<uint_fast64_t, uint_fast64_t>, storm::expressions::Variable> countIndexToVariablePair;
534
535 bool negated = Cudd_Regular(this->getCuddDdNode()) != this->getCuddDdNode();
536
537 // Translate from the top node downwards.
538 storm::expressions::Variable topVariable = this->toExpressionRec(Cudd_Regular(this->getCuddDdNode()), ddManager->getCuddManager(), manager, result.first,
539 result.second, countIndexToVariablePair, nodeToCounterMap, nextCounterForIndex);
540
541 // Create the final expression.
542 if (negated) {
543 result.first.push_back(!topVariable);
544 } else {
545 result.first.push_back(topVariable);
546 }
547
548 return result;
549}
550
552 DdNode const* dd, cudd::Cudd const& ddManager, storm::expressions::ExpressionManager& manager, std::vector<storm::expressions::Expression>& expressions,
553 std::unordered_map<uint_fast64_t, storm::expressions::Variable>& indexToVariableMap,
554 std::unordered_map<std::pair<uint_fast64_t, uint_fast64_t>, storm::expressions::Variable>& countIndexToVariablePair,
555 std::unordered_map<DdNode const*, uint_fast64_t>& nodeToCounterMap, std::vector<uint_fast64_t>& nextCounterForIndex) {
556 STORM_LOG_ASSERT(dd == Cudd_Regular(dd), "Expected non-negated BDD node.");
557
558 // First, try to look up the current node if it's not a terminal node.
559 auto nodeCounterIt = nodeToCounterMap.find(dd);
560 if (nodeCounterIt != nodeToCounterMap.end()) {
561 // If we have found the node, this means we can look up the counter-index pair and get the corresponding variable.
562 auto variableIt = countIndexToVariablePair.find(std::make_pair(nodeCounterIt->second, Cudd_NodeReadIndex(dd)));
563 STORM_LOG_ASSERT(variableIt != countIndexToVariablePair.end(), "Unable to find node.");
564 return variableIt->second;
565 }
566
567 // If the node was not yet encountered, we create a variable and associate it with the appropriate expression.
568 storm::expressions::Variable newNodeVariable = manager.declareFreshBooleanVariable();
569
570 // Since we want to reuse the variable whenever possible, we insert the appropriate entries in the hash table.
571 if (!Cudd_IsConstant_const(dd)) {
572 // If we are dealing with a non-terminal node, we count it as a new node with this index.
573 nodeToCounterMap[dd] = nextCounterForIndex[Cudd_NodeReadIndex(dd)];
574 countIndexToVariablePair[std::make_pair(nextCounterForIndex[Cudd_NodeReadIndex(dd)], Cudd_NodeReadIndex(dd))] = newNodeVariable;
575 ++nextCounterForIndex[Cudd_NodeReadIndex(dd)];
576 } else {
577 // If it's a terminal node, it is the one leaf and there's no need to keep track of a counter for this level.
578 nodeToCounterMap[dd] = 0;
579 countIndexToVariablePair[std::make_pair(0, Cudd_NodeReadIndex(dd))] = newNodeVariable;
580 }
581
582 // In the terminal case, we can only have a one since we are considering non-negated nodes only.
583 if (dd == Cudd_ReadOne(ddManager.getManager())) {
584 // Push the expression that enforces that the new variable is true.
585 expressions.push_back(storm::expressions::iff(manager.boolean(true), newNodeVariable));
586 } else {
587 // In the non-terminal case, we recursively translate the children nodes and then construct and appropriate ite-expression.
588 DdNode const* t = Cudd_T_const(dd);
589 DdNode const* e = Cudd_E_const(dd);
590 DdNode const* T = Cudd_Regular(t);
591 DdNode const* E = Cudd_Regular(e);
592 storm::expressions::Variable thenVariable =
593 toExpressionRec(T, ddManager, manager, expressions, indexToVariableMap, countIndexToVariablePair, nodeToCounterMap, nextCounterForIndex);
594 storm::expressions::Variable elseVariable =
595 toExpressionRec(E, ddManager, manager, expressions, indexToVariableMap, countIndexToVariablePair, nodeToCounterMap, nextCounterForIndex);
596
597 // Create the appropriate expression.
598 auto indexVariable = indexToVariableMap.find(Cudd_NodeReadIndex(dd));
599 storm::expressions::Variable levelVariable;
600 if (indexVariable == indexToVariableMap.end()) {
601 levelVariable = manager.declareFreshBooleanVariable();
602 indexToVariableMap[Cudd_NodeReadIndex(dd)] = levelVariable;
603 } else {
604 levelVariable = indexVariable->second;
605 }
606 expressions.push_back(storm::expressions::iff(
607 newNodeVariable, storm::expressions::ite(levelVariable, t == T ? thenVariable : !thenVariable, e == E ? elseVariable : !elseVariable)));
608 }
609
610 // Return the variable for this node.
611 return newNodeVariable;
612}
613
614template InternalAdd<DdType::CUDD, double> InternalBdd<DdType::CUDD>::toAdd() const;
615template InternalAdd<DdType::CUDD, uint_fast64_t> InternalBdd<DdType::CUDD>::toAdd() const;
616#ifdef STORM_HAVE_CARL
617template InternalAdd<DdType::CUDD, storm::RationalNumber> InternalBdd<DdType::CUDD>::toAdd() const;
618#endif
619
620template void InternalBdd<DdType::CUDD>::filterExplicitVectorRec<double>(DdNode const* dd, cudd::Cudd const& manager, uint_fast64_t currentLevel,
621 bool complement, uint_fast64_t maxLevel,
622 std::vector<uint_fast64_t> const& ddVariableIndices, uint_fast64_t currentOffset,
623 storm::dd::Odd const& odd, std::vector<double>& result, uint_fast64_t& currentIndex,
624 std::vector<double> const& values);
625template void InternalBdd<DdType::CUDD>::filterExplicitVectorRec<uint_fast64_t>(DdNode const* dd, cudd::Cudd const& manager, uint_fast64_t currentLevel,
626 bool complement, uint_fast64_t maxLevel,
627 std::vector<uint_fast64_t> const& ddVariableIndices,
628 uint_fast64_t currentOffset, storm::dd::Odd const& odd,
629 std::vector<uint_fast64_t>& result, uint_fast64_t& currentIndex,
630 std::vector<uint_fast64_t> const& values);
631
632template void InternalBdd<DdType::CUDD>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
633 std::vector<double> const& sourceValues, std::vector<double>& targetValues) const;
634template void InternalBdd<DdType::CUDD>::filterExplicitVector(Odd const& odd, std::vector<uint_fast64_t> const& ddVariableIndices,
635 std::vector<uint_fast64_t> const& sourceValues, std::vector<uint_fast64_t>& targetValues) const;
636
637template InternalAdd<DdType::CUDD, double> InternalBdd<DdType::CUDD>::ite(InternalAdd<DdType::CUDD, double> const& thenAdd,
638 InternalAdd<DdType::CUDD, double> const& elseAdd) const;
639template InternalAdd<DdType::CUDD, uint_fast64_t> InternalBdd<DdType::CUDD>::ite(InternalAdd<DdType::CUDD, uint_fast64_t> const& thenAdd,
640 InternalAdd<DdType::CUDD, uint_fast64_t> const& elseAdd) const;
641template InternalAdd<DdType::CUDD, storm::RationalNumber> InternalBdd<DdType::CUDD>::ite(InternalAdd<DdType::CUDD, storm::RationalNumber> const& thenAdd,
642 InternalAdd<DdType::CUDD, storm::RationalNumber> const& elseAdd) const;
643} // namespace dd
644} // namespace storm
Odd const & getThenSuccessor() const
Retrieves the then-successor of this ODD node.
Definition Odd.cpp:23
uint_fast64_t getTotalOffset() const
Retrieves the total offset, i.e., the sum of the then- and else-offset.
Definition Odd.cpp:47
uint_fast64_t getElseOffset() const
Retrieves the else-offset of this ODD node.
Definition Odd.cpp:31
Odd const & getElseSuccessor() const
Retrieves the else-successor of this ODD node.
Definition Odd.cpp:27
uint_fast64_t getThenOffset() const
Retrieves the then-offset of this ODD node.
Definition Odd.cpp:39
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:18
void set(uint_fast64_t index, bool value=true)
Sets the given truth value at the given index.
bool get(uint_fast64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
#define STORM_LOG_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.
LabParser.cpp.
Definition cli.cpp:18