#include "storm/abstraction/AbstractionInformation.h" #include "storm/storage/BitVector.h" #include "storm/storage/dd/DdManager.h" #include "storm/utility/macros.h" #include "storm/exceptions/InvalidOperationException.h" #include "storm/storage/expressions/Expression.h" #include "storm/storage/expressions/ExpressionManager.h" namespace storm { namespace abstraction { template AbstractionInformation::AbstractionInformation(storm::expressions::ExpressionManager& expressionManager, std::unique_ptr&& smtSolver, std::shared_ptr> ddManager) : expressionManager(expressionManager), equivalenceChecker(std::move(smtSolver)), ddManager(ddManager), allPredicateIdentities(ddManager->getBddOne()) { // Intentionally left empty. } template void AbstractionInformation::addExpressionVariable(storm::expressions::Variable const& variable) { variables.insert(variable); } template void AbstractionInformation::addExpressionVariable(storm::expressions::Variable const& variable, storm::expressions::Expression const& constraint) { addExpressionVariable(variable); addConstraint(constraint); } template std::set AbstractionInformation::getExpressionVariables() const { return variables; } template void AbstractionInformation::addConstraint(storm::expressions::Expression const& constraint) { constraints.push_back(constraint); } template uint_fast64_t AbstractionInformation::getOrAddPredicate(storm::expressions::Expression const& predicate) { // Check if we already have an equivalent predicate. for (uint64_t index = 0; index < predicates.size(); ++index) { auto const& oldPredicate = predicates[index]; if (equivalenceChecker.areEquivalent(oldPredicate, predicate)) { return index; } } std::size_t predicateIndex = predicates.size(); predicateToIndexMap[predicate] = predicateIndex; // Add the new predicate to the list of known predicates. predicates.push_back(predicate); // Add DD variables for the new predicate. std::stringstream stream; stream << predicate; std::pair newMetaVariable = ddManager->addMetaVariable(stream.str()); predicateDdVariables.push_back(newMetaVariable); extendedPredicateDdVariables.push_back(newMetaVariable); predicateBdds.emplace_back(ddManager->getEncoding(newMetaVariable.first, 1), ddManager->getEncoding(newMetaVariable.second, 1)); predicateIdentities.push_back(ddManager->getEncoding(newMetaVariable.first, 1).iff(ddManager->getEncoding(newMetaVariable.second, 1))); allPredicateIdentities &= predicateIdentities.back(); sourceVariables.insert(newMetaVariable.first); successorVariables.insert(newMetaVariable.second); orderedSuccessorVariables.push_back(newMetaVariable.second); ddVariableIndexToPredicateIndexMap[predicateIdentities.back().getIndex()] = predicateIndex; return predicateIndex; } template std::vector AbstractionInformation::addPredicates(std::vector const& predicates) { std::vector predicateIndices; for (auto const& predicate : predicates) { predicateIndices.push_back(this->getOrAddPredicate(predicate)); } return predicateIndices; } template std::vector const& AbstractionInformation::getConstraints() const { return constraints; } template storm::expressions::ExpressionManager& AbstractionInformation::getExpressionManager() { return expressionManager.get(); } template storm::expressions::ExpressionManager const& AbstractionInformation::getExpressionManager() const { return expressionManager.get(); } template storm::dd::DdManager& AbstractionInformation::getDdManager() { return *ddManager; } template storm::dd::DdManager const& AbstractionInformation::getDdManager() const { return *ddManager; } template std::shared_ptr> AbstractionInformation::getDdManagerAsSharedPointer() { return ddManager; } template std::shared_ptr const> AbstractionInformation::getDdManagerAsSharedPointer() const { return ddManager; } template std::vector const& AbstractionInformation::getPredicates() const { return predicates; } template storm::expressions::Expression const& AbstractionInformation::getPredicateByIndex(uint_fast64_t index) const { return predicates[index]; } template storm::dd::Bdd AbstractionInformation::getPredicateSourceVariable(storm::expressions::Expression const& predicate) const { auto indexIt = predicateToIndexMap.find(predicate); STORM_LOG_THROW(indexIt != predicateToIndexMap.end(), storm::exceptions::InvalidOperationException, "Cannot retrieve BDD for unknown predicate."); return predicateBdds[indexIt->second].first; } template bool AbstractionInformation::hasPredicate(storm::expressions::Expression const& predicate) const { return predicateToIndexMap.find(predicate) != predicateToIndexMap.end(); } template std::size_t AbstractionInformation::getNumberOfPredicates() const { return predicates.size(); } template std::set const& AbstractionInformation::getVariables() const { return variables; } template void AbstractionInformation::createEncodingVariables(uint64_t player1VariableCount, uint64_t player2VariableCount, uint64_t auxVariableCount) { STORM_LOG_THROW(player1Variables.empty() && player2Variables.empty() && auxVariables.empty(), storm::exceptions::InvalidOperationException, "Variables have already been created."); for (uint64_t index = 0; index < player1VariableCount; ++index) { storm::expressions::Variable newVariable = ddManager->addMetaVariable("pl1." + std::to_string(index)).first; player1Variables.push_back(newVariable); player1VariableBdds.push_back(ddManager->getEncoding(newVariable, 1)); } STORM_LOG_DEBUG("Created " << player1VariableCount << " player 1 variables."); for (uint64_t index = 0; index < player2VariableCount; ++index) { storm::expressions::Variable newVariable = ddManager->addMetaVariable("pl2." + std::to_string(index)).first; player2Variables.push_back(newVariable); player2VariableBdds.push_back(ddManager->getEncoding(newVariable, 1)); } STORM_LOG_DEBUG("Created " << player2VariableCount << " player 2 variables."); for (uint64_t index = 0; index < auxVariableCount; ++index) { storm::expressions::Variable newVariable = ddManager->addMetaVariable("aux_" + std::to_string(index)).first; auxVariables.push_back(newVariable); auxVariableBdds.push_back(ddManager->getEncoding(newVariable, 1)); } STORM_LOG_DEBUG("Created " << auxVariableCount << " auxiliary variables."); bottomStateVariables = ddManager->addMetaVariable("bot"); bottomStateBdds = std::make_pair(ddManager->getEncoding(bottomStateVariables.first, 1), ddManager->getEncoding(bottomStateVariables.second, 1)); extendedPredicateDdVariables.push_back(bottomStateVariables); } template storm::dd::Bdd AbstractionInformation::encodePlayer1Choice(uint_fast64_t index, uint_fast64_t end) const { return encodeChoice(index, 0, end, player1VariableBdds); } template uint_fast64_t AbstractionInformation::decodePlayer1Choice(storm::expressions::Valuation const& valuation, uint_fast64_t end) const { return decodeChoice(valuation, 0, end, player1Variables); } template storm::dd::Bdd AbstractionInformation::encodePlayer2Choice(uint_fast64_t index, uint_fast64_t end) const { return encodeChoice(index, 0, end, player2VariableBdds); } template uint_fast64_t AbstractionInformation::decodePlayer2Choice(storm::expressions::Valuation const& valuation, uint_fast64_t end) const { return decodeChoice(valuation, 0, end, player2Variables); } template storm::dd::Bdd AbstractionInformation::encodeAux(uint_fast64_t index, uint_fast64_t start, uint_fast64_t end) const { return encodeChoice(index, start, end, auxVariableBdds); } template uint_fast64_t AbstractionInformation::decodeAux(storm::expressions::Valuation const& valuation, uint_fast64_t start, uint_fast64_t end) const { return decodeChoice(valuation, start, end, auxVariables); } template storm::dd::Bdd AbstractionInformation::getPlayer2ZeroCube(uint_fast64_t start, uint_fast64_t end) const { storm::dd::Bdd result = ddManager->getBddOne(); for (uint_fast64_t index = start; index < end; ++index) { result &= !player2VariableBdds[index]; } STORM_LOG_ASSERT(!result.isZero(), "Zero cube must not be zero."); return result; } template std::vector const& AbstractionInformation::getPlayer1Variables() const { return player1Variables; } template std::set AbstractionInformation::getPlayer1VariableSet(uint_fast64_t count) const { return std::set(player1Variables.begin(), player1Variables.begin() + count); } template std::vector const& AbstractionInformation::getPlayer2Variables() const { return player2Variables; } template std::set AbstractionInformation::getPlayer2VariableSet(uint_fast64_t count) const { return std::set(player2Variables.begin(), player2Variables.begin() + count); } template std::vector const& AbstractionInformation::getAuxVariables() const { return auxVariables; } template storm::expressions::Variable const& AbstractionInformation::getAuxVariable(uint_fast64_t index) const { return auxVariables[index]; } template std::set AbstractionInformation::getAuxVariableSet(uint_fast64_t start, uint_fast64_t end) const { return std::set(auxVariables.begin() + start, auxVariables.begin() + end); } template std::set const& AbstractionInformation::getSourceVariables() const { return sourceVariables; } template std::set const& AbstractionInformation::getSuccessorVariables() const { return successorVariables; } template std::vector const& AbstractionInformation::getOrderedSuccessorVariables() const { return orderedSuccessorVariables; } template storm::dd::Bdd const& AbstractionInformation::getAllPredicateIdentities() const { return allPredicateIdentities; } template std::size_t AbstractionInformation::getPlayer1VariableCount() const { return player1Variables.size(); } template std::size_t AbstractionInformation::getPlayer2VariableCount() const { return player2Variables.size(); } template std::size_t AbstractionInformation::getAuxVariableCount() const { return auxVariables.size(); } template std::map> AbstractionInformation::getPredicateToBddMap() const { std::map> result; for (uint_fast64_t index = 0; index < predicates.size(); ++index) { result[predicates[index]] = predicateBdds[index].first && !bottomStateBdds.first; } return result; } template std::vector> const& AbstractionInformation::getSourceSuccessorVariablePairs() const { return predicateDdVariables; } template std::vector> const& AbstractionInformation::getExtendedSourceSuccessorVariablePairs() const { return extendedPredicateDdVariables; } template storm::expressions::Variable const& AbstractionInformation::getBottomStateVariable(bool source) const { if (source) { return bottomStateVariables.first; } else { return bottomStateVariables.second; } } template storm::dd::Bdd AbstractionInformation::getBottomStateBdd(bool source, bool negated) const { if (source) { if (negated) { return !bottomStateBdds.first; } else { return bottomStateBdds.first; } } else { if (negated) { return !bottomStateBdds.second; } else { return bottomStateBdds.second; } } } template storm::dd::Bdd const& AbstractionInformation::encodePredicateAsSource(uint_fast64_t predicateIndex) const { return predicateBdds[predicateIndex].first; } template storm::dd::Bdd const& AbstractionInformation::encodePredicateAsSuccessor(uint_fast64_t predicateIndex) const { return predicateBdds[predicateIndex].second; } template storm::dd::Bdd const& AbstractionInformation::getPredicateIdentity(uint_fast64_t predicateIndex) const { return predicateIdentities[predicateIndex]; } template storm::expressions::Expression const& AbstractionInformation::getPredicateForDdVariableIndex(uint_fast64_t ddVariableIndex) const { auto indexIt = ddVariableIndexToPredicateIndexMap.find(ddVariableIndex); STORM_LOG_THROW(indexIt != ddVariableIndexToPredicateIndexMap.end(), storm::exceptions::InvalidOperationException, "Unknown DD variable index."); return predicates[indexIt->second]; } template std::vector> AbstractionInformation::declareNewVariables(std::vector> const& oldPredicates, std::set const& newPredicates) const { std::vector> result; auto oldIt = oldPredicates.begin(); auto oldIte = oldPredicates.end(); auto newIt = newPredicates.begin(); auto newIte = newPredicates.end(); for (; newIt != newIte; ++newIt) { if (oldIt == oldIte || oldIt->second != *newIt) { result.push_back(std::make_pair(expressionManager.get().declareFreshBooleanVariable(), *newIt)); } else { ++oldIt; } } return result; } template storm::dd::Bdd AbstractionInformation::encodeChoice(uint_fast64_t index, uint_fast64_t start, uint_fast64_t end, std::vector> const& variables) const { storm::dd::Bdd result = ddManager->getBddOne(); for (uint_fast64_t bitIndex = end; bitIndex > start; --bitIndex) { if ((index & 1) != 0) { result &= variables[bitIndex - 1]; } else { result &= !variables[bitIndex - 1]; } index >>= 1; } STORM_LOG_ASSERT(!result.isZero(), "BDD encoding must not be zero."); return result; } template uint_fast64_t AbstractionInformation::decodeChoice(storm::expressions::Valuation const& valuation, uint_fast64_t start, uint_fast64_t end, std::vector const& variables) const { uint_fast64_t result = 0; for (uint_fast64_t variableIndex = start; variableIndex < end; ++variableIndex) { result <<= 1; if (valuation.getBooleanValue(variables[variableIndex])) { result |= 1; } } return result; } template std::map AbstractionInformation::decodeChoiceToUpdateSuccessorMapping(storm::dd::Bdd const& choice) const { std::map result; storm::dd::Add lowerChoiceAsAdd = choice.template toAdd(); for (auto const& successorValuePair : lowerChoiceAsAdd) { uint_fast64_t updateIndex = this->decodeAux(successorValuePair.first, 0, this->getAuxVariableCount()); #ifdef LOCAL_DEBUG std::cout << "update idx: " << updateIndex << std::endl; #endif storm::storage::BitVector successor(this->getNumberOfPredicates()); for (uint_fast64_t index = 0; index < this->getOrderedSuccessorVariables().size(); ++index) { auto const& successorVariable = this->getOrderedSuccessorVariables()[index]; #ifdef LOCAL_DEBUG std::cout << successorVariable.getName() << " has value"; #endif if (successorValuePair.first.getBooleanValue(successorVariable)) { successor.set(index); #ifdef LOCAL_DEBUG std::cout << " true"; #endif } else { #ifdef LOCAL_DEBUG std::cout << " false"; #endif } #ifdef LOCAL_DEBUG std::cout << std::endl; #endif } result[updateIndex] = successor; } return result; } template class AbstractionInformation; template class AbstractionInformation; } }