Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
QuotientExtractor.cpp
Go to the documentation of this file.
2
3#pragma clang diagnostic push
4#pragma clang diagnostic ignored "-Wcomma"
5#include <gtl/phmap.hpp>
6#pragma clang diagnostic pop
7#include <numeric>
8
25
26namespace storm {
27namespace dd {
28namespace bisimulation {
29
30template<storm::dd::DdType DdType>
32
33template<storm::dd::DdType DdType>
35 public:
36 InternalRepresentativeComputerBase(storm::dd::Bdd<DdType> const& partitionBdd, std::set<storm::expressions::Variable> const& rowVariables)
38 ddManager = &partitionBdd.getDdManager();
39 internalDdManager = &ddManager->getInternalDdManager();
40
41 // Create state variables cube.
42 this->rowVariablesCube = ddManager->getBddOne();
43 for (auto const& var : rowVariables) {
44 auto const& metaVariable = ddManager->getMetaVariable(var);
45 this->rowVariablesCube &= metaVariable.getCube();
46 }
47 }
48
49 protected:
52
53 std::set<storm::expressions::Variable> const& rowVariables;
55
57};
58
59template<>
61 public:
64#ifdef STORM_HAVE_CUDD
65 this->ddman = this->internalDdManager->getCuddManager().getManager();
66#else
67 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
68 "This version of Storm was compiled without support for CUDD. Yet, a method was called that requires this support. Please choose a "
69 "version of Storm with CUDD support.");
70#endif
71 }
72
74#ifdef STORM_HAVE_CUDD
76 *this->ddManager,
79 cudd::BDD(this->internalDdManager->getCuddManager(), this->getRepresentativesRec(this->partitionBdd.getInternalBdd().getCuddDdNode(),
80 this->rowVariablesCube.getInternalBdd().getCuddDdNode()))),
81 this->rowVariables);
82#else
83 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
84 "This version of Storm was compiled without support for CUDD. Yet, a method was called that requires this support. Please choose a "
85 "version of Storm with CUDD support.");
86#endif
87 }
88
89 private:
90#ifdef STORM_HAVE_CUDD
91 DdNodePtr getRepresentativesRec(DdNodePtr partitionNode, DdNodePtr stateVariablesCube) {
92 if (partitionNode == Cudd_ReadLogicZero(ddman)) {
93 return partitionNode;
94 }
95
96 // If we visited the node before, there is no block that we still need to cover.
97 if (visitedNodes.find(partitionNode) != visitedNodes.end()) {
98 return Cudd_ReadLogicZero(ddman);
99 }
100
101 // If we hit a block variable and have not yet terminated the DFS earlier, it means we have a new representative.
102 if (Cudd_IsConstant(stateVariablesCube)) {
103 visitedNodes.emplace(partitionNode, true);
104 return Cudd_ReadOne(ddman);
105 } else {
106 bool skipped = false;
107 DdNodePtr elsePartitionNode;
108 DdNodePtr thenPartitionNode;
109 if (Cudd_NodeReadIndex(partitionNode) == Cudd_NodeReadIndex(stateVariablesCube)) {
110 elsePartitionNode = Cudd_E(partitionNode);
111 thenPartitionNode = Cudd_T(partitionNode);
112
113 if (Cudd_IsComplement(partitionNode)) {
114 elsePartitionNode = Cudd_Not(elsePartitionNode);
115 thenPartitionNode = Cudd_Not(thenPartitionNode);
116 }
117 } else {
118 elsePartitionNode = thenPartitionNode = partitionNode;
119 skipped = true;
120 }
121
122 if (!skipped) {
123 visitedNodes.emplace(partitionNode, true);
124 }
125
126 // Otherwise, recursively proceed with DFS.
127 DdNodePtr elseResult = getRepresentativesRec(elsePartitionNode, Cudd_T(stateVariablesCube));
128 Cudd_Ref(elseResult);
129
130 DdNodePtr thenResult = nullptr;
131 if (!skipped) {
132 thenResult = getRepresentativesRec(thenPartitionNode, Cudd_T(stateVariablesCube));
133 Cudd_Ref(thenResult);
134
135 if (thenResult == elseResult) {
136 Cudd_Deref(elseResult);
137 Cudd_Deref(thenResult);
138 return elseResult;
139 } else {
140 bool complement = Cudd_IsComplement(thenResult);
141 auto result = cuddUniqueInter(ddman, Cudd_NodeReadIndex(stateVariablesCube), Cudd_Regular(thenResult),
142 complement ? Cudd_Not(elseResult) : elseResult);
143 Cudd_Deref(elseResult);
144 Cudd_Deref(thenResult);
145 return complement ? Cudd_Not(result) : result;
146 }
147 } else {
148 DdNodePtr result;
149 if (elseResult == Cudd_ReadLogicZero(ddman)) {
150 result = elseResult;
151 } else {
152 result = Cudd_Not(cuddUniqueInter(ddman, Cudd_NodeReadIndex(stateVariablesCube), Cudd_ReadOne(ddman), Cudd_Not(elseResult)));
153 }
154 Cudd_Deref(elseResult);
155 return result;
156 }
157 }
158 }
159
160 ::DdManager* ddman;
161 gtl::flat_hash_map<DdNode const*, bool> visitedNodes;
162#endif
163};
164
165template<>
167 public:
170#ifndef STORM_HAVE_SYLVAN
171 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
172 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
173 "version of Storm with Sylvan support.");
174#endif
175 // Intentionally left empty.
176 }
177
179#ifdef STORM_HAVE_SYLVAN
181 *this->ddManager,
183 this->internalDdManager, sylvan::Bdd(this->getRepresentativesRec(this->partitionBdd.getInternalBdd().getSylvanBdd().GetBDD(),
184 this->rowVariablesCube.getInternalBdd().getSylvanBdd().GetBDD()))),
185 this->rowVariables);
186#else
187 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
188 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
189 "version of Storm with Sylvan support.");
190#endif
191 }
192
193 private:
194#ifdef STORM_HAVE_SYLVAN
195 BDD getRepresentativesRec(BDD partitionNode, BDD stateVariablesCube) {
196 if (partitionNode == sylvan_false) {
197 return sylvan_false;
198 }
199
200 // If we visited the node before, there is no block that we still need to cover.
201 if (visitedNodes.find(partitionNode) != visitedNodes.end()) {
202 return sylvan_false;
203 }
204
205 // If we hit a block variable and have not yet terminated the DFS earlier, it means we have a new representative.
206 if (sylvan_isconst(stateVariablesCube)) {
207 visitedNodes.emplace(partitionNode, true);
208 return sylvan_true;
209 } else {
210 bool skipped = false;
211 BDD elsePartitionNode;
212 BDD thenPartitionNode;
213 if (sylvan_bdd_matches_variable_index(partitionNode, sylvan_var(stateVariablesCube))) {
214 elsePartitionNode = sylvan_low(partitionNode);
215 thenPartitionNode = sylvan_high(partitionNode);
216 } else {
217 elsePartitionNode = thenPartitionNode = partitionNode;
218 skipped = true;
219 }
220
221 if (!skipped) {
222 visitedNodes.emplace(partitionNode, true);
223 }
224
225 // Otherwise, recursively proceed with DFS.
226 BDD elseResult = getRepresentativesRec(elsePartitionNode, sylvan_high(stateVariablesCube));
227 mtbdd_refs_push(elseResult);
228
229 BDD thenResult;
230 if (!skipped) {
231 thenResult = getRepresentativesRec(thenPartitionNode, sylvan_high(stateVariablesCube));
232 mtbdd_refs_push(thenResult);
233
234 if (thenResult == elseResult) {
235 mtbdd_refs_pop(2);
236 return elseResult;
237 } else {
238 auto result = sylvan_makenode(sylvan_var(stateVariablesCube), elseResult, thenResult);
239 mtbdd_refs_pop(2);
240 return result;
241 }
242 } else {
243 BDD result;
244 if (elseResult == sylvan_false) {
245 result = elseResult;
246 } else {
247 result = sylvan_makenode(sylvan_var(stateVariablesCube), elseResult, sylvan_false);
248 }
249 mtbdd_refs_pop(1);
250 return result;
251 }
252 }
253 }
254
255 gtl::flat_hash_map<BDD, bool> visitedNodes;
256#endif
257};
258
259template<storm::dd::DdType DdType, typename ValueType, typename ExportValueType = ValueType>
261
262template<storm::dd::DdType DdType, typename ValueType, typename ExportValueType = ValueType>
264 public:
268 : model(model),
269 manager(model.getManager()),
270 isNondeterministic(false),
275 matrixEntriesCreated(false) {
276 // Create cubes.
277 rowVariablesCube = manager.getBddOne();
278 for (auto const& variable : model.getRowVariables()) {
279 auto const& ddMetaVariable = manager.getMetaVariable(variable);
280 rowVariablesCube &= ddMetaVariable.getCube();
281 }
282 columnVariablesCube = manager.getBddOne();
283 for (auto const& variable : model.getColumnVariables()) {
284 auto const& ddMetaVariable = manager.getMetaVariable(variable);
285 columnVariablesCube &= ddMetaVariable.getCube();
286 }
288 for (auto const& variable : model.getNondeterminismVariables()) {
289 auto const& ddMetaVariable = manager.getMetaVariable(variable);
290 nondeterminismVariablesCube &= ddMetaVariable.getCube();
291 }
294
295 // Create ODDs.
296 this->odd = representatives.createOdd();
297 if (this->isNondeterministic) {
298 this->nondeterminismOdd = (model.getQualitativeTransitionMatrix().existsAbstract(model.getColumnVariables()) && this->representatives).createOdd();
299 }
300
301 STORM_LOG_TRACE("Partition has " << partitionBdd.existsAbstract(model.getRowVariables()).getNonZeroCount() << " states in " << this->numberOfBlocks
302 << " blocks.");
303 }
304
306
310
311 std::vector<ExportValueType> extractStateVector(storm::dd::Add<DdType, ValueType> const& vector) {
312 return extractVectorInternal(vector, this->rowVariablesCube, this->odd);
313 }
314
315 std::vector<ExportValueType> extractStateActionVector(storm::dd::Add<DdType, ValueType> const& vector) {
316 if (!this->isNondeterministic) {
317 return extractStateVector(vector);
318 } else {
319 STORM_LOG_ASSERT(!this->rowPermutation.empty(), "Expected proper row permutation.");
320 std::vector<ExportValueType> valueVector = extractVectorInternal(vector, this->allSourceVariablesCube, this->nondeterminismOdd);
321
322 // Reorder the values according to the known row permutation.
323 std::vector<ExportValueType> reorderedValues(valueVector.size());
324 for (uint64_t pos = 0; pos < valueVector.size(); ++pos) {
325 reorderedValues[pos] = valueVector[rowPermutation[pos]];
326 }
327 return reorderedValues;
328 }
329 }
330
332 return (set && representatives).toVector(this->odd);
333 }
334
336 return ((set && partitionBdd).existsAbstract(model.getRowVariables()) && partitionBdd && representatives)
337 .existsAbstract({this->blockVariable})
338 .toVector(this->odd);
339 }
340
341 protected:
343
344 virtual std::vector<ExportValueType> extractVectorInternal(storm::dd::Add<DdType, ValueType> const& vector, storm::dd::Bdd<DdType> const& variablesCube,
345 storm::dd::Odd const& odd) = 0;
346
348 for (auto& row : matrixEntries) {
349 std::sort(row.begin(), row.end(),
351 storm::storage::MatrixEntry<uint_fast64_t, ExportValueType> const& b) { return a.getColumn() < b.getColumn(); });
352 }
353
354 rowPermutation = std::vector<uint64_t>(matrixEntries.size());
355 std::iota(rowPermutation.begin(), rowPermutation.end(), 0ull);
356 if (this->isNondeterministic) {
357 std::stable_sort(rowPermutation.begin(), rowPermutation.end(),
358 [this](uint64_t first, uint64_t second) { return this->rowToState[first] < this->rowToState[second]; });
359 }
360
361 uint64_t rowCounter = 0;
362 uint64_t lastState = this->isNondeterministic ? rowToState[rowPermutation.front()] : 0;
363 storm::storage::SparseMatrixBuilder<ExportValueType> builder(matrixEntries.size(), this->numberOfBlocks, 0, true, this->isNondeterministic);
364 if (this->isNondeterministic) {
365 builder.newRowGroup(0);
366 }
367 for (auto& rowIdx : rowPermutation) {
368 // For nondeterministic models, open a new row group.
369 if (this->isNondeterministic && rowToState[rowIdx] != lastState) {
370 builder.newRowGroup(rowCounter);
371 lastState = rowToState[rowIdx];
372 }
373
374 auto& row = matrixEntries[rowIdx];
375 for (auto const& entry : row) {
376 builder.addNextValue(rowCounter, entry.getColumn(), entry.getValue());
377 }
378
379 // Free storage for row.
380 row.clear();
381 row.shrink_to_fit();
382
383 ++rowCounter;
384 }
385
386 rowToState.clear();
387 rowToState.shrink_to_fit();
388 matrixEntries.clear();
389 matrixEntries.shrink_to_fit();
390
391 return builder.build();
392 }
393
394 void addMatrixEntry(uint64_t row, uint64_t column, ExportValueType const& value) {
395 this->matrixEntries[row].emplace_back(column, value);
396 }
397
400 matrixEntries.clear();
401 if (isNondeterministic) {
402 rowToState.clear();
403 }
404 }
405 matrixEntries.resize(this->isNondeterministic ? nondeterminismOdd.getTotalOffset() : odd.getTotalOffset());
406 if (isNondeterministic) {
407 rowToState.resize(matrixEntries.size());
408 }
409 }
410
411 void assignRowToState(uint64_t row, uint64_t state) {
412 rowToState[row] = state;
413 }
414
416
417 // The manager responsible for the DDs.
419
420 // A flag that stores whether we need to take care of nondeterminism.
422
423 // Useful cubes needed in the translation.
428
429 // Information about the state partition.
436
437 // A flag that stores whether the underlying storage for matrix entries has been created.
439
440 // The entries of the quotient matrix that is built.
441 std::vector<std::vector<storm::storage::MatrixEntry<uint_fast64_t, ExportValueType>>> matrixEntries;
442
443 // A vector storing for each row which state it belongs to.
444 std::vector<uint64_t> rowToState;
445
446 // A vector storing the row permutation for nondeterministic models.
447 std::vector<uint64_t> rowPermutation;
448};
449
450template<typename ValueType>
451class InternalSparseQuotientExtractor<storm::dd::DdType::CUDD, ValueType> : public InternalSparseQuotientExtractorBase<storm::dd::DdType::CUDD, ValueType> {
452 public:
453#ifdef STORM_HAVE_CUDD
458 ddman(this->manager.getInternalDdManager().getCuddManager().getManager()) {
459 this->createBlockToOffsetMapping();
460 }
461#else
466 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
467 "This version of Storm was compiled without support for CUDD. Yet, a method was called that requires this support. Please choose a "
468 "version of Storm with CUDD support.");
469 }
470#endif
471
472 private:
473 virtual storm::storage::SparseMatrix<ValueType> extractMatrixInternal(storm::dd::Add<storm::dd::DdType::CUDD, ValueType> const& matrix) override {
474#ifdef STORM_HAVE_CUDD
475
476 this->createMatrixEntryStorage();
477 extractTransitionMatrixRec(matrix.getInternalAdd().getCuddDdNode(), this->isNondeterministic ? this->nondeterminismOdd : this->odd, 0,
478 this->partitionBdd.getInternalBdd().getCuddDdNode(), this->representatives.getInternalBdd().getCuddDdNode(),
479 this->allSourceVariablesCube.getInternalBdd().getCuddDdNode(),
480 this->nondeterminismVariablesCube.getInternalBdd().getCuddDdNode(), this->isNondeterministic ? &this->odd : nullptr, 0);
481 return this->createMatrixFromEntries();
482#else
483 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
484 "This version of Storm was compiled without support for CUDD. Yet, a method was called that requires this support. Please choose a "
485 "version of Storm with CUDD support.");
486#endif
487 }
488
489 virtual std::vector<ValueType> extractVectorInternal(storm::dd::Add<storm::dd::DdType::CUDD, ValueType> const& vector,
490 storm::dd::Bdd<storm::dd::DdType::CUDD> const& variablesCube, storm::dd::Odd const& odd) override {
491#ifdef STORM_HAVE_CUDD
492 std::vector<ValueType> result(odd.getTotalOffset());
493 extractVectorRec(vector.getInternalAdd().getCuddDdNode(), this->representatives.getInternalBdd().getCuddDdNode(),
494 variablesCube.getInternalBdd().getCuddDdNode(), odd, 0, result);
495 return result;
496#else
497 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
498 "This version of Storm was compiled without support for CUDD. Yet, a method was called that requires this support. Please choose a "
499 "version of Storm with CUDD support.");
500#endif
501 }
502#ifdef STORM_HAVE_CUDD
503 void createBlockToOffsetMapping() {
504 this->createBlockToOffsetMappingRec(this->partitionBdd.getInternalBdd().getCuddDdNode(), this->representatives.getInternalBdd().getCuddDdNode(),
505 this->rowVariablesCube.getInternalBdd().getCuddDdNode(), this->odd, 0);
506 STORM_LOG_ASSERT(blockToOffset.size() == this->numberOfBlocks,
507 "Mismatching block-to-offset mapping: " << blockToOffset.size() << " vs. " << this->numberOfBlocks << ".");
508 }
509
510 void createBlockToOffsetMappingRec(DdNodePtr partitionNode, DdNodePtr representativesNode, DdNodePtr variables, storm::dd::Odd const& odd,
511 uint64_t offset) {
512 STORM_LOG_ASSERT(partitionNode != Cudd_ReadLogicZero(ddman) || representativesNode == Cudd_ReadLogicZero(ddman),
513 "Expected representative to be zero if the partition is zero.");
514 if (representativesNode == Cudd_ReadLogicZero(ddman) || partitionNode == Cudd_ReadLogicZero(ddman)) {
515 return;
516 }
517
518 if (Cudd_IsConstant(variables)) {
519 STORM_LOG_ASSERT(odd.isTerminalNode(), "Expected terminal node.");
520 STORM_LOG_ASSERT(blockToOffset.find(partitionNode) == blockToOffset.end(), "Duplicate entry.");
521 blockToOffset[partitionNode] = offset;
522 } else {
523 STORM_LOG_ASSERT(!odd.isTerminalNode(), "Expected non-terminal node.");
524 DdNodePtr partitionT;
525 DdNodePtr partitionE;
526 if (Cudd_NodeReadIndex(partitionNode) == Cudd_NodeReadIndex(variables)) {
527 partitionT = Cudd_T(partitionNode);
528 partitionE = Cudd_E(partitionNode);
529
530 if (Cudd_IsComplement(partitionNode)) {
531 partitionE = Cudd_Not(partitionE);
532 partitionT = Cudd_Not(partitionT);
533 }
534 } else {
535 partitionT = partitionE = partitionNode;
536 }
537
538 DdNodePtr representativesT;
539 DdNodePtr representativesE;
540 if (Cudd_NodeReadIndex(representativesNode) == Cudd_NodeReadIndex(variables)) {
541 representativesT = Cudd_T(representativesNode);
542 representativesE = Cudd_E(representativesNode);
543
544 if (Cudd_IsComplement(representativesNode)) {
545 representativesE = Cudd_Not(representativesE);
546 representativesT = Cudd_Not(representativesT);
547 }
548 } else {
549 representativesT = representativesE = representativesNode;
550 }
551
552 createBlockToOffsetMappingRec(partitionE, representativesE, Cudd_T(variables), odd.getElseSuccessor(), offset);
553 createBlockToOffsetMappingRec(partitionT, representativesT, Cudd_T(variables), odd.getThenSuccessor(), offset + odd.getElseOffset());
554 }
555 }
556
557 void extractVectorRec(DdNodePtr vector, DdNodePtr representativesNode, DdNodePtr variables, storm::dd::Odd const& odd, uint64_t offset,
558 std::vector<ValueType>& result) {
559 if (representativesNode == Cudd_ReadLogicZero(ddman) || vector == Cudd_ReadZero(ddman)) {
560 return;
561 }
562
563 if (Cudd_IsConstant(variables)) {
564 result[offset] = Cudd_V(vector);
565 } else {
566 DdNodePtr vectorT;
567 DdNodePtr vectorE;
568 if (Cudd_NodeReadIndex(vector) == Cudd_NodeReadIndex(variables)) {
569 vectorT = Cudd_T(vector);
570 vectorE = Cudd_E(vector);
571 } else {
572 vectorT = vectorE = vector;
573 }
574
575 DdNodePtr representativesT;
576 DdNodePtr representativesE;
577 if (Cudd_NodeReadIndex(representativesNode) == Cudd_NodeReadIndex(variables)) {
578 representativesT = Cudd_T(representativesNode);
579 representativesE = Cudd_E(representativesNode);
580
581 if (Cudd_IsComplement(representativesNode)) {
582 representativesT = Cudd_Not(representativesT);
583 representativesE = Cudd_Not(representativesE);
584 }
585 } else {
586 representativesT = representativesE = representativesNode;
587 }
588
589 extractVectorRec(vectorE, representativesE, Cudd_T(variables), odd.getElseSuccessor(), offset, result);
590 extractVectorRec(vectorT, representativesT, Cudd_T(variables), odd.getThenSuccessor(), offset + odd.getElseOffset(), result);
591 }
592 }
593
594 void extractTransitionMatrixRec(DdNodePtr transitionMatrixNode, storm::dd::Odd const& sourceOdd, uint64_t sourceOffset, DdNodePtr targetPartitionNode,
595 DdNodePtr representativesNode, DdNodePtr variables, DdNodePtr nondeterminismVariables, storm::dd::Odd const* stateOdd,
596 uint64_t stateOffset) {
597 // For the empty DD, we do not need to add any entries. Note that the partition nodes cannot be zero
598 // as all states of the model have to be contained.
599 if (transitionMatrixNode == Cudd_ReadZero(ddman) || representativesNode == Cudd_ReadLogicZero(ddman)) {
600 return;
601 }
602
603 // If we have moved through all source variables, we must have arrived at a target block encoding.
604 if (Cudd_IsConstant(variables)) {
605 STORM_LOG_ASSERT(Cudd_IsConstant(transitionMatrixNode), "Expected constant node.");
606 this->addMatrixEntry(sourceOffset, blockToOffset.at(targetPartitionNode), Cudd_V(transitionMatrixNode));
607 if (stateOdd) {
608 this->assignRowToState(sourceOffset, stateOffset);
609 }
610 } else {
611 // Determine whether the next variable is a nondeterminism variable.
612 bool nextVariableIsNondeterminismVariable =
613 !Cudd_IsConstant(nondeterminismVariables) && Cudd_NodeReadIndex(nondeterminismVariables) == Cudd_NodeReadIndex(variables);
614
615 if (nextVariableIsNondeterminismVariable) {
616 DdNodePtr t;
617 DdNodePtr e;
618
619 // Determine whether the variable was skipped in the matrix.
620 if (Cudd_NodeReadIndex(transitionMatrixNode) == Cudd_NodeReadIndex(variables)) {
621 t = Cudd_T(transitionMatrixNode);
622 e = Cudd_E(transitionMatrixNode);
623 } else {
624 t = e = transitionMatrixNode;
625 }
626
627 STORM_LOG_ASSERT(stateOdd, "Expected separate state ODD.");
628 extractTransitionMatrixRec(e, sourceOdd.getElseSuccessor(), sourceOffset, targetPartitionNode, representativesNode, Cudd_T(variables),
629 Cudd_T(nondeterminismVariables), stateOdd, stateOffset);
630 extractTransitionMatrixRec(t, sourceOdd.getThenSuccessor(), sourceOffset + sourceOdd.getElseOffset(), targetPartitionNode, representativesNode,
631 Cudd_T(variables), Cudd_T(nondeterminismVariables), stateOdd, stateOffset);
632 } else {
633 DdNodePtr t;
634 DdNodePtr tt;
635 DdNodePtr te;
636 DdNodePtr e;
637 DdNodePtr et;
638 DdNodePtr ee;
639 if (Cudd_NodeReadIndex(transitionMatrixNode) == Cudd_NodeReadIndex(variables)) {
640 // Source node was not skipped in transition matrix.
641 t = Cudd_T(transitionMatrixNode);
642 e = Cudd_E(transitionMatrixNode);
643 } else {
644 t = e = transitionMatrixNode;
645 }
646
647 if (Cudd_NodeReadIndex(t) == Cudd_NodeReadIndex(variables) + 1) {
648 // Target node was not skipped in transition matrix.
649 tt = Cudd_T(t);
650 te = Cudd_E(t);
651 } else {
652 // Target node was skipped in transition matrix.
653 tt = te = t;
654 }
655 if (t != e) {
656 if (Cudd_NodeReadIndex(e) == Cudd_NodeReadIndex(variables) + 1) {
657 // Target node was not skipped in transition matrix.
658 et = Cudd_T(e);
659 ee = Cudd_E(e);
660 } else {
661 // Target node was skipped in transition matrix.
662 et = ee = e;
663 }
664 } else {
665 et = tt;
666 ee = te;
667 }
668
669 DdNodePtr targetT;
670 DdNodePtr targetE;
671 if (Cudd_NodeReadIndex(targetPartitionNode) == Cudd_NodeReadIndex(variables)) {
672 // Node was not skipped in target partition.
673 targetT = Cudd_T(targetPartitionNode);
674 targetE = Cudd_E(targetPartitionNode);
675
676 if (Cudd_IsComplement(targetPartitionNode)) {
677 targetT = Cudd_Not(targetT);
678 targetE = Cudd_Not(targetE);
679 }
680 } else {
681 // Node was skipped in target partition.
682 targetT = targetE = targetPartitionNode;
683 }
684
685 DdNodePtr representativesT;
686 DdNodePtr representativesE;
687 if (Cudd_NodeReadIndex(representativesNode) == Cudd_NodeReadIndex(variables)) {
688 // Node was not skipped in representatives.
689 representativesT = Cudd_T(representativesNode);
690 representativesE = Cudd_E(representativesNode);
691 } else {
692 // Node was skipped in representatives.
693 representativesT = representativesE = representativesNode;
694 }
695
696 if (representativesT != representativesE && Cudd_IsComplement(representativesNode)) {
697 representativesT = Cudd_Not(representativesT);
698 representativesE = Cudd_Not(representativesE);
699 }
700
701 extractTransitionMatrixRec(ee, sourceOdd.getElseSuccessor(), sourceOffset, targetE, representativesE, Cudd_T(variables),
702 nondeterminismVariables, stateOdd ? &stateOdd->getElseSuccessor() : stateOdd, stateOffset);
703 extractTransitionMatrixRec(et, sourceOdd.getElseSuccessor(), sourceOffset, targetT, representativesE, Cudd_T(variables),
704 nondeterminismVariables, stateOdd ? &stateOdd->getElseSuccessor() : stateOdd, stateOffset);
705 extractTransitionMatrixRec(te, sourceOdd.getThenSuccessor(), sourceOffset + sourceOdd.getElseOffset(), targetE, representativesT,
706 Cudd_T(variables), nondeterminismVariables, stateOdd ? &stateOdd->getThenSuccessor() : stateOdd,
707 stateOffset + (stateOdd ? stateOdd->getElseOffset() : 0));
708 extractTransitionMatrixRec(tt, sourceOdd.getThenSuccessor(), sourceOffset + sourceOdd.getElseOffset(), targetT, representativesT,
709 Cudd_T(variables), nondeterminismVariables, stateOdd ? &stateOdd->getThenSuccessor() : stateOdd,
710 stateOffset + (stateOdd ? stateOdd->getElseOffset() : 0));
711 }
712 }
713 }
714
715 ::DdManager* ddman;
716
717 // A mapping from blocks (stored in terms of a DD node) to the offset of the corresponding block.
718 gtl::flat_hash_map<DdNode const*, uint64_t> blockToOffset;
719#endif
720};
721
722template<typename ValueType, typename ExportValueType>
724 : public InternalSparseQuotientExtractorBase<storm::dd::DdType::Sylvan, ValueType, ExportValueType> {
725 public:
731#ifdef STORM_HAVE_SYLVAN
732 this->createBlockToOffsetMapping();
733#else
734 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
735 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
736 "version of Storm with Sylvan support.");
737#endif
738 }
739
740 private:
742#ifdef STORM_HAVE_SYLVAN
743 this->createMatrixEntryStorage();
744 extractTransitionMatrixRec(matrix.getInternalAdd().getSylvanMtbdd().GetMTBDD(), this->isNondeterministic ? this->nondeterminismOdd : this->odd, 0,
745 this->partitionBdd.getInternalBdd().getSylvanBdd().GetBDD(), this->representatives.getInternalBdd().getSylvanBdd().GetBDD(),
746 this->allSourceVariablesCube.getInternalBdd().getSylvanBdd().GetBDD(),
747 this->nondeterminismVariablesCube.getInternalBdd().getSylvanBdd().GetBDD(), this->isNondeterministic ? &this->odd : nullptr,
748 0);
749 return this->createMatrixFromEntries();
750#else
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#endif
755 }
756
757 virtual std::vector<ExportValueType> extractVectorInternal(storm::dd::Add<storm::dd::DdType::Sylvan, ValueType> const& vector,
759 storm::dd::Odd const& odd) override {
760#ifdef STORM_HAVE_SYLVAN
761 std::vector<ExportValueType> result(odd.getTotalOffset());
762 extractVectorRec(vector.getInternalAdd().getSylvanMtbdd().GetMTBDD(), this->representatives.getInternalBdd().getSylvanBdd().GetBDD(),
763 variablesCube.getInternalBdd().getSylvanBdd().GetBDD(), odd, 0, result);
764 return result;
765#else
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#endif
770 }
771
772#ifdef STORM_HAVE_SYLVAN
773 void extractVectorRec(MTBDD vector, BDD representativesNode, BDD variables, storm::dd::Odd const& odd, uint64_t offset,
774 std::vector<ExportValueType>& result) {
775 if (representativesNode == sylvan_false || mtbdd_iszero(vector)) {
776 return;
777 }
778
779 if (sylvan_isconst(variables)) {
781 } else {
782 MTBDD vectorT;
783 MTBDD vectorE;
784 if (sylvan_mtbdd_matches_variable_index(vector, sylvan_var(variables))) {
785 vectorT = sylvan_high(vector);
786 vectorE = sylvan_low(vector);
787 } else {
788 vectorT = vectorE = vector;
789 }
790
791 BDD representativesT;
792 BDD representativesE;
793 if (sylvan_bdd_matches_variable_index(representativesNode, sylvan_var(variables))) {
794 representativesT = sylvan_high(representativesNode);
795 representativesE = sylvan_low(representativesNode);
796 } else {
797 representativesT = representativesE = representativesNode;
798 }
799
800 extractVectorRec(vectorE, representativesE, sylvan_high(variables), odd.getElseSuccessor(), offset, result);
801 extractVectorRec(vectorT, representativesT, sylvan_high(variables), odd.getThenSuccessor(), offset + odd.getElseOffset(), result);
802 }
803 }
804
805 void createBlockToOffsetMapping() {
806 this->createBlockToOffsetMappingRec(this->partitionBdd.getInternalBdd().getSylvanBdd().GetBDD(),
807 this->representatives.getInternalBdd().getSylvanBdd().GetBDD(),
808 this->rowVariablesCube.getInternalBdd().getSylvanBdd().GetBDD(), this->odd, 0);
809 STORM_LOG_ASSERT(blockToOffset.size() == this->numberOfBlocks,
810 "Mismatching block-to-offset mapping: " << blockToOffset.size() << " vs. " << this->numberOfBlocks << ".");
811 }
812
813 void createBlockToOffsetMappingRec(BDD partitionNode, BDD representativesNode, BDD variables, storm::dd::Odd const& odd, uint64_t offset) {
814 STORM_LOG_ASSERT(partitionNode != sylvan_false || representativesNode == sylvan_false, "Expected representative to be zero if the partition is zero.");
815 if (representativesNode == sylvan_false || partitionNode == sylvan_false) {
816 return;
817 }
818
819 if (sylvan_isconst(variables)) {
820 STORM_LOG_ASSERT(odd.isTerminalNode(), "Expected terminal node.");
821 STORM_LOG_ASSERT(blockToOffset.find(partitionNode) == blockToOffset.end(), "Duplicate entry.");
822 blockToOffset[partitionNode] = offset;
823 } else {
824 STORM_LOG_ASSERT(!odd.isTerminalNode(), "Expected non-terminal node.");
825 BDD partitionT;
826 BDD partitionE;
827 if (sylvan_bdd_matches_variable_index(partitionNode, sylvan_var(variables))) {
828 partitionT = sylvan_high(partitionNode);
829 partitionE = sylvan_low(partitionNode);
830 } else {
831 partitionT = partitionE = partitionNode;
832 }
833
834 BDD representativesT;
835 BDD representativesE;
836 if (sylvan_bdd_matches_variable_index(representativesNode, sylvan_var(variables))) {
837 representativesT = sylvan_high(representativesNode);
838 representativesE = sylvan_low(representativesNode);
839 } else {
840 representativesT = representativesE = representativesNode;
841 }
842
843 createBlockToOffsetMappingRec(partitionE, representativesE, sylvan_high(variables), odd.getElseSuccessor(), offset);
844 createBlockToOffsetMappingRec(partitionT, representativesT, sylvan_high(variables), odd.getThenSuccessor(), offset + odd.getElseOffset());
845 }
846 }
847
848 void extractTransitionMatrixRec(MTBDD transitionMatrixNode, storm::dd::Odd const& sourceOdd, uint64_t sourceOffset, BDD targetPartitionNode,
849 BDD representativesNode, BDD variables, BDD nondeterminismVariables, storm::dd::Odd const* stateOdd, uint64_t stateOffset) {
850 // For the empty DD, we do not need to add any entries. Note that the partition nodes cannot be zero
851 // as all states of the model have to be contained.
852 if (mtbdd_iszero(transitionMatrixNode) || representativesNode == sylvan_false) {
853 return;
854 }
855
856 // If we have moved through all source variables, we must have arrived at a target block encoding.
857 if (sylvan_isconst(variables)) {
858 STORM_LOG_ASSERT(mtbdd_isleaf(transitionMatrixNode), "Expected constant node.");
859 this->addMatrixEntry(
860 sourceOffset, blockToOffset.at(targetPartitionNode),
861 storm::utility::convertNumber<ExportValueType>(storm::dd::InternalAdd<storm::dd::DdType::Sylvan, ValueType>::getValue(transitionMatrixNode)));
862 if (stateOdd) {
863 this->assignRowToState(sourceOffset, stateOffset);
864 }
865 } else {
866 // Determine whether the next variable is a nondeterminism variable.
867 bool nextVariableIsNondeterminismVariable =
868 !sylvan_isconst(nondeterminismVariables) && sylvan_var(nondeterminismVariables) == sylvan_var(variables);
869
870 if (nextVariableIsNondeterminismVariable) {
871 MTBDD t;
872 MTBDD e;
873
874 // Determine whether the variable was skipped in the matrix.
875 if (sylvan_mtbdd_matches_variable_index(transitionMatrixNode, sylvan_var(variables))) {
876 t = sylvan_high(transitionMatrixNode);
877 e = sylvan_low(transitionMatrixNode);
878 } else {
879 t = e = transitionMatrixNode;
880 }
881
882 STORM_LOG_ASSERT(stateOdd, "Expected separate state ODD.");
883 extractTransitionMatrixRec(e, sourceOdd.getElseSuccessor(), sourceOffset, targetPartitionNode, representativesNode, sylvan_high(variables),
884 sylvan_high(nondeterminismVariables), stateOdd, stateOffset);
885 extractTransitionMatrixRec(t, sourceOdd.getThenSuccessor(), sourceOffset + sourceOdd.getElseOffset(), targetPartitionNode, representativesNode,
886 sylvan_high(variables), sylvan_high(nondeterminismVariables), stateOdd, stateOffset);
887 } else {
888 MTBDD t;
889 MTBDD tt;
890 MTBDD te;
891 MTBDD e;
892 MTBDD et;
893 MTBDD ee;
894 if (sylvan_mtbdd_matches_variable_index(transitionMatrixNode, sylvan_var(variables))) {
895 // Source node was not skipped in transition matrix.
896 t = sylvan_high(transitionMatrixNode);
897 e = sylvan_low(transitionMatrixNode);
898 } else {
899 t = e = transitionMatrixNode;
900 }
901
902 if (sylvan_mtbdd_matches_variable_index(t, sylvan_var(variables) + 1)) {
903 // Target node was not skipped in transition matrix.
904 tt = sylvan_high(t);
905 te = sylvan_low(t);
906 } else {
907 // Target node was skipped in transition matrix.
908 tt = te = t;
909 }
910 if (t != e) {
911 if (sylvan_mtbdd_matches_variable_index(e, sylvan_var(variables) + 1)) {
912 // Target node was not skipped in transition matrix.
913 et = sylvan_high(e);
914 ee = sylvan_low(e);
915 } else {
916 // Target node was skipped in transition matrix.
917 et = ee = e;
918 }
919 } else {
920 et = tt;
921 ee = te;
922 }
923
924 BDD targetT;
925 BDD targetE;
926 if (sylvan_bdd_matches_variable_index(targetPartitionNode, sylvan_var(variables))) {
927 // Node was not skipped in target partition.
928 targetT = sylvan_high(targetPartitionNode);
929 targetE = sylvan_low(targetPartitionNode);
930 } else {
931 // Node was skipped in target partition.
932 targetT = targetE = targetPartitionNode;
933 }
934
935 BDD representativesT;
936 BDD representativesE;
937 if (sylvan_bdd_matches_variable_index(representativesNode, sylvan_var(variables))) {
938 // Node was not skipped in representatives.
939 representativesT = sylvan_high(representativesNode);
940 representativesE = sylvan_low(representativesNode);
941 } else {
942 // Node was skipped in representatives.
943 representativesT = representativesE = representativesNode;
944 }
945
946 extractTransitionMatrixRec(ee, sourceOdd.getElseSuccessor(), sourceOffset, targetE, representativesE, sylvan_high(variables),
947 nondeterminismVariables, stateOdd ? &stateOdd->getElseSuccessor() : stateOdd, stateOffset);
948 extractTransitionMatrixRec(et, sourceOdd.getElseSuccessor(), sourceOffset, targetT, representativesE, sylvan_high(variables),
949 nondeterminismVariables, stateOdd ? &stateOdd->getElseSuccessor() : stateOdd, stateOffset);
950 extractTransitionMatrixRec(te, sourceOdd.getThenSuccessor(), sourceOffset + sourceOdd.getElseOffset(), targetE, representativesT,
951 sylvan_high(variables), nondeterminismVariables, stateOdd ? &stateOdd->getThenSuccessor() : stateOdd,
952 stateOffset + (stateOdd ? stateOdd->getElseOffset() : 0));
953 extractTransitionMatrixRec(tt, sourceOdd.getThenSuccessor(), sourceOffset + sourceOdd.getElseOffset(), targetT, representativesT,
954 sylvan_high(variables), nondeterminismVariables, stateOdd ? &stateOdd->getThenSuccessor() : stateOdd,
955 stateOffset + (stateOdd ? stateOdd->getElseOffset() : 0));
956 }
957 }
958 }
959
960 // A mapping from blocks (stored in terms of a DD node) to the offset of the corresponding block.
961 gtl::flat_hash_map<BDD, uint64_t> blockToOffset;
962#endif
963};
964
965template<storm::dd::DdType DdType, typename ValueType, typename ExportValueType>
967 BisimulationOptions const& bisimulationOptions)
968 : useRepresentatives(bisimulationOptions.useRepresentatives),
969 useOriginalVariables(bisimulationOptions.useOriginalVariables),
970 quotientFormat(quotientFormat) {
971 // Intentionally left empty.
972}
973
974template<storm::dd::DdType DdType, typename ValueType, typename ExportValueType>
975std::shared_ptr<storm::models::Model<ExportValueType>> QuotientExtractor<DdType, ValueType, ExportValueType>::extract(
977 PreservationInformation<DdType, ValueType> const& preservationInformation) {
978 auto start = std::chrono::high_resolution_clock::now();
979 std::shared_ptr<storm::models::Model<ExportValueType>> result;
981 result = extractSparseQuotient(model, partition, preservationInformation);
982 } else {
983 result = extractDdQuotient(model, partition, preservationInformation);
984 }
985 auto end = std::chrono::high_resolution_clock::now();
986 STORM_LOG_INFO("Quotient extraction completed in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
987
988 STORM_LOG_THROW(result, storm::exceptions::NotSupportedException, "Quotient could not be extracted.");
989
990 return result;
991}
992
993template<storm::dd::DdType DdType, typename ValueType, typename ExportValueType>
994std::shared_ptr<storm::models::sparse::Model<ExportValueType>> QuotientExtractor<DdType, ValueType, ExportValueType>::extractSparseQuotient(
996 PreservationInformation<DdType, ValueType> const& preservationInformation) {
997 auto states = partition.getStates().swapVariables(model.getRowColumnMetaVariablePairs());
998
999 storm::dd::Bdd<DdType> partitionAsBdd = partition.storedAsAdd() ? partition.asAdd().toBdd() : partition.asBdd();
1000 partitionAsBdd = partitionAsBdd.renameVariables(model.getColumnVariables(), model.getRowVariables());
1001
1002 auto start = std::chrono::high_resolution_clock::now();
1003 auto representatives = InternalRepresentativeComputer<DdType>(partitionAsBdd, model.getRowVariables()).getRepresentatives();
1005 representatives.getNonZeroCount() == partition.getNumberOfBlocks(),
1006 "Representatives size does not match that of the partition: " << representatives.getNonZeroCount() << " vs. " << partition.getNumberOfBlocks() << ".");
1007 STORM_LOG_ASSERT((representatives && partitionAsBdd).existsAbstract(model.getRowVariables()) == partitionAsBdd.existsAbstract(model.getRowVariables()),
1008 "Representatives do not cover all blocks.");
1009 InternalSparseQuotientExtractor<DdType, ValueType, ExportValueType> sparseExtractor(model, partitionAsBdd, partition.getBlockVariable(),
1010 partition.getNumberOfBlocks(), representatives);
1011 storm::storage::SparseMatrix<ExportValueType> quotientTransitionMatrix = sparseExtractor.extractTransitionMatrix(model.getTransitionMatrix());
1012 auto end = std::chrono::high_resolution_clock::now();
1013 STORM_LOG_INFO("Quotient transition matrix extracted in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
1014
1015 start = std::chrono::high_resolution_clock::now();
1016 storm::models::sparse::StateLabeling quotientStateLabeling(partition.getNumberOfBlocks());
1017 quotientStateLabeling.addLabel("init", sparseExtractor.extractSetExists(model.getInitialStates()));
1018 quotientStateLabeling.addLabel("deadlock", sparseExtractor.extractSetExists(model.getDeadlockStates()));
1019
1020 for (auto const& label : preservationInformation.getLabels()) {
1021 quotientStateLabeling.addLabel(label, sparseExtractor.extractSetAll(model.getStates(label)));
1022 }
1023 for (auto const& expression : preservationInformation.getExpressions()) {
1024 std::stringstream stream;
1025 stream << expression;
1026 std::string expressionAsString = stream.str();
1027
1028 if (quotientStateLabeling.containsLabel(expressionAsString)) {
1029 STORM_LOG_WARN("Duplicate label '" << expressionAsString << "', dropping second label definition.");
1030 } else {
1031 quotientStateLabeling.addLabel(stream.str(), sparseExtractor.extractSetAll(model.getStates(expression)));
1032 }
1033 }
1034 end = std::chrono::high_resolution_clock::now();
1035 STORM_LOG_INFO("Quotient labels extracted in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
1036
1037 start = std::chrono::high_resolution_clock::now();
1038 std::unordered_map<std::string, storm::models::sparse::StandardRewardModel<ExportValueType>> quotientRewardModels;
1039 for (auto const& rewardModelName : preservationInformation.getRewardModelNames()) {
1040 auto const& rewardModel = model.getRewardModel(rewardModelName);
1041
1042 std::optional<std::vector<ExportValueType>> quotientStateRewards;
1043 if (rewardModel.hasStateRewards()) {
1044 quotientStateRewards = sparseExtractor.extractStateVector(rewardModel.getStateRewardVector());
1045 }
1046
1047 std::optional<std::vector<ExportValueType>> quotientStateActionRewards;
1048 if (rewardModel.hasStateActionRewards()) {
1049 quotientStateActionRewards = sparseExtractor.extractStateActionVector(rewardModel.getStateActionRewardVector());
1050 }
1051
1052 quotientRewardModels.emplace(rewardModelName, storm::models::sparse::StandardRewardModel<ExportValueType>(
1053 std::move(quotientStateRewards), std::move(quotientStateActionRewards), std::nullopt));
1054 }
1055 end = std::chrono::high_resolution_clock::now();
1056 STORM_LOG_INFO("Reward models extracted in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
1057
1058 std::shared_ptr<storm::models::sparse::Model<ExportValueType>> result;
1059 if (model.getType() == storm::models::ModelType::Dtmc) {
1060 result = std::make_shared<storm::models::sparse::Dtmc<ExportValueType>>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling),
1061 std::move(quotientRewardModels));
1062 } else if (model.getType() == storm::models::ModelType::Ctmc) {
1063 result = std::make_shared<storm::models::sparse::Ctmc<ExportValueType>>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling),
1064 std::move(quotientRewardModels));
1065 } else if (model.getType() == storm::models::ModelType::Mdp) {
1066 result = std::make_shared<storm::models::sparse::Mdp<ExportValueType>>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling),
1067 std::move(quotientRewardModels));
1068 } else if (model.getType() == storm::models::ModelType::MarkovAutomaton) {
1069 storm::models::symbolic::MarkovAutomaton<DdType, ValueType> const& markovAutomaton =
1070 *model.template as<storm::models::symbolic::MarkovAutomaton<DdType, ValueType>>();
1071
1072 boost::optional<storm::storage::BitVector> markovianStates = sparseExtractor.extractSetExists(markovAutomaton.getMarkovianStates());
1073 storm::storage::sparse::ModelComponents<ExportValueType> modelComponents(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling),
1074 std::move(quotientRewardModels), false, std::move(markovianStates));
1075 modelComponents.exitRates = sparseExtractor.extractStateVector(markovAutomaton.getExitRateVector());
1076
1077 result = std::make_shared<storm::models::sparse::MarkovAutomaton<ExportValueType>>(std::move(modelComponents));
1078 }
1079
1080 return result;
1081}
1082
1083template<storm::dd::DdType DdType, typename ValueType, typename ExportValueType>
1084std::shared_ptr<storm::models::symbolic::Model<DdType, ExportValueType>> QuotientExtractor<DdType, ValueType, ExportValueType>::extractDdQuotient(
1085 storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition,
1086 PreservationInformation<DdType, ValueType> const& preservationInformation) {
1087 if (this->useOriginalVariables) {
1088 return extractQuotientUsingOriginalVariables(model, partition, preservationInformation);
1089 } else {
1090 return extractQuotientUsingBlockVariables(model, partition, preservationInformation);
1091 }
1092}
1093
1094template<storm::dd::DdType DdType, typename ValueType, typename ExportValueType>
1095std::shared_ptr<storm::models::symbolic::Model<DdType, ExportValueType>>
1096QuotientExtractor<DdType, ValueType, ExportValueType>::extractQuotientUsingBlockVariables(
1097 storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition,
1098 PreservationInformation<DdType, ValueType> const& preservationInformation) {
1099 auto modelType = model.getType();
1100
1101 bool useRepresentativesForThisExtraction = this->useRepresentatives;
1102 if (modelType == storm::models::ModelType::Dtmc || modelType == storm::models::ModelType::Ctmc || modelType == storm::models::ModelType::Mdp ||
1104 // Sanity checks.
1105 STORM_LOG_ASSERT(partition.getNumberOfStates() == model.getNumberOfStates(), "Mismatching partition size.");
1106 STORM_LOG_ASSERT(partition.getStates().renameVariables(model.getColumnVariables(), model.getRowVariables()) == model.getReachableStates(),
1107 "Mismatching partition.");
1108
1109 std::set<storm::expressions::Variable> blockVariableSet = {partition.getBlockVariable()};
1110 std::set<storm::expressions::Variable> blockPrimeVariableSet = {partition.getPrimedBlockVariable()};
1111 std::vector<std::pair<storm::expressions::Variable, storm::expressions::Variable>> blockMetaVariablePairs = {
1112 std::make_pair(partition.getBlockVariable(), partition.getPrimedBlockVariable())};
1113
1114 auto start = std::chrono::high_resolution_clock::now();
1115
1116 // Compute representatives.
1117 storm::dd::Bdd<DdType> partitionAsBdd = partition.storedAsBdd() ? partition.asBdd() : partition.asAdd().notZero();
1118 partitionAsBdd = partitionAsBdd.renameVariables(model.getColumnVariables(), model.getRowVariables());
1119 auto representatives = InternalRepresentativeComputer<DdType>(partitionAsBdd, model.getRowVariables()).getRepresentatives();
1120
1121 if (useRepresentativesForThisExtraction) {
1122 storm::dd::Bdd<DdType> partitionAsBddOverPrimedBlockVariables = partitionAsBdd.renameVariables(blockVariableSet, blockPrimeVariableSet);
1123 storm::dd::Bdd<DdType> tmp =
1124 (representatives && partitionAsBddOverPrimedBlockVariables).renameVariablesConcretize(model.getRowVariables(), blockVariableSet);
1125 partitionAsBdd = (tmp && partitionAsBddOverPrimedBlockVariables).existsAbstract(blockPrimeVariableSet);
1126 }
1127
1128 storm::dd::Bdd<DdType> reachableStates = partitionAsBdd.existsAbstract(model.getRowVariables());
1129 storm::dd::Bdd<DdType> initialStates = (model.getInitialStates() && partitionAsBdd).existsAbstract(model.getRowVariables());
1130
1131 std::map<std::string, storm::dd::Bdd<DdType>> preservedLabelBdds;
1132 for (auto const& label : preservationInformation.getLabels()) {
1133 preservedLabelBdds.emplace(label, (model.getStates(label) && partitionAsBdd).existsAbstract(model.getRowVariables()));
1134 }
1135 for (auto const& expression : preservationInformation.getExpressions()) {
1136 std::stringstream stream;
1137 stream << expression;
1138 std::string expressionAsString = stream.str();
1139
1140 auto it = preservedLabelBdds.find(expressionAsString);
1141 if (it != preservedLabelBdds.end()) {
1142 STORM_LOG_WARN("Duplicate label '" << expressionAsString << "', dropping second label definition.");
1143 } else {
1144 preservedLabelBdds.emplace(stream.str(), (model.getStates(expression) && partitionAsBdd).existsAbstract(model.getRowVariables()));
1145 }
1146 }
1147 auto end = std::chrono::high_resolution_clock::now();
1148 STORM_LOG_INFO("Quotient labels extracted in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
1149
1150 start = std::chrono::high_resolution_clock::now();
1151 std::set<storm::expressions::Variable> blockAndRowVariables;
1152 std::set_union(blockVariableSet.begin(), blockVariableSet.end(), model.getRowVariables().begin(), model.getRowVariables().end(),
1153 std::inserter(blockAndRowVariables, blockAndRowVariables.end()));
1154 std::set<storm::expressions::Variable> blockPrimeAndColumnVariables;
1155 std::set_union(blockPrimeVariableSet.begin(), blockPrimeVariableSet.end(), model.getColumnVariables().begin(), model.getColumnVariables().end(),
1156 std::inserter(blockPrimeAndColumnVariables, blockPrimeAndColumnVariables.end()));
1157 storm::dd::Add<DdType, ValueType> partitionAsAdd = partitionAsBdd.template toAdd<ValueType>();
1158 storm::dd::Add<DdType, ValueType> quotientTransitionMatrix = model.getTransitionMatrix().multiplyMatrix(
1159 partitionAsAdd.renameVariables(blockAndRowVariables, blockPrimeAndColumnVariables), model.getColumnVariables());
1160
1161 // Pick a representative from each block.
1162 partitionAsBdd &= representatives;
1163 partitionAsAdd *= partitionAsBdd.template toAdd<ValueType>();
1164
1165 quotientTransitionMatrix = quotientTransitionMatrix.multiplyMatrix(partitionAsAdd, model.getRowVariables());
1166 end = std::chrono::high_resolution_clock::now();
1167
1168 // Check quotient matrix for sanity.
1169 if (std::is_same<ValueType, storm::RationalNumber>::value) {
1170 STORM_LOG_ASSERT(quotientTransitionMatrix.greater(storm::utility::one<ValueType>()).isZero(), "Illegal entries in quotient matrix.");
1171 } else if (std::is_same<ValueType, storm::RationalFunction>::value) {
1172 // No comparison for rational functions
1173 } else {
1175 "Illegal entries in quotient matrix.");
1176 }
1177 STORM_LOG_ASSERT(quotientTransitionMatrix.sumAbstract(blockPrimeVariableSet)
1178 .equalModuloPrecision(quotientTransitionMatrix.notZero().existsAbstract(blockPrimeVariableSet).template toAdd<ValueType>(),
1180 "Illegal non-probabilistic matrix.");
1181
1182 STORM_LOG_INFO("Quotient transition matrix extracted in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
1183
1184 storm::dd::Bdd<DdType> quotientTransitionMatrixBdd = quotientTransitionMatrix.notZero();
1185
1186 std::set<storm::expressions::Variable> blockPrimeAndNondeterminismVariables = model.getNondeterminismVariables();
1187 blockPrimeAndNondeterminismVariables.insert(blockPrimeVariableSet.begin(), blockPrimeVariableSet.end());
1188 storm::dd::Bdd<DdType> deadlockStates = !quotientTransitionMatrixBdd.existsAbstract(blockPrimeAndNondeterminismVariables) && reachableStates;
1189
1190 start = std::chrono::high_resolution_clock::now();
1191 std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<DdType, ValueType>> quotientRewardModels;
1192 for (auto const& rewardModelName : preservationInformation.getRewardModelNames()) {
1193 auto const& rewardModel = model.getRewardModel(rewardModelName);
1194
1195 boost::optional<storm::dd::Add<DdType, ValueType>> quotientStateRewards;
1196 if (rewardModel.hasStateRewards()) {
1197 quotientStateRewards = rewardModel.getStateRewardVector().multiplyMatrix(partitionAsAdd, model.getRowVariables());
1198 }
1199
1200 boost::optional<storm::dd::Add<DdType, ValueType>> quotientStateActionRewards;
1201 if (rewardModel.hasStateActionRewards()) {
1202 quotientStateActionRewards = rewardModel.getStateActionRewardVector().multiplyMatrix(partitionAsAdd, model.getRowVariables());
1203 }
1204
1205 quotientRewardModels.emplace(rewardModelName, storm::models::symbolic::StandardRewardModel<DdType, ValueType>(
1206 quotientStateRewards, quotientStateActionRewards, boost::none));
1207 }
1208 end = std::chrono::high_resolution_clock::now();
1209 STORM_LOG_INFO("Reward models extracted in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
1210
1211 std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> result;
1212 if (modelType == storm::models::ModelType::Dtmc) {
1213 result = std::shared_ptr<storm::models::symbolic::Dtmc<DdType, ValueType>>(new storm::models::symbolic::Dtmc<DdType, ValueType>(
1214 model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet,
1215 blockPrimeVariableSet, blockMetaVariablePairs, preservedLabelBdds, quotientRewardModels));
1216 } else if (modelType == storm::models::ModelType::Ctmc) {
1217 result = std::shared_ptr<storm::models::symbolic::Ctmc<DdType, ValueType>>(new storm::models::symbolic::Ctmc<DdType, ValueType>(
1218 model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet,
1219 blockPrimeVariableSet, blockMetaVariablePairs, preservedLabelBdds, quotientRewardModels));
1220 } else if (modelType == storm::models::ModelType::Mdp) {
1221 result = std::shared_ptr<storm::models::symbolic::Mdp<DdType, ValueType>>(new storm::models::symbolic::Mdp<DdType, ValueType>(
1222 model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet,
1223 blockPrimeVariableSet, blockMetaVariablePairs, model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels));
1224 } else {
1225 result =
1226 std::shared_ptr<storm::models::symbolic::MarkovAutomaton<DdType, ValueType>>(new storm::models::symbolic::MarkovAutomaton<DdType, ValueType>(
1227 model.getManager().asSharedPointer(),
1228 model.template as<storm::models::symbolic::MarkovAutomaton<DdType, ValueType>>()->getMarkovianMarker(), reachableStates, initialStates,
1229 deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs,
1230 model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels));
1231 }
1232
1233 return result->template toValueType<ExportValueType>();
1234 } else {
1235 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Cannot extract quotient for this model type.");
1236 }
1237}
1238
1239template<storm::dd::DdType DdType, typename ValueType, typename ExportValueType>
1240std::shared_ptr<storm::models::symbolic::Model<DdType, ExportValueType>>
1241QuotientExtractor<DdType, ValueType, ExportValueType>::extractQuotientUsingOriginalVariables(
1242 storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition,
1243 PreservationInformation<DdType, ValueType> const& preservationInformation) {
1244 auto modelType = model.getType();
1245
1246 bool useRepresentativesForThisExtraction = this->useRepresentatives;
1247 if (modelType == storm::models::ModelType::Dtmc || modelType == storm::models::ModelType::Ctmc || modelType == storm::models::ModelType::Mdp ||
1249 STORM_LOG_WARN_COND(!this->useRepresentatives, "Using representatives is unsupported for this extraction, falling back to regular extraction.");
1250
1251 // Sanity checks.
1252 STORM_LOG_ASSERT(partition.getNumberOfStates() == model.getNumberOfStates(), "Mismatching partition size.");
1253 STORM_LOG_ASSERT(partition.getStates().renameVariables(model.getColumnVariables(), model.getRowVariables()) == model.getReachableStates(),
1254 "Mismatching partition.");
1255
1256 std::set<storm::expressions::Variable> blockVariableSet = {partition.getBlockVariable()};
1257 std::set<storm::expressions::Variable> blockPrimeVariableSet = {partition.getPrimedBlockVariable()};
1258 std::vector<std::pair<storm::expressions::Variable, storm::expressions::Variable>> blockMetaVariablePairs = {
1259 std::make_pair(partition.getBlockVariable(), partition.getPrimedBlockVariable())};
1260
1261 auto start = std::chrono::high_resolution_clock::now();
1262
1263 // Compute representatives.
1264 storm::dd::Bdd<DdType> partitionAsBdd = partition.storedAsBdd() ? partition.asBdd() : partition.asAdd().notZero();
1265 partitionAsBdd = partitionAsBdd.renameVariables(model.getColumnVariables(), model.getRowVariables());
1266 auto representatives = InternalRepresentativeComputer<DdType>(partitionAsBdd, model.getRowVariables()).getRepresentatives();
1267
1268 if (useRepresentativesForThisExtraction) {
1269 storm::dd::Bdd<DdType> partitionAsBddOverPrimedBlockVariables = partitionAsBdd.renameVariables(blockVariableSet, blockPrimeVariableSet);
1270 storm::dd::Bdd<DdType> tmp =
1271 (representatives && partitionAsBddOverPrimedBlockVariables).renameVariablesConcretize(model.getRowVariables(), blockVariableSet);
1272 partitionAsBdd = (tmp && partitionAsBddOverPrimedBlockVariables).existsAbstract(blockPrimeVariableSet);
1273 }
1274
1275 storm::dd::Bdd<DdType> reachableStates =
1276 partitionAsBdd.existsAbstract(model.getRowVariables()).renameVariablesAbstract(blockVariableSet, model.getRowVariables());
1277 storm::dd::Bdd<DdType> initialStates = (model.getInitialStates() && partitionAsBdd)
1279 .renameVariablesAbstract(blockVariableSet, model.getRowVariables());
1280
1281 std::map<std::string, storm::dd::Bdd<DdType>> preservedLabelBdds;
1282 for (auto const& label : preservationInformation.getLabels()) {
1283 preservedLabelBdds.emplace(label, (model.getStates(label) && partitionAsBdd)
1284 .existsAbstract(model.getRowVariables())
1285 .renameVariablesAbstract(blockVariableSet, model.getRowVariables()));
1286 }
1287 for (auto const& expression : preservationInformation.getExpressions()) {
1288 std::stringstream stream;
1289 stream << expression;
1290 std::string expressionAsString = stream.str();
1291
1292 auto it = preservedLabelBdds.find(expressionAsString);
1293 if (it != preservedLabelBdds.end()) {
1294 STORM_LOG_WARN("Duplicate label '" << expressionAsString << "', dropping second label definition.");
1295 } else {
1296 preservedLabelBdds.emplace(stream.str(), (model.getStates(expression) && partitionAsBdd)
1297 .existsAbstract(model.getRowVariables())
1298 .renameVariablesAbstract(blockVariableSet, model.getRowVariables()));
1299 }
1300 }
1301 auto end = std::chrono::high_resolution_clock::now();
1302 STORM_LOG_INFO("Quotient labels extracted in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
1303
1304 start = std::chrono::high_resolution_clock::now();
1305 std::set<storm::expressions::Variable> blockAndRowVariables;
1306 std::set_union(blockVariableSet.begin(), blockVariableSet.end(), model.getRowVariables().begin(), model.getRowVariables().end(),
1307 std::inserter(blockAndRowVariables, blockAndRowVariables.end()));
1308 std::set<storm::expressions::Variable> blockPrimeAndColumnVariables;
1309 std::set_union(blockPrimeVariableSet.begin(), blockPrimeVariableSet.end(), model.getColumnVariables().begin(), model.getColumnVariables().end(),
1310 std::inserter(blockPrimeAndColumnVariables, blockPrimeAndColumnVariables.end()));
1311 storm::dd::Add<DdType, ValueType> partitionAsAdd = partitionAsBdd.template toAdd<ValueType>();
1312 storm::dd::Add<DdType, ValueType> quotientTransitionMatrix =
1313 model.getTransitionMatrix()
1314 .multiplyMatrix(partitionAsAdd.renameVariables(model.getRowVariables(), model.getColumnVariables()), model.getColumnVariables())
1315 .renameVariablesAbstract(blockVariableSet, model.getColumnVariables());
1316
1317 // Pick a representative from each block.
1318 partitionAsBdd &= representatives;
1319 partitionAsAdd = partitionAsBdd.template toAdd<ValueType>();
1320
1321 // Workaround for problem with CUDD. Matrix-Matrix multiplication yields other result than multiplication+sum-abstract...
1323 quotientTransitionMatrix = (quotientTransitionMatrix * partitionAsAdd)
1324 .sumAbstract(model.getRowVariables())
1325 .renameVariablesAbstract(blockVariableSet, model.getRowVariables());
1326 } else {
1327 quotientTransitionMatrix = quotientTransitionMatrix.multiplyMatrix(partitionAsAdd, model.getRowVariables())
1328 .renameVariablesAbstract(blockVariableSet, model.getRowVariables());
1329 }
1330 end = std::chrono::high_resolution_clock::now();
1331
1332 // Check quotient matrix for sanity.
1333 if (std::is_same<ValueType, storm::RationalNumber>::value) {
1334 STORM_LOG_ASSERT(quotientTransitionMatrix.greater(storm::utility::one<ValueType>()).isZero(), "Illegal entries in quotient matrix.");
1335 } else {
1337 "Illegal entries in quotient matrix.");
1338 }
1339 STORM_LOG_ASSERT(quotientTransitionMatrix.sumAbstract(model.getColumnVariables())
1340 .equalModuloPrecision(quotientTransitionMatrix.notZero().existsAbstract(model.getColumnVariables()).template toAdd<ValueType>(),
1342 "Illegal probabilistic matrix.");
1343
1344 STORM_LOG_INFO("Quotient transition matrix extracted in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
1345
1346 storm::dd::Bdd<DdType> quotientTransitionMatrixBdd = quotientTransitionMatrix.notZero();
1347
1348 std::set<storm::expressions::Variable> columnAndNondeterminismVariables = model.getColumnVariables();
1349 columnAndNondeterminismVariables.insert(model.getNondeterminismVariables().begin(), model.getNondeterminismVariables().end());
1350 storm::dd::Bdd<DdType> deadlockStates = !quotientTransitionMatrixBdd.existsAbstract(columnAndNondeterminismVariables) && reachableStates;
1351
1352 start = std::chrono::high_resolution_clock::now();
1353 std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<DdType, ValueType>> quotientRewardModels;
1354 for (auto const& rewardModelName : preservationInformation.getRewardModelNames()) {
1355 auto const& rewardModel = model.getRewardModel(rewardModelName);
1356
1357 boost::optional<storm::dd::Add<DdType, ValueType>> quotientStateRewards;
1358 if (rewardModel.hasStateRewards()) {
1359 quotientStateRewards = rewardModel.getStateRewardVector()
1360 .multiplyMatrix(partitionAsAdd, model.getRowVariables())
1361 .renameVariablesAbstract(blockVariableSet, model.getRowVariables());
1362 }
1363
1364 boost::optional<storm::dd::Add<DdType, ValueType>> quotientStateActionRewards;
1365 if (rewardModel.hasStateActionRewards()) {
1366 quotientStateActionRewards = rewardModel.getStateActionRewardVector()
1367 .multiplyMatrix(partitionAsAdd, model.getRowVariables())
1368 .renameVariablesAbstract(blockVariableSet, model.getRowVariables());
1369 }
1370
1371 quotientRewardModels.emplace(rewardModelName, storm::models::symbolic::StandardRewardModel<DdType, ValueType>(
1372 quotientStateRewards, quotientStateActionRewards, boost::none));
1373 }
1374 end = std::chrono::high_resolution_clock::now();
1375 STORM_LOG_INFO("Reward models extracted in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
1376
1377 std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> result;
1378 if (modelType == storm::models::ModelType::Dtmc) {
1379 result = std::shared_ptr<storm::models::symbolic::Dtmc<DdType, ValueType>>(new storm::models::symbolic::Dtmc<DdType, ValueType>(
1380 model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(),
1381 model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), preservedLabelBdds, quotientRewardModels));
1382 } else if (modelType == storm::models::ModelType::Ctmc) {
1383 result = std::shared_ptr<storm::models::symbolic::Ctmc<DdType, ValueType>>(new storm::models::symbolic::Ctmc<DdType, ValueType>(
1384 model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(),
1385 model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), preservedLabelBdds, quotientRewardModels));
1386 } else if (modelType == storm::models::ModelType::Mdp) {
1387 result = std::shared_ptr<storm::models::symbolic::Mdp<DdType, ValueType>>(new storm::models::symbolic::Mdp<DdType, ValueType>(
1388 model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(),
1389 model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), model.getNondeterminismVariables(), preservedLabelBdds,
1390 quotientRewardModels));
1391 } else {
1392 result =
1393 std::shared_ptr<storm::models::symbolic::MarkovAutomaton<DdType, ValueType>>(new storm::models::symbolic::MarkovAutomaton<DdType, ValueType>(
1394 model.getManager().asSharedPointer(),
1395 model.template as<storm::models::symbolic::MarkovAutomaton<DdType, ValueType>>()->getMarkovianMarker(), reachableStates, initialStates,
1396 deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(),
1397 model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels));
1398 }
1399
1400 return result->template toValueType<ExportValueType>();
1401 } else {
1402 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Cannot extract quotient for this model type.");
1403 }
1404}
1405
1407
1412
1413} // namespace bisimulation
1414} // namespace dd
1415} // namespace storm
InternalAdd< LibraryType, ValueType > const & getInternalAdd() const
Retrieves the internal ADD.
Definition Add.cpp:1190
Bdd< LibraryType > greater(Add< LibraryType, ValueType > const &other) const
Retrieves the function that maps all evaluations to one whose function value in the first ADD are gre...
Definition Add.cpp:109
Add< LibraryType, ValueType > renameVariables(std::set< storm::expressions::Variable > const &from, std::set< storm::expressions::Variable > const &to) const
Renames the given meta variables in the ADD.
Definition Add.cpp:209
Add< LibraryType, ValueType > sumAbstract(std::set< storm::expressions::Variable > const &metaVariables) const
Sum-abstracts from the given meta variables.
Definition Add.cpp:171
Add< LibraryType, ValueType > multiplyMatrix(Add< LibraryType, ValueType > const &otherMatrix, std::set< storm::expressions::Variable > const &summationMetaVariables) const
Multiplies the current ADD (representing a matrix) with the given matrix by summing over the given me...
Definition Add.cpp:365
Bdd< LibraryType > toBdd() const
Converts the ADD to a BDD by mapping all values unequal to zero to 1.
Definition Add.cpp:1180
Bdd< LibraryType > notZero() const
Computes a BDD that represents the function in which all assignments with a function value unequal to...
Definition Add.cpp:424
Add< LibraryType, ValueType > renameVariablesAbstract(std::set< storm::expressions::Variable > const &from, std::set< storm::expressions::Variable > const &to) const
Renames the given meta variables in the ADD.
Definition Add.cpp:240
Bdd< LibraryType > existsAbstract(std::set< storm::expressions::Variable > const &metaVariables) const
Existentially abstracts from the given meta variables.
Definition Bdd.cpp:172
virtual uint_fast64_t getNonZeroCount() const override
Retrieves the number of encodings that are mapped to a non-zero value.
Definition Bdd.cpp:507
Bdd< LibraryType > swapVariables(std::vector< std::pair< storm::expressions::Variable, storm::expressions::Variable > > const &metaVariablePairs) const
Swaps the given pairs of meta variables in the BDD.
Definition Bdd.cpp:296
Bdd< LibraryType > renameVariables(std::set< storm::expressions::Variable > const &from, std::set< storm::expressions::Variable > const &to) const
Renames the given meta variables in the BDD.
Definition Bdd.cpp:341
InternalBdd< LibraryType > const & getInternalBdd() const
Retrieves the internal BDD.
Definition Bdd.cpp:570
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
bool isTerminalNode() const
Checks whether the given ODD node is a terminal node, i.e.
Definition Odd.cpp:71
Odd const & getElseSuccessor() const
Retrieves the else-successor of this ODD node.
Definition Odd.cpp:24
InternalRepresentativeComputer(storm::dd::Bdd< storm::dd::DdType::CUDD > const &partitionBdd, std::set< storm::expressions::Variable > const &rowVariables)
InternalRepresentativeComputer(storm::dd::Bdd< storm::dd::DdType::Sylvan > const &partitionBdd, std::set< storm::expressions::Variable > const &rowVariables)
std::set< storm::expressions::Variable > const & rowVariables
storm::dd::InternalDdManager< DdType > const * internalDdManager
InternalRepresentativeComputerBase(storm::dd::Bdd< DdType > const &partitionBdd, std::set< storm::expressions::Variable > const &rowVariables)
InternalSparseQuotientExtractor(storm::models::symbolic::Model< storm::dd::DdType::Sylvan, ValueType > const &model, storm::dd::Bdd< storm::dd::DdType::Sylvan > const &partitionBdd, storm::expressions::Variable const &blockVariable, uint64_t numberOfBlocks, storm::dd::Bdd< storm::dd::DdType::Sylvan > const &representatives)
InternalSparseQuotientExtractor(storm::models::symbolic::Model< storm::dd::DdType::CUDD, ValueType > const &model, storm::dd::Bdd< storm::dd::DdType::CUDD > const &partitionBdd, storm::expressions::Variable const &blockVariable, uint64_t numberOfBlocks, storm::dd::Bdd< storm::dd::DdType::CUDD > const &representatives)
virtual storm::storage::SparseMatrix< ExportValueType > extractMatrixInternal(storm::dd::Add< DdType, ValueType > const &matrix)=0
storm::models::symbolic::Model< DdType, ValueType > const & model
void addMatrixEntry(uint64_t row, uint64_t column, ExportValueType const &value)
InternalSparseQuotientExtractorBase(storm::models::symbolic::Model< DdType, ValueType > const &model, storm::dd::Bdd< DdType > const &partitionBdd, storm::expressions::Variable const &blockVariable, uint64_t numberOfBlocks, storm::dd::Bdd< DdType > const &representatives)
virtual std::vector< ExportValueType > extractVectorInternal(storm::dd::Add< DdType, ValueType > const &vector, storm::dd::Bdd< DdType > const &variablesCube, storm::dd::Odd const &odd)=0
storm::storage::SparseMatrix< ExportValueType > extractTransitionMatrix(storm::dd::Add< DdType, ValueType > const &transitionMatrix)
std::vector< ExportValueType > extractStateVector(storm::dd::Add< DdType, ValueType > const &vector)
storm::storage::SparseMatrix< ExportValueType > createMatrixFromEntries()
storm::storage::BitVector extractSetExists(storm::dd::Bdd< DdType > const &set)
storm::storage::BitVector extractSetAll(storm::dd::Bdd< DdType > const &set)
std::vector< ExportValueType > extractStateActionVector(storm::dd::Add< DdType, ValueType > const &vector)
std::vector< std::vector< storm::storage::MatrixEntry< uint_fast64_t, ExportValueType > > > matrixEntries
storm::expressions::Variable const & getBlockVariable() const
storm::dd::Bdd< DdType > const & asBdd() const
storm::dd::Bdd< DdType > getStates() const
storm::dd::Add< DdType, ValueType > const & asAdd() const
std::set< std::string > const & getLabels() const
std::set< std::string > const & getRewardModelNames() const
std::set< storm::expressions::Expression > const & getExpressions() const
std::shared_ptr< storm::models::Model< ExportValueType > > extract(storm::models::symbolic::Model< DdType, ValueType > const &model, Partition< DdType, ValueType > const &partition, PreservationInformation< DdType, ValueType > const &preservationInformation)
QuotientExtractor(storm::dd::bisimulation::QuotientFormat const &quotientFormat, BisimulationOptions const &bisimulationOptions)
virtual ModelType getType() const
Return the actual type of the model.
Definition ModelBase.cpp:7
This class manages the labeling of the state space with a number of (atomic) labels.
storm::dd::Bdd< Type > const & getMarkovianStates() const
storm::dd::Add< Type, ValueType > const & getExitRateVector() const
Base class for all symbolic models.
Definition Model.h:42
storm::dd::DdManager< Type > & getManager() const
Retrieves the manager responsible for the DDs that represent this model.
Definition Model.cpp:88
RewardModelType const & getRewardModel(std::string const &rewardModelName) const
Retrieves the reward model with the given name, if one exists.
Definition Model.cpp:245
storm::dd::Add< Type, ValueType > const & getTransitionMatrix() const
Retrieves the matrix representing the transitions of the model.
Definition Model.cpp:173
storm::dd::Bdd< Type > const & getDeadlockStates() const
Definition Model.cpp:108
std::set< storm::expressions::Variable > const & getColumnVariables() const
Retrieves the meta variables used to encode the columns of the transition matrix and the vector indic...
Definition Model.cpp:193
storm::dd::Bdd< Type > const & getInitialStates() const
Retrieves the initial states of the model.
Definition Model.cpp:103
virtual std::set< storm::expressions::Variable > const & getNondeterminismVariables() const
Retrieves all meta variables used to encode the nondeterminism.
Definition Model.cpp:214
std::vector< std::pair< storm::expressions::Variable, storm::expressions::Variable > > const & getRowColumnMetaVariablePairs() const
Retrieves the pairs of row and column meta variables.
Definition Model.cpp:219
std::set< storm::expressions::Variable > const & getRowVariables() const
Retrieves the meta variables used to encode the rows of the transition matrix and the vector indices.
Definition Model.cpp:188
virtual storm::dd::Bdd< Type > getStates(std::string const &label) const
Returns the sets of states labeled with the given label.
Definition Model.cpp:113
storm::dd::Bdd< Type > const & getReachableStates() const
Retrieves the reachable states of the model.
Definition Model.cpp:98
virtual uint_fast64_t getNumberOfStates() const override
Returns the number of states of the model.
Definition Model.cpp:73
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
A class that can be used to build a sparse matrix by adding value by value.
A class that holds a possibly non-square matrix in the compressed row storage format.
#define STORM_LOG_INFO(message)
Definition logging.h:27
#define STORM_LOG_WARN(message)
Definition logging.h:28
#define STORM_LOG_TRACE(message)
Definition logging.h:15
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:36
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:28
std::pair< storm::RationalNumber, storm::RationalNumber > count(std::vector< storm::storage::BitVector > const &origSets, std::vector< storm::storage::BitVector > const &intersects, std::vector< storm::storage::BitVector > const &intersectsInfo, storm::RationalNumber val, bool plus, uint64_t remdepth)
ValueType one()
Definition constants.cpp:19
TargetType convertNumber(SourceType const &number)