#include #include #include #include "src/storage/dd/CuddDdManager.h" #include "src/exceptions/ExceptionMacros.h" #include "src/exceptions/InvalidArgumentException.h" #include "src/settings/SettingsManager.h" namespace storm { namespace dd { DdManager::DdManager() : metaVariableMap(), cuddManager(), reorderingTechnique(CUDD_REORDER_NONE) { this->cuddManager.SetMaxMemory(static_cast(storm::settings::SettingsManager::getInstance()->getOptionByLongName("cuddmaxmem").getArgument(0).getValueAsUnsignedInteger() * 1024ul * 1024ul)); this->cuddManager.SetEpsilon(storm::settings::SettingsManager::getInstance()->getOptionByLongName("cuddprec").getArgument(0).getValueAsDouble()); // Now set the selected reordering technique. std::string const& reorderingTechnique = storm::settings::SettingsManager::getInstance()->getOptionByLongName("reorder").getArgument(0).getValueAsString(); if (reorderingTechnique == "none") { this->reorderingTechnique = CUDD_REORDER_NONE; } else if (reorderingTechnique == "random") { this->reorderingTechnique = CUDD_REORDER_RANDOM; } else if (reorderingTechnique == "randompivot") { this->reorderingTechnique = CUDD_REORDER_RANDOM_PIVOT; } else if (reorderingTechnique == "sift") { this->reorderingTechnique = CUDD_REORDER_SIFT; } else if (reorderingTechnique == "siftconv") { this->reorderingTechnique = CUDD_REORDER_SIFT_CONVERGE; } else if (reorderingTechnique == "ssift") { this->reorderingTechnique = CUDD_REORDER_SYMM_SIFT; } else if (reorderingTechnique == "ssiftconv") { this->reorderingTechnique = CUDD_REORDER_SYMM_SIFT_CONV; } else if (reorderingTechnique == "gsift") { this->reorderingTechnique = CUDD_REORDER_GROUP_SIFT; } else if (reorderingTechnique == "gsiftconv") { this->reorderingTechnique = CUDD_REORDER_GROUP_SIFT_CONV; } else if (reorderingTechnique == "win2") { this->reorderingTechnique = CUDD_REORDER_WINDOW2; } else if (reorderingTechnique == "win2conv") { this->reorderingTechnique = CUDD_REORDER_WINDOW2_CONV; } else if (reorderingTechnique == "win3") { this->reorderingTechnique = CUDD_REORDER_WINDOW3; } else if (reorderingTechnique == "win3conv") { this->reorderingTechnique = CUDD_REORDER_WINDOW3_CONV; } else if (reorderingTechnique == "win4") { this->reorderingTechnique = CUDD_REORDER_WINDOW4; } else if (reorderingTechnique == "win4conv") { this->reorderingTechnique = CUDD_REORDER_WINDOW4_CONV; } else if (reorderingTechnique == "annealing") { this->reorderingTechnique = CUDD_REORDER_ANNEALING; } else if (reorderingTechnique == "genetic") { this->reorderingTechnique = CUDD_REORDER_GENETIC; } else if (reorderingTechnique == "exact") { this->reorderingTechnique = CUDD_REORDER_EXACT; } } Dd DdManager::getOne() { return Dd(this->shared_from_this(), cuddManager.addOne()); } Dd DdManager::getZero() { return Dd(this->shared_from_this(), cuddManager.addZero()); } Dd DdManager::getConstant(double value) { return Dd(this->shared_from_this(), cuddManager.constant(value)); } Dd DdManager::getEncoding(std::string const& metaVariableName, int_fast64_t value) { DdMetaVariable const& metaVariable = this->getMetaVariable(metaVariableName); LOG_THROW(value >= metaVariable.getLow() && value <= metaVariable.getHigh(), storm::exceptions::InvalidArgumentException, "Illegal value " << value << " for meta variable '" << metaVariableName << "'."); // Now compute the encoding relative to the low value of the meta variable. value -= metaVariable.getLow(); std::vector> const& ddVariables = metaVariable.getDdVariables(); Dd 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; } Dd DdManager::getRange(std::string const& metaVariableName) { storm::dd::DdMetaVariable const& metaVariable = this->getMetaVariable(metaVariableName); Dd result = this->getZero(); for (int_fast64_t value = metaVariable.getLow(); value <= metaVariable.getHigh(); ++value) { result.setValue(metaVariableName, value, static_cast(1)); } return result; } Dd DdManager::getIdentity(std::string const& metaVariableName) { storm::dd::DdMetaVariable const& metaVariable = this->getMetaVariable(metaVariableName); Dd result = this->getZero(); for (int_fast64_t value = metaVariable.getLow(); value <= metaVariable.getHigh(); ++value) { result.setValue(metaVariableName, value, static_cast(value)); } return result; } void DdManager::addMetaVariable(std::string const& name, int_fast64_t low, int_fast64_t high) { // Check whether the variable name is legal. LOG_THROW(name != "" && name.back() != '\'', storm::exceptions::InvalidArgumentException, "Illegal name of meta variable: '" << name << "'."); // Check whether a meta variable already exists. LOG_THROW(!this->hasMetaVariable(name), storm::exceptions::InvalidArgumentException, "A meta variable '" << name << "' already exists."); // Check that the range is legal. 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))); std::vector> variables; std::vector> variablesPrime; for (std::size_t i = 0; i < numberOfBits; ++i) { variables.emplace_back(Dd(this->shared_from_this(), cuddManager.addVar(), {name})); variablesPrime.emplace_back(Dd(this->shared_from_this(), cuddManager.addVar(), {name + "'"})); } // Now group the non-primed and primed variable. for (uint_fast64_t i = 0; i < numberOfBits; ++i) { this->getCuddManager().MakeTreeNode(variables[i].getCuddAdd().NodeReadIndex(), 2, MTR_FIXED); } metaVariableMap.emplace(name, DdMetaVariable(name, low, high, variables, this->shared_from_this())); metaVariableMap.emplace(name + "'", DdMetaVariable(name + "'", low, high, variablesPrime, this->shared_from_this())); } void DdManager::addMetaVariable(std::string const& name) { // Check whether the variable name is legal. LOG_THROW(name != "" && name.back() != '\'', storm::exceptions::InvalidArgumentException, "Illegal name of meta variable: '" << name << "'."); // Check whether a meta variable already exists. LOG_THROW(!this->hasMetaVariable(name), storm::exceptions::InvalidArgumentException, "A meta variable '" << name << "' already exists."); std::vector> variables; std::vector> variablesPrime; variables.emplace_back(Dd(this->shared_from_this(), cuddManager.addVar(), {name})); variablesPrime.emplace_back(Dd(this->shared_from_this(), cuddManager.addVar(), {name + "'"})); // Now group the non-primed and primed variable. this->getCuddManager().MakeTreeNode(variables.front().getCuddAdd().NodeReadIndex(), 2, MTR_FIXED); metaVariableMap.emplace(name, DdMetaVariable(name, variables, this->shared_from_this())); metaVariableMap.emplace(name + "'", DdMetaVariable(name + "'", variablesPrime, this->shared_from_this())); } DdMetaVariable const& DdManager::getMetaVariable(std::string const& metaVariableName) const { auto const& nameVariablePair = metaVariableMap.find(metaVariableName); // Check whether the meta variable exists. LOG_THROW(nameVariablePair != metaVariableMap.end(), storm::exceptions::InvalidArgumentException, "Unknown meta variable name '" << metaVariableName << "'."); return nameVariablePair->second; } std::set DdManager::getAllMetaVariableNames() const { std::set result; for (auto const& nameValuePair : metaVariableMap) { result.insert(nameValuePair.first); } return result; } std::size_t DdManager::getNumberOfMetaVariables() const { return this->metaVariableMap.size(); } bool DdManager::hasMetaVariable(std::string const& metaVariableName) const { return this->metaVariableMap.find(metaVariableName) != this->metaVariableMap.end(); } Cudd& DdManager::getCuddManager() { return this->cuddManager; } Cudd const& DdManager::getCuddManager() const { return this->cuddManager; } std::vector DdManager::getDdVariableNames() const { // First, we initialize a list DD variables and their names. std::vector> variableNamePairs; for (auto const& nameMetaVariablePair : this->metaVariableMap) { DdMetaVariable const& metaVariable = nameMetaVariablePair.second; // If the meta variable is of type bool, we don't need to suffix it with the bit number. if (metaVariable.getType() == DdMetaVariable::MetaVariableType::Bool) { variableNamePairs.emplace_back(metaVariable.getDdVariables().front().getCuddAdd(), metaVariable.getName()); } else { // For integer-valued meta variables, we, however, have to add the suffix. for (uint_fast64_t variableIndex = 0; variableIndex < metaVariable.getNumberOfDdVariables(); ++variableIndex) { variableNamePairs.emplace_back(metaVariable.getDdVariables()[variableIndex].getCuddAdd(), metaVariable.getName() + "." + std::to_string(variableIndex)); } } } // Then, we sort this list according to the indices of the ADDs. std::sort(variableNamePairs.begin(), variableNamePairs.end(), [](std::pair const& a, std::pair const& b) { return a.first.NodeReadIndex() < b.first.NodeReadIndex(); }); // Now, we project the sorted vector to its second component. std::vector result; for (auto const& element : variableNamePairs) { result.push_back(element.second); } return result; } void DdManager::allowDynamicReordering(bool value) { if (value) { this->getCuddManager().AutodynEnable(this->reorderingTechnique); } else { this->getCuddManager().AutodynDisable(); } } bool DdManager::isDynamicReorderingAllowed() const { Cudd_ReorderingType type; return this->getCuddManager().ReorderingStatus(&type); } void DdManager::triggerReordering() { this->getCuddManager().ReduceHeap(this->reorderingTechnique, 0); } } }