#include "DFTBuilder.h" #include <algorithm> #include "storm/utility/macros.h" #include "storm/exceptions/NotSupportedException.h" #include "storm/exceptions/WrongFormatException.h" #include "storm-dft/storage/dft/DFT.h" #include "storm-dft/storage/dft/OrderDFTElementsById.h" namespace storm { namespace storage { template<typename ValueType> std::size_t DFTBuilder<ValueType>::mUniqueOffset = 0; template<typename ValueType> DFT<ValueType> DFTBuilder<ValueType>::build() { for(auto& elem : mChildNames) { DFTGatePointer gate = std::static_pointer_cast<DFTGate<ValueType>>(elem.first); for(auto const& child : elem.second) { auto itFind = mElements.find(child); if (itFind != mElements.end()) { // Child found DFTElementPointer childElement = itFind->second; STORM_LOG_TRACE("Ignore functional dependency " << child << " in gate " << gate->name()); if(!childElement->isDependency()) { gate->pushBackChild(childElement); childElement->addParent(gate); } } else { // Child not found -> find first dependent event to assure that child is dependency // TODO: Not sure whether this is the intended behaviour? auto itFind = mElements.find(child + "_1"); STORM_LOG_ASSERT(itFind != mElements.end(), "Child '" << child << "' for gate '" << gate->name() << "' not found."); STORM_LOG_ASSERT(itFind->second->isDependency(), "Child is no dependency."); STORM_LOG_TRACE("Ignore functional dependency " << child << " in gate " << gate->name()); } } } for(auto& elem : mRestrictionChildNames) { for(auto const& childName : elem.second) { auto itFind = mElements.find(childName); STORM_LOG_ASSERT(itFind != mElements.end(), "Child not found."); DFTElementPointer childElement = itFind->second; STORM_LOG_ASSERT(!childElement->isDependency() && !childElement->isRestriction(), "Child '" << childElement->name() << "' has invalid type."); elem.first->pushBackChild(childElement); childElement->addRestriction(elem.first); } } for(auto& elem : mDependencyChildNames) { bool first = true; std::vector<std::shared_ptr<DFTBE<ValueType>>> dependencies; for(auto const& childName : elem.second) { auto itFind = mElements.find(childName); STORM_LOG_ASSERT(itFind != mElements.end(), "Child '" << childName << "' not found"); DFTElementPointer childElement = itFind->second; if (!first) { STORM_LOG_ASSERT(childElement->isBasicElement(), "Child '" << childName << "' of dependency '" << elem.first->name() << "' must be BE."); dependencies.push_back(std::static_pointer_cast<DFTBE<ValueType>>(childElement)); } else { elem.first->setTriggerElement(std::static_pointer_cast<DFTGate<ValueType>>(childElement)); childElement->addOutgoingDependency(elem.first); } first = false; } if (binaryDependencies) { assert(dependencies.size() == 1); } elem.first->setDependentEvents(dependencies); for (auto& dependency : dependencies) { dependency->addIngoingDependency(elem.first); } } // Sort elements topologically // compute rank for (auto& elem : mElements) { computeRank(elem.second); } DFTElementVector elems = topoSort(); size_t id = 0; for(DFTElementPointer e : elems) { e->setId(id++); } STORM_LOG_ASSERT(!mTopLevelIdentifier.empty(), "No top level element."); DFT<ValueType> dft(elems, mElements[mTopLevelIdentifier]); // Set layout info for (auto& elem : mElements) { if(mLayoutInfo.count(elem.first) > 0) { dft.setElementLayoutInfo(elem.second->id(), mLayoutInfo.at(elem.first)); } else { // Set default layout dft.setElementLayoutInfo(elem.second->id(), storm::storage::DFTLayoutInfo()); } } return dft; } template<typename ValueType> unsigned DFTBuilder<ValueType>::computeRank(DFTElementPointer const& elem) { if(elem->rank() == static_cast<decltype(elem->rank())>(-1)) { if(elem->nrChildren() == 0 || elem->isDependency()) { elem->setRank(0); } else { DFTGatePointer gate = std::static_pointer_cast<DFTGate<ValueType>>(elem); unsigned maxrnk = 0; unsigned newrnk = 0; for (DFTElementPointer const &child : gate->children()) { newrnk = computeRank(child); if (newrnk > maxrnk) { maxrnk = newrnk; } } elem->setRank(maxrnk + 1); } } return elem->rank(); } template<typename ValueType> bool DFTBuilder<ValueType>::addRestriction(std::string const& name, std::vector<std::string> const& children, DFTElementType tp) { if (children.size() <= 1) { STORM_LOG_ERROR("Sequence enforcers require at least two children"); } if (mElements.count(name) != 0) { return false; } DFTRestrictionPointer restr; switch (tp) { case DFTElementType::SEQ: restr = std::make_shared<DFTSeq<ValueType>>(mNextId++, name); break; case DFTElementType::MUTEX: // TODO notice that mutex state generation support is lacking anyway, as DONT CARE propagation would be broken for this. STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type not supported."); break; default: STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type not known."); break; } mElements[name] = restr; mRestrictionChildNames[restr] = children; mRestrictions.push_back(restr); return true; } template<typename ValueType> bool DFTBuilder<ValueType>::addStandardGate(std::string const& name, std::vector<std::string> const& children, DFTElementType tp) { STORM_LOG_ASSERT(children.size() > 0, "No child for " << name); if(mElements.count(name) != 0) { // Element with that name already exists. return false; } DFTElementPointer element; switch(tp) { case DFTElementType::AND: element = std::make_shared<DFTAnd<ValueType>>(mNextId++, name); break; case DFTElementType::OR: element = std::make_shared<DFTOr<ValueType>>(mNextId++, name); break; case DFTElementType::PAND: element = std::make_shared<DFTPand<ValueType>>(mNextId++, name, pandDefaultInclusive); break; case DFTElementType::POR: element = std::make_shared<DFTPor<ValueType>>(mNextId++, name, porDefaultInclusive); break; case DFTElementType::SPARE: element = std::make_shared<DFTSpare<ValueType>>(mNextId++, name); break; case DFTElementType::BE: case DFTElementType::VOT: case DFTElementType::PDEP: // Handled separately STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type handled separately."); case DFTElementType::CONSTF: case DFTElementType::CONSTS: STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type not supported."); default: STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type not known."); } mElements[name] = element; mChildNames[element] = children; return true; } template<typename ValueType> void DFTBuilder<ValueType>::topoVisit(DFTElementPointer const& n, std::map<DFTElementPointer, topoSortColour, OrderElementsById<ValueType>>& visited, DFTElementVector& L) { if(visited[n] == topoSortColour::GREY) { throw storm::exceptions::WrongFormatException("DFT is cyclic"); } else if(visited[n] == topoSortColour::WHITE) { if(n->isGate()) { visited[n] = topoSortColour::GREY; for (DFTElementPointer const& c : std::static_pointer_cast<DFTGate<ValueType>>(n)->children()) { topoVisit(c, visited, L); } } // TODO restrictions and dependencies have no parents, so this can be done more efficiently. if(n->isRestriction()) { visited[n] = topoSortColour::GREY; for (DFTElementPointer const& c : std::static_pointer_cast<DFTRestriction<ValueType>>(n)->children()) { topoVisit(c, visited, L); } } if(n->isDependency()) { visited[n] = topoSortColour::GREY; for (DFTElementPointer const& c : std::static_pointer_cast<DFTDependency<ValueType>>(n)->dependentEvents()) { topoVisit(c, visited, L); } topoVisit(std::static_pointer_cast<DFTDependency<ValueType>>(n)->triggerEvent(), visited, L); } visited[n] = topoSortColour::BLACK; L.push_back(n); } } template<typename ValueType> std::vector<std::shared_ptr<DFTElement<ValueType>>> DFTBuilder<ValueType>::topoSort() { std::map<DFTElementPointer, topoSortColour, OrderElementsById<ValueType>> visited; for(auto const& e : mElements) { visited.insert(std::make_pair(e.second, topoSortColour::WHITE)); } DFTElementVector L; for(auto const& e : visited) { topoVisit(e.first, visited, L); } //std::reverse(L.begin(), L.end()); return L; } template<typename ValueType> std::string DFTBuilder<ValueType>::getUniqueName(std::string name) { return name + "_" + std::to_string(++mUniqueOffset); } template<typename ValueType> void DFTBuilder<ValueType>::copyElement(DFTElementPointer element) { std::vector<std::string> children; switch (element->type()) { case DFTElementType::AND: case DFTElementType::OR: case DFTElementType::PAND: case DFTElementType::POR: case DFTElementType::SPARE: case DFTElementType::VOT: { for (DFTElementPointer const& elem : std::static_pointer_cast<DFTGate<ValueType>>(element)->children()) { children.push_back(elem->name()); } copyGate(std::static_pointer_cast<DFTGate<ValueType>>(element), children); break; } case DFTElementType::BE: { std::shared_ptr<DFTBE<ValueType>> be = std::static_pointer_cast<DFTBE<ValueType>>(element); ValueType dormancyFactor = storm::utility::zero<ValueType>(); if (be->canFail()) { dormancyFactor = be->passiveFailureRate() / be->activeFailureRate(); } addBasicElement(be->name(), be->activeFailureRate(), dormancyFactor, be->isTransient()); break; } case DFTElementType::CONSTF: case DFTElementType::CONSTS: // TODO STORM_LOG_ASSERT(false, "Const elements not supported."); break; case DFTElementType::PDEP: { DFTDependencyPointer dependency = std::static_pointer_cast<DFTDependency<ValueType>>(element); children.push_back(dependency->triggerEvent()->name()); for(auto const& depEv : dependency->dependentEvents()) { children.push_back(depEv->name()); } addDepElement(element->name(), children, dependency->probability()); break; } case DFTElementType::SEQ: case DFTElementType::MUTEX: { for (DFTElementPointer const& elem : std::static_pointer_cast<DFTRestriction<ValueType>>(element)->children()) { children.push_back(elem->name()); } addRestriction(element->name(), children, element->type()); break; } default: STORM_LOG_ASSERT(false, "Dft type not known."); break; } } template<typename ValueType> void DFTBuilder<ValueType>::copyGate(DFTGatePointer gate, std::vector<std::string> const& children) { switch (gate->type()) { case DFTElementType::AND: case DFTElementType::OR: case DFTElementType::PAND: case DFTElementType::POR: case DFTElementType::SPARE: addStandardGate(gate->name(), children, gate->type()); break; case DFTElementType::VOT: addVotElement(gate->name(), std::static_pointer_cast<DFTVot<ValueType>>(gate)->threshold(), children); break; default: STORM_LOG_ASSERT(false, "Dft type not known."); break; } } // Explicitly instantiate the class. template class DFTBuilder<double>; #ifdef STORM_HAVE_CARL template class DFTBuilder<RationalFunction>; #endif } }