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