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