#include "src/storage/dd/sylvan/SylvanAddIterator.h" #include "src/storage/dd/sylvan/InternalSylvanAdd.h" #include "src/storage/dd/DdManager.h" #include "src/storage/expressions/ExpressionManager.h" #include "src/utility/macros.h" #include "src/exceptions/NotImplementedException.h" #include #include "src/adapters/CarlAdapter.h" #include "storm-config.h" namespace storm { namespace dd { template AddIterator::AddIterator() { // Intentionally left empty. } template AddIterator::AddIterator(DdManager const& ddManager, sylvan::Mtbdd mtbdd, sylvan::Bdd variables, uint_fast64_t numberOfDdVariables, bool isAtEnd, std::set const* metaVariables, bool enumerateDontCareMetaVariables) : ddManager(&ddManager), mtbdd(mtbdd), variables(variables), cube(numberOfDdVariables), leaf(), isAtEnd(isAtEnd), metaVariables(metaVariables), enumerateDontCareMetaVariables(enumerateDontCareMetaVariables), cubeCounter(0), relevantDontCareDdVariables(), currentValuation(ddManager.getExpressionManager().getSharedPointer()) { // If the given generator is not yet at its end, we need to create the current valuation from the cube from // scratch. if (!this->isAtEnd) { this->createGlobalToLocalIndexMapping(); // And then get ready for treating the first cube. leaf = mtbdd_enum_first(mtbdd.GetMTBDD(), variables.GetBDD(), cube.data(), &mtbdd_isnonzero); if (leaf != mtbdd_false) { this->treatNewCube(); } else { this->isAtEnd = true; } } } template void AddIterator::createGlobalToLocalIndexMapping() { // Create the global to local index mapping. std::vector globalIndices; for (auto const& metaVariable : *this->metaVariables) { auto const& ddMetaVariable = this->ddManager->getMetaVariable(metaVariable); for (auto const& ddVariable : ddMetaVariable.getDdVariables()) { globalIndices.push_back(ddVariable.getIndex()); } } std::sort(globalIndices.begin(), globalIndices.end()); for (auto it = globalIndices.begin(), ite = globalIndices.end(); it != ite; ++it) { globalToLocalIndexMap[*it] = std::distance(globalIndices.begin(), it); } } template AddIterator AddIterator::createBeginIterator(DdManager const& ddManager, sylvan::Mtbdd mtbdd, sylvan::Bdd variables, uint_fast64_t numberOfDdVariables, std::set const* metaVariables, bool enumerateDontCareMetaVariables) { return AddIterator(ddManager, mtbdd, variables, numberOfDdVariables, false, metaVariables, enumerateDontCareMetaVariables); } template AddIterator AddIterator::createEndIterator(DdManager const& ddManager) { return AddIterator(ddManager, sylvan::Mtbdd(), sylvan::Bdd(), 0, true, nullptr, false); } template AddIterator& AddIterator::operator++() { STORM_LOG_ASSERT(!this->isAtEnd, "Illegally incrementing iterator that is already at its end."); // If there were no (relevant) don't cares or we have enumerated all combination, we need to eliminate the // found solutions and get the next "first" cube. if (this->relevantDontCareDdVariables.empty() || this->cubeCounter >= std::pow(2, this->relevantDontCareDdVariables.size()) - 1) { leaf = mtbdd_enum_next(mtbdd.GetMTBDD(), variables.GetBDD(), cube.data(), &mtbdd_isnonzero); if (leaf != mtbdd_false) { this->treatNewCube(); } else { this->isAtEnd = true; } } else { // Treat the next solution of the cube. this->treatNextInCube(); } return *this; } template bool AddIterator::operator==(AddIterator const& other) const { if (this->isAtEnd && other.isAtEnd) { return true; } else { return this->ddManager == other.ddManager && this->mtbdd == other.mtbdd && this->variables == other.variables && this->cube == other.cube && this->leaf == other.leaf && this->isAtEnd == other.isAtEnd && this->metaVariables == other.metaVariables && this->cubeCounter == other.cubeCounter && this->relevantDontCareDdVariables == other.relevantDontCareDdVariables && this->currentValuation == other.currentValuation; } } template bool AddIterator::operator!=(AddIterator const& other) const { return !(*this == other); } template std::pair AddIterator::operator*() const { return std::make_pair(currentValuation, static_cast(InternalAdd::getValue(leaf))); } template void AddIterator::treatNewCube() { this->relevantDontCareDdVariables.clear(); // Now loop through the bits of all meta variables and check whether they need to be set, not set or are // don't cares. In the latter case, we add them to a special list, so we can iterate over their concrete // valuations later. for (auto const& metaVariable : *this->metaVariables) { bool metaVariableAppearsInCube = false; std::vector> localRelenvantDontCareDdVariables; auto const& ddMetaVariable = this->ddManager->getMetaVariable(metaVariable); if (ddMetaVariable.getType() == MetaVariableType::Bool) { if (this->cube[globalToLocalIndexMap.at(ddMetaVariable.getDdVariables().front().getIndex())] == 0) { metaVariableAppearsInCube = true; currentValuation.setBooleanValue(metaVariable, false); } else if (this->cube[globalToLocalIndexMap.at(ddMetaVariable.getDdVariables().front().getIndex())] == 1) { metaVariableAppearsInCube = true; currentValuation.setBooleanValue(metaVariable, true); } else { localRelenvantDontCareDdVariables.push_back(std::make_tuple(metaVariable, 0)); } } else { int_fast64_t intValue = 0; for (uint_fast64_t bitIndex = 0; bitIndex < ddMetaVariable.getNumberOfDdVariables(); ++bitIndex) { if (cube[globalToLocalIndexMap.at(ddMetaVariable.getDdVariables()[bitIndex].getIndex())] == 0) { // Leave bit unset. metaVariableAppearsInCube = true; } else if (cube[globalToLocalIndexMap.at(ddMetaVariable.getDdVariables()[bitIndex].getIndex())] == 1) { intValue |= 1ull << (ddMetaVariable.getNumberOfDdVariables() - bitIndex - 1); metaVariableAppearsInCube = true; } else { // Temporarily leave bit unset so we can iterate trough the other option later. // Add the bit to the relevant don't care bits. localRelenvantDontCareDdVariables.push_back(std::make_tuple(metaVariable, ddMetaVariable.getNumberOfDdVariables() - bitIndex - 1)); } } if (this->enumerateDontCareMetaVariables || metaVariableAppearsInCube) { currentValuation.setBitVectorValue(metaVariable, intValue + ddMetaVariable.getLow()); } } // If all meta variables are to be enumerated or the meta variable appeared in the cube, we register the // missing bits to later enumerate all possible valuations. if (this->enumerateDontCareMetaVariables || metaVariableAppearsInCube) { relevantDontCareDdVariables.insert(relevantDontCareDdVariables.end(), localRelenvantDontCareDdVariables.begin(), localRelenvantDontCareDdVariables.end()); } } // Finally, reset the cube counter. this->cubeCounter = 0; } template void AddIterator::treatNextInCube() { // Start by increasing the counter and check which bits we need to set/unset in the new valuation. ++this->cubeCounter; for (uint_fast64_t index = 0; index < this->relevantDontCareDdVariables.size(); ++index) { auto const& ddMetaVariable = this->ddManager->getMetaVariable(std::get<0>(this->relevantDontCareDdVariables[index])); if (ddMetaVariable.getType() == MetaVariableType::Bool) { if ((this->cubeCounter & (1ull << index)) != 0) { currentValuation.setBooleanValue(std::get<0>(this->relevantDontCareDdVariables[index]), true); } else { currentValuation.setBooleanValue(std::get<0>(this->relevantDontCareDdVariables[index]), false); } } else { storm::expressions::Variable const& metaVariable = std::get<0>(this->relevantDontCareDdVariables[index]); if ((this->cubeCounter & (1ull << index)) != 0) { currentValuation.setBitVectorValue(metaVariable, ((currentValuation.getBitVectorValue(metaVariable) - ddMetaVariable.getLow()) | (1ull << std::get<1>(this->relevantDontCareDdVariables[index]))) + ddMetaVariable.getLow()); } else { currentValuation.setBitVectorValue(metaVariable, ((currentValuation.getBitVectorValue(metaVariable) - ddMetaVariable.getLow()) & ~(1ull << std::get<1>(this->relevantDontCareDdVariables[index]))) + ddMetaVariable.getLow()); } } } } template class AddIterator; template class AddIterator; #ifdef STORM_HAVE_CARL template class AddIterator; #endif } }