diff --git a/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp b/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp index c28b328e3..24b290168 100644 --- a/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp +++ b/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp @@ -33,25 +33,21 @@ namespace storm { namespace dd { namespace bisimulation { - template + template class InternalRepresentativeComputer; - template + template class InternalRepresentativeComputerBase { public: - InternalRepresentativeComputerBase(Partition const& partition, std::set const& rowVariables, std::set const& columnVariables) : partition(partition), rowVariables(rowVariables), columnVariables(columnVariables) { - if (partition.storedAsAdd()) { - ddManager = &partition.asAdd().getDdManager(); - } else { - ddManager = &partition.asBdd().getDdManager(); - } + InternalRepresentativeComputerBase(storm::dd::Bdd const& partitionBdd, std::set const& rowVariables) : rowVariables(rowVariables), partitionBdd(partitionBdd) { + ddManager = &partitionBdd.getDdManager(); internalDdManager = &ddManager->getInternalDdManager(); // Create state variables cube. - this->columnVariablesCube = ddManager->getBddOne(); - for (auto const& var : columnVariables) { + this->rowVariablesCube = ddManager->getBddOne(); + for (auto const& var : rowVariables) { auto const& metaVariable = ddManager->getMetaVariable(var); - this->columnVariablesCube &= metaVariable.getCube(); + this->rowVariablesCube &= metaVariable.getCube(); } } @@ -59,27 +55,27 @@ namespace storm { storm::dd::DdManager const* ddManager; storm::dd::InternalDdManager const* internalDdManager; - Partition const& partition; std::set const& rowVariables; - std::set const& columnVariables; - storm::dd::Bdd columnVariablesCube; + storm::dd::Bdd rowVariablesCube; + + storm::dd::Bdd partitionBdd; }; - template - class InternalRepresentativeComputer : public InternalRepresentativeComputerBase { + template <> + class InternalRepresentativeComputer : public InternalRepresentativeComputerBase { public: - InternalRepresentativeComputer(Partition const& partition, std::set const& rowVariables, std::set const& columnVariables) : InternalRepresentativeComputerBase(partition, rowVariables, columnVariables) { + InternalRepresentativeComputer(storm::dd::Bdd const& partitionBdd, std::set const& rowVariables) : InternalRepresentativeComputerBase(partitionBdd, rowVariables) { this->ddman = this->internalDdManager->getCuddManager().getManager(); } storm::dd::Bdd getRepresentatives() { - return storm::dd::Bdd(*this->ddManager, storm::dd::InternalBdd(this->internalDdManager, cudd::BDD(this->internalDdManager->getCuddManager(), this->getRepresentativesRec(this->partition.asAdd().getInternalAdd().getCuddDdNode(), this->columnVariablesCube.getInternalBdd().getCuddDdNode()))), this->rowVariables); + return storm::dd::Bdd(*this->ddManager, storm::dd::InternalBdd(this->internalDdManager, cudd::BDD(this->internalDdManager->getCuddManager(), this->getRepresentativesRec(this->partitionBdd.getInternalBdd().getCuddDdNode(), this->rowVariablesCube.getInternalBdd().getCuddDdNode()))), this->rowVariables); } private: DdNodePtr getRepresentativesRec(DdNodePtr partitionNode, DdNodePtr stateVariablesCube) { - if (partitionNode == Cudd_ReadZero(ddman)) { - return Cudd_ReadLogicZero(ddman); + if (partitionNode == Cudd_ReadLogicZero(ddman)) { + return partitionNode; } // If we visited the node before, there is no block that we still need to cover. @@ -98,6 +94,11 @@ namespace storm { if (Cudd_NodeReadIndex(partitionNode) == Cudd_NodeReadIndex(stateVariablesCube)) { elsePartitionNode = Cudd_E(partitionNode); thenPartitionNode = Cudd_T(partitionNode); + + if (Cudd_IsComplement(partitionNode)) { + elsePartitionNode = Cudd_Not(elsePartitionNode); + thenPartitionNode = Cudd_Not(thenPartitionNode); + } } else { elsePartitionNode = thenPartitionNode = partitionNode; skipped = true; @@ -122,7 +123,7 @@ namespace storm { return elseResult; } else { bool complement = Cudd_IsComplement(thenResult); - auto result = cuddUniqueInter(ddman, Cudd_NodeReadIndex(stateVariablesCube) - 1, Cudd_Regular(thenResult), complement ? Cudd_Not(elseResult) : elseResult); + auto result = cuddUniqueInter(ddman, Cudd_NodeReadIndex(stateVariablesCube), Cudd_Regular(thenResult), complement ? Cudd_Not(elseResult) : elseResult); Cudd_Deref(elseResult); Cudd_Deref(thenResult); return complement ? Cudd_Not(result) : result; @@ -132,7 +133,7 @@ namespace storm { if (elseResult == Cudd_ReadLogicZero(ddman)) { result = elseResult; } else { - result = Cudd_Not(cuddUniqueInter(ddman, Cudd_NodeReadIndex(stateVariablesCube) - 1, Cudd_ReadOne(ddman), Cudd_Not(elseResult))); + result = Cudd_Not(cuddUniqueInter(ddman, Cudd_NodeReadIndex(stateVariablesCube), Cudd_ReadOne(ddman), Cudd_Not(elseResult))); } Cudd_Deref(elseResult); return result; @@ -144,15 +145,15 @@ namespace storm { spp::sparse_hash_map visitedNodes; }; - template - class InternalRepresentativeComputer : public InternalRepresentativeComputerBase { + template<> + class InternalRepresentativeComputer : public InternalRepresentativeComputerBase { public: - InternalRepresentativeComputer(Partition const& partition, std::set const& rowVariables, std::set const& columnVariables) : InternalRepresentativeComputerBase(partition, rowVariables, columnVariables) { + InternalRepresentativeComputer(storm::dd::Bdd const& partitionBdd, std::set const& rowVariables) : InternalRepresentativeComputerBase(partitionBdd, rowVariables) { // Intentionally left empty. } storm::dd::Bdd getRepresentatives() { - return storm::dd::Bdd(*this->ddManager, storm::dd::InternalBdd(this->internalDdManager, sylvan::Bdd(this->getRepresentativesRec(this->partition.asBdd().getInternalBdd().getSylvanBdd().GetBDD(), this->columnVariablesCube.getInternalBdd().getSylvanBdd().GetBDD()))), this->rowVariables); + return storm::dd::Bdd(*this->ddManager, storm::dd::InternalBdd(this->internalDdManager, sylvan::Bdd(this->getRepresentativesRec(this->partitionBdd.getInternalBdd().getSylvanBdd().GetBDD(), this->rowVariablesCube.getInternalBdd().getSylvanBdd().GetBDD()))), this->rowVariables); } private: @@ -199,7 +200,7 @@ namespace storm { mtbdd_refs_pop(2); return elseResult; } else { - auto result = sylvan_makenode(sylvan_var(stateVariablesCube) - 1, elseResult, thenResult); + auto result = sylvan_makenode(sylvan_var(stateVariablesCube), elseResult, thenResult); mtbdd_refs_pop(2); return result; } @@ -208,7 +209,7 @@ namespace storm { if (elseResult == sylvan_false) { result = elseResult; } else { - result = sylvan_makenode(sylvan_var(stateVariablesCube) - 1, elseResult, sylvan_false); + result = sylvan_makenode(sylvan_var(stateVariablesCube), elseResult, sylvan_false); } mtbdd_refs_pop(1); return result; @@ -718,8 +719,8 @@ namespace storm { partitionAsBdd = partitionAsBdd.renameVariables(model.getColumnVariables(), model.getRowVariables()); auto start = std::chrono::high_resolution_clock::now(); - // FIXME: Use partition as BDD in representative computation. - auto representatives = InternalRepresentativeComputer(partition, model.getRowVariables(), model.getColumnVariables()).getRepresentatives(); + auto representatives = InternalRepresentativeComputer(partitionAsBdd, model.getRowVariables()).getRepresentatives(); + representatives.template toAdd().exportToDot("repr.dot"); STORM_LOG_ASSERT(representatives.getNonZeroCount() == partition.getNumberOfBlocks(), "Representatives size does not match that of the partition: " << representatives.getNonZeroCount() << " vs. " << partition.getNumberOfBlocks() << "."); STORM_LOG_ASSERT((representatives && partitionAsBdd).existsAbstract(model.getRowVariables()) == partitionAsBdd.existsAbstract(model.getRowVariables()), "Representatives do not cover all blocks."); InternalSparseQuotientExtractor sparseExtractor(model, partition, representatives); @@ -795,13 +796,13 @@ namespace storm { } auto start = std::chrono::high_resolution_clock::now(); - storm::dd::Bdd partitionAsBddOverRowVariables = partitionAsBdd.renameVariables(model.getColumnVariables(), model.getRowVariables()); - storm::dd::Bdd reachableStates = partitionAsBdd.existsAbstract(model.getColumnVariables()); - storm::dd::Bdd initialStates = (model.getInitialStates() && partitionAsBddOverRowVariables).existsAbstract(model.getRowVariables()); + partitionAsBdd = partitionAsBdd.renameVariables(model.getColumnVariables(), model.getRowVariables()); + storm::dd::Bdd reachableStates = partitionAsBdd.existsAbstract(model.getRowVariables()); + storm::dd::Bdd initialStates = (model.getInitialStates() && partitionAsBdd).existsAbstract(model.getRowVariables()); std::map> preservedLabelBdds; for (auto const& label : preservationInformation.getLabels()) { - preservedLabelBdds.emplace(label, (model.getStates(label) && partitionAsBddOverRowVariables).existsAbstract(model.getRowVariables())); + preservedLabelBdds.emplace(label, (model.getStates(label) && partitionAsBdd).existsAbstract(model.getRowVariables())); } for (auto const& expression : preservationInformation.getExpressions()) { std::stringstream stream; @@ -812,18 +813,18 @@ namespace storm { if (it != preservedLabelBdds.end()) { STORM_LOG_WARN("Duplicate label '" << expressionAsString << "', dropping second label definition."); } else { - preservedLabelBdds.emplace(stream.str(), (model.getStates(expression) && partitionAsBddOverRowVariables).existsAbstract(model.getRowVariables())); + preservedLabelBdds.emplace(stream.str(), (model.getStates(expression) && partitionAsBdd).existsAbstract(model.getRowVariables())); } } auto end = std::chrono::high_resolution_clock::now(); STORM_LOG_TRACE("Quotient labels extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); start = std::chrono::high_resolution_clock::now(); - storm::dd::Add quotientTransitionMatrix = model.getTransitionMatrix().multiplyMatrix(partitionAsBdd.renameVariables(blockVariableSet, blockPrimeVariableSet), model.getColumnVariables()); + storm::dd::Add quotientTransitionMatrix = model.getTransitionMatrix().multiplyMatrix(partitionAsBdd.renameVariables(blockVariableSet, blockPrimeVariableSet).renameVariables(model.getRowVariables(), model.getColumnVariables()), model.getColumnVariables()); // Pick a representative from each block. - auto representatives = InternalRepresentativeComputer(partition, model.getRowVariables(), model.getColumnVariables()).getRepresentatives(); - partitionAsBdd = representatives && partitionAsBdd.renameVariables(model.getColumnVariables(), model.getRowVariables()); + auto representatives = InternalRepresentativeComputer(partitionAsBdd, model.getRowVariables()).getRepresentatives(); + partitionAsBdd &= representatives; storm::dd::Add partitionAsAdd = partitionAsBdd.template toAdd(); quotientTransitionMatrix = quotientTransitionMatrix.multiplyMatrix(partitionAsAdd, model.getRowVariables());