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