#include "storm/storage/dd/bisimulation/Partition.h" #include "storm/storage/dd/DdManager.h" #include "storm/storage/dd/bisimulation/PreservationInformation.h" #include "storm/logic/Formula.h" #include "storm/logic/AtomicExpressionFormula.h" #include "storm/logic/AtomicLabelFormula.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/BisimulationSettings.h" #include "storm/utility/macros.h" #include "storm/exceptions/NotSupportedException.h" #include "storm/exceptions/InvalidPropertyException.h" namespace storm { namespace dd { namespace bisimulation { template Partition::Partition(storm::dd::Add const& partitionAdd, std::pair const& blockVariables, uint64_t nextFreeBlockIndex) : partition(partitionAdd), blockVariables(blockVariables), nextFreeBlockIndex(nextFreeBlockIndex) { // Intentionally left empty. } template Partition::Partition(storm::dd::Bdd const& partitionBdd, std::pair const& blockVariables, uint64_t nextFreeBlockIndex) : partition(partitionBdd), blockVariables(blockVariables), nextFreeBlockIndex(nextFreeBlockIndex) { // Intentionally left empty. } template bool Partition::operator==(Partition const& other) { return this->partition == other.partition && this->blockVariables == other.blockVariables && this->nextFreeBlockIndex == other.nextFreeBlockIndex; } template Partition Partition::replacePartition(storm::dd::Add const& newPartitionAdd, uint64_t nextFreeBlockIndex) const { return Partition(newPartitionAdd, blockVariables, nextFreeBlockIndex); } template Partition Partition::replacePartition(storm::dd::Bdd const& newPartitionBdd, uint64_t nextFreeBlockIndex) const { return Partition(newPartitionBdd, blockVariables, nextFreeBlockIndex); } template Partition Partition::create(storm::models::symbolic::Model const& model, storm::storage::BisimulationType const& bisimulationType, PreservationInformation const& preservationInformation) { std::vector expressionVector; for (auto const& expression : preservationInformation.getExpressions()) { expressionVector.emplace_back(expression); } return create(model, expressionVector, bisimulationType); } template Partition Partition::create(storm::models::symbolic::Model const& model, std::vector const& expressions, storm::storage::BisimulationType const& bisimulationType) { STORM_LOG_THROW(bisimulationType == storm::storage::BisimulationType::Strong, storm::exceptions::NotSupportedException, "Currently only strong bisimulation is supported."); storm::dd::DdManager& manager = model.getManager(); std::vector> stateSets; for (auto const& expression : expressions) { stateSets.emplace_back(model.getStates(expression)); } uint64_t numberOfDdVariables = 0; for (auto const& metaVariable : model.getRowVariables()) { auto const& ddMetaVariable = manager.getMetaVariable(metaVariable); numberOfDdVariables += ddMetaVariable.getNumberOfDdVariables(); } std::pair blockVariables = createBlockVariables(manager, numberOfDdVariables); std::pair, uint64_t> partitionBddAndBlockCount = createPartitionBdd(manager, model, stateSets, blockVariables.first); // Store the partition as an ADD only in the case of CUDD. if (DdType == storm::dd::DdType::CUDD) { return Partition(partitionBddAndBlockCount.first.template toAdd(), blockVariables, partitionBddAndBlockCount.second); } else { return Partition(partitionBddAndBlockCount.first, blockVariables, partitionBddAndBlockCount.second); } } template uint64_t Partition::getNumberOfStates() const { return this->getStates().getNonZeroCount(); } template storm::dd::Bdd Partition::getStates() const { if (this->storedAsAdd()) { return this->asAdd().notZero().existsAbstract({this->getBlockVariable()}); } else { return this->asBdd().existsAbstract({this->getBlockVariable()}); } } template uint64_t Partition::getNumberOfBlocks() const { return nextFreeBlockIndex; } template bool Partition::storedAsAdd() const { return partition.which() == 1; } template bool Partition::storedAsBdd() const { return partition.which() == 0; } template storm::dd::Add const& Partition::asAdd() const { return boost::get>(partition); } template storm::dd::Bdd const& Partition::asBdd() const { return boost::get>(partition); } template storm::expressions::Variable const& Partition::getBlockVariable() const { return blockVariables.first; } template storm::expressions::Variable const& Partition::getPrimedBlockVariable() const { return blockVariables.second; } template uint64_t Partition::getNextFreeBlockIndex() const { return nextFreeBlockIndex; } template uint64_t Partition::getNodeCount() const { if (this->storedAsBdd()) { return asBdd().getNodeCount(); } else { return asAdd().getNodeCount(); } } template PreservationInformation const& Partition::getPreservationInformation() const { return *preservationInformation; } template void enumerateBlocksRec(std::vector> const& stateSets, storm::dd::Bdd const& currentStateSet, uint64_t offset, storm::expressions::Variable const& blockVariable, std::function const&)> const& callback) { if (currentStateSet.isZero()) { return; } if (offset == stateSets.size()) { callback(currentStateSet); } else { enumerateBlocksRec(stateSets, currentStateSet && stateSets[offset], offset + 1, blockVariable, callback); enumerateBlocksRec(stateSets, currentStateSet && !stateSets[offset], offset + 1, blockVariable, callback); } } template std::pair, uint64_t> Partition::createPartitionBdd(storm::dd::DdManager const& manager, storm::models::symbolic::Model const& model, std::vector> const& stateSets, storm::expressions::Variable const& blockVariable) { uint64_t blockCount = 0; storm::dd::Bdd partitionBdd = manager.getBddZero(); // Enumerate all realizable blocks. enumerateBlocksRec(stateSets, model.getReachableStates(), 0, blockVariable, [&manager, &partitionBdd, &blockVariable, &blockCount](storm::dd::Bdd const& stateSet) { partitionBdd |= (stateSet && manager.getEncoding(blockVariable, blockCount, false)); blockCount++; } ); // Move the partition over to the primed variables. partitionBdd = partitionBdd.swapVariables(model.getRowColumnMetaVariablePairs()); return std::make_pair(partitionBdd, blockCount); } template std::pair Partition::createBlockVariables(storm::dd::DdManager& manager, uint64_t numberOfDdVariables) { std::vector blockVariables; if (manager.hasMetaVariable("blocks")) { int64_t counter = 0; while (manager.hasMetaVariable("block" + std::to_string(counter))) { ++counter; } blockVariables = manager.addBitVectorMetaVariable("blocks" + std::to_string(counter), numberOfDdVariables, 2); } else { blockVariables = manager.addBitVectorMetaVariable("blocks", numberOfDdVariables, 2); } return std::make_pair(blockVariables[0], blockVariables[1]); } template class Partition; template class Partition; template class Partition; template class Partition; } } }