#include "src/storage/dd/DdManager.h" #include "src/storage/expressions/ExpressionManager.h" #include "src/utility/macros.h" #include "src/exceptions/InvalidArgumentException.h" namespace storm { namespace dd { template DdManager::DdManager() : internalDdManager(), metaVariableMap(), manager(new storm::expressions::ExpressionManager()) { // Intentionally left empty. } template Bdd DdManager::getBddOne() const { return Bdd(*this, internalDdManager.getBddOne()); } template template Add DdManager::getAddOne() const { return Add(*this, internalDdManager.template getAddOne()); } template Bdd DdManager::getBddZero() const { return Bdd(*this, internalDdManager.getBddZero()); } template template Add DdManager::getAddZero() const { return Add(*this, internalDdManager.template getAddZero()); } template template Add DdManager::getConstant(ValueType const& value) const { return Add(*this, internalDdManager.getConstant(value)); } template Bdd DdManager::getEncoding(storm::expressions::Variable const& variable, int_fast64_t value) const { DdMetaVariable const& metaVariable = this->getMetaVariable(variable); STORM_LOG_THROW(value >= metaVariable.getLow() && value <= metaVariable.getHigh(), storm::exceptions::InvalidArgumentException, "Illegal value " << value << " for meta variable '" << variable.getName() << "'."); // Now compute the encoding relative to the low value of the meta variable. value -= metaVariable.getLow(); std::vector> const& ddVariables = metaVariable.getDdVariables(); Bdd result; if (value & (1ull << (ddVariables.size() - 1))) { result = ddVariables[0]; } else { result = !ddVariables[0]; } for (std::size_t i = 1; i < ddVariables.size(); ++i) { if (value & (1ull << (ddVariables.size() - i - 1))) { result &= ddVariables[i]; } else { result &= !ddVariables[i]; } } return result; } template Bdd DdManager::getRange(storm::expressions::Variable const& variable) const { storm::dd::DdMetaVariable const& metaVariable = this->getMetaVariable(variable); Bdd result = this->getBddZero(); for (int_fast64_t value = metaVariable.getLow(); value <= metaVariable.getHigh(); ++value) { result |= this->getEncoding(variable, value); } return result; } template template Add DdManager::getIdentity(storm::expressions::Variable const& variable) const { storm::dd::DdMetaVariable const& metaVariable = this->getMetaVariable(variable); Add result = this->getAddZero(); for (int_fast64_t value = metaVariable.getLow(); value <= metaVariable.getHigh(); ++value) { result += this->getEncoding(variable, value).template toAdd() * this->getConstant(static_cast(value)); } return result; } template std::pair DdManager::addMetaVariable(std::string const& name, int_fast64_t low, int_fast64_t high) { // Check whether the variable name is legal. STORM_LOG_THROW(name != "" && name.back() != '\'', storm::exceptions::InvalidArgumentException, "Illegal name of meta variable: '" << name << "'."); // Check whether a meta variable already exists. STORM_LOG_THROW(!this->hasMetaVariable(name), storm::exceptions::InvalidArgumentException, "A meta variable '" << name << "' already exists."); // Check that the range is legal. STORM_LOG_THROW(high != low, storm::exceptions::InvalidArgumentException, "Range of meta variable must be at least 2 elements."); std::size_t numberOfBits = static_cast(std::ceil(std::log2(high - low + 1))); storm::expressions::Variable unprimed = manager->declareBitVectorVariable(name, numberOfBits); storm::expressions::Variable primed = manager->declareBitVectorVariable(name + "'", numberOfBits); std::vector> variables; std::vector> variablesPrime; for (std::size_t i = 0; i < numberOfBits; ++i) { auto ddVariablePair = internalDdManager.createNewDdVariablePair(); variables.emplace_back(Bdd(*this, ddVariablePair.first, {unprimed})); variablesPrime.emplace_back(Bdd(*this, ddVariablePair.second, {primed})); } metaVariableMap.emplace(unprimed, DdMetaVariable(name, low, high, variables)); metaVariableMap.emplace(primed, DdMetaVariable(name + "'", low, high, variablesPrime)); return std::make_pair(unprimed, primed); } template std::pair DdManager::addMetaVariable(std::string const& name) { // Check whether the variable name is legal. STORM_LOG_THROW(name != "" && name.back() != '\'', storm::exceptions::InvalidArgumentException, "Illegal name of meta variable: '" << name << "'."); // Check whether a meta variable already exists. STORM_LOG_THROW(!this->hasMetaVariable(name), storm::exceptions::InvalidArgumentException, "A meta variable '" << name << "' already exists."); storm::expressions::Variable unprimed = manager->declareBooleanVariable(name); storm::expressions::Variable primed = manager->declareBooleanVariable(name + "'"); std::vector> variables; std::vector> variablesPrime; auto ddVariablePair = internalDdManager.createNewDdVariablePair(); variables.emplace_back(Bdd(*this, ddVariablePair.first, {unprimed})); variablesPrime.emplace_back(Bdd(*this, ddVariablePair.second, {primed})); metaVariableMap.emplace(unprimed, DdMetaVariable(name, variables)); metaVariableMap.emplace(primed, DdMetaVariable(name + "'", variablesPrime)); return std::make_pair(unprimed, primed); } template DdMetaVariable const& DdManager::getMetaVariable(storm::expressions::Variable const& variable) const { auto const& variablePair = metaVariableMap.find(variable); // Check whether the meta variable exists. STORM_LOG_THROW(variablePair != metaVariableMap.end(), storm::exceptions::InvalidArgumentException, "Unknown meta variable name '" << variable.getName() << "'."); return variablePair->second; } template std::set DdManager::getAllMetaVariableNames() const { std::set result; for (auto const& variablePair : metaVariableMap) { result.insert(variablePair.first.getName()); } return result; } template std::size_t DdManager::getNumberOfMetaVariables() const { return this->metaVariableMap.size(); } template bool DdManager::hasMetaVariable(std::string const& metaVariableName) const { return manager->hasVariable(metaVariableName); } template storm::expressions::ExpressionManager const& DdManager::getExpressionManager() const { return *manager; } template storm::expressions::ExpressionManager& DdManager::getExpressionManager() { return *manager; } template std::vector DdManager::getDdVariableNames() const { // First, we initialize a list DD variables and their names. std::vector> variablePairs; for (auto const& variablePair : this->metaVariableMap) { DdMetaVariable const& metaVariable = variablePair.second; // If the meta variable is of type bool, we don't need to suffix it with the bit number. if (metaVariable.getType() == MetaVariableType::Bool) { variablePairs.emplace_back(metaVariable.getDdVariables().front().getIndex(), variablePair.first.getName()); } else { // For integer-valued meta variables, we, however, have to add the suffix. for (uint_fast64_t variableIndex = 0; variableIndex < metaVariable.getNumberOfDdVariables(); ++variableIndex) { variablePairs.emplace_back(metaVariable.getDdVariables()[variableIndex].getIndex(), variablePair.first.getName() + '.' + std::to_string(variableIndex)); } } } // Then, we sort this list according to the indices of the ADDs. std::sort(variablePairs.begin(), variablePairs.end(), [](std::pair const& a, std::pair const& b) { return a.first < b.first; }); // Now, we project the sorted vector to its second component. std::vector result; for (auto const& element : variablePairs) { result.push_back(element.second); } return result; } template std::vector DdManager::getDdVariables() const { // First, we initialize a list DD variables and their names. std::vector> variablePairs; for (auto const& variablePair : this->metaVariableMap) { DdMetaVariable const& metaVariable = variablePair.second; // If the meta variable is of type bool, we don't need to suffix it with the bit number. if (metaVariable.getType() == MetaVariableType::Bool) { variablePairs.emplace_back(metaVariable.getDdVariables().front().getIndex(), variablePair.first); } else { // For integer-valued meta variables, we, however, have to add the suffix. for (uint_fast64_t variableIndex = 0; variableIndex < metaVariable.getNumberOfDdVariables(); ++variableIndex) { variablePairs.emplace_back(metaVariable.getDdVariables()[variableIndex].getIndex(), variablePair.first); } } } // Then, we sort this list according to the indices of the ADDs. std::sort(variablePairs.begin(), variablePairs.end(), [](std::pair const& a, std::pair const& b) { return a.first < b.first; }); // Now, we project the sorted vector to its second component. std::vector result; for (auto const& element : variablePairs) { result.push_back(element.second); } return result; } template void DdManager::allowDynamicReordering(bool value) { internalDdManager.allowDynamicReordering(value); } template bool DdManager::isDynamicReorderingAllowed() const { return internalDdManager.isDynamicReorderingAllowed(); } template void DdManager::triggerReordering() { internalDdManager.triggerReordering(); } template std::set DdManager::getAllMetaVariables() const { std::set result; for (auto const& variable : this->metaVariableMap) { result.insert(variable.first); } return result; } template std::vector DdManager::getSortedVariableIndices() const { return this->getSortedVariableIndices(this->getAllMetaVariables()); } template std::vector DdManager::getSortedVariableIndices(std::set const& metaVariables) const { std::vector ddVariableIndices; for (auto const& metaVariable : metaVariables) { for (auto const& ddVariable : metaVariableMap.at(metaVariable).getDdVariables()) { ddVariableIndices.push_back(ddVariable.getIndex()); } } // Next, we need to sort them, since they may be arbitrarily ordered otherwise. std::sort(ddVariableIndices.begin(), ddVariableIndices.end()); return ddVariableIndices; } template InternalDdManager& DdManager::getInternalDdManager() { return internalDdManager; } template InternalDdManager const& DdManager::getInternalDdManager() const { return internalDdManager; } template InternalDdManager* DdManager::getInternalDdManagerPointer() { return &internalDdManager; } template InternalDdManager const* DdManager::getInternalDdManagerPointer() const { return &internalDdManager; } template class DdManager; template Add DdManager::getAddZero() const; template Add DdManager::getAddZero() const; template Add DdManager::getAddOne() const; template Add DdManager::getAddOne() const; template Add DdManager::getConstant(double const& value) const; template Add DdManager::getConstant(uint_fast64_t const& value) const; template Add DdManager::getIdentity(storm::expressions::Variable const& variable) const; template Add DdManager::getIdentity(storm::expressions::Variable const& variable) const; template class DdManager; template Add DdManager::getAddZero() const; template Add DdManager::getAddZero() const; template Add DdManager::getAddOne() const; template Add DdManager::getAddOne() const; template Add DdManager::getConstant(double const& value) const; template Add DdManager::getConstant(uint_fast64_t const& value) const; template Add DdManager::getIdentity(storm::expressions::Variable const& variable) const; template Add DdManager::getIdentity(storm::expressions::Variable const& variable) const; } }