#pragma once #include <iostream> #include <unordered_map> #include <map> #include "storm/utility/macros.h" #include "storm-dft/storage/dft/DFTElements.h" #include "storm-dft/storage/dft/elements/DFTRestriction.h" namespace storm { namespace storage { template<typename ValueType> class DFT; template<typename ValueType> class DFTBuilder { using DFTElementPointer = std::shared_ptr<DFTElement<ValueType>>; using DFTElementVector = std::vector<DFTElementPointer>; using DFTGatePointer = std::shared_ptr<DFTGate<ValueType>>; using DFTGateVector = std::vector<DFTGatePointer>; using DFTDependencyPointer = std::shared_ptr<DFTDependency<ValueType>>; using DFTRestrictionPointer = std::shared_ptr<DFTRestriction<ValueType>>; private: std::size_t mNextId = 0; static std::size_t mUniqueOffset; std::string mTopLevelIdentifier; std::unordered_map<std::string, DFTElementPointer> mElements; std::unordered_map<DFTElementPointer, std::vector<std::string>> mChildNames; std::unordered_map<DFTRestrictionPointer, std::vector<std::string>> mRestrictionChildNames; std::vector<DFTDependencyPointer> mDependencies; std::vector<DFTRestrictionPointer> mRestrictions; public: DFTBuilder(bool defaultInclusive = true) : pandDefaultInclusive(defaultInclusive), porDefaultInclusive(defaultInclusive) { } bool addAndElement(std::string const& name, std::vector<std::string> const& children) { return addStandardGate(name, children, DFTElementType::AND); } bool addOrElement(std::string const& name, std::vector<std::string> const& children) { return addStandardGate(name, children, DFTElementType::OR); } bool addPandElement(std::string const& name, std::vector<std::string> const& children) { return addStandardGate(name, children, DFTElementType::PAND); } bool addPandElement(std::string const& name, std::vector<std::string> const& children, bool inclusive) { bool tmpDefault = pandDefaultInclusive; bool result = addStandardGate(name, children, DFTElementType::PAND); pandDefaultInclusive = tmpDefault; return result; } bool addPorElement(std::string const& name, std::vector<std::string> const& children) { return addStandardGate(name, children, DFTElementType::POR); } bool addSpareElement(std::string const& name, std::vector<std::string> const& children) { return addStandardGate(name, children, DFTElementType::SPARE); } bool addSequenceEnforcer(std::string const& name, std::vector<std::string> const& children) { return addRestriction(name, children, DFTElementType::SEQ); } bool addMutex(std::string const& name, std::vector<std::string> const& children) { return addRestriction(name, children, DFTElementType::MUTEX); } bool addDepElement(std::string const& name, std::vector<std::string> const& children, ValueType probability) { if(children.size() <= 1) { STORM_LOG_ERROR("Dependencies require at least two children"); } if(mElements.count(name) != 0) { // Element with that name already exists. return false; } if (storm::utility::isZero(probability)) { // Element is superfluous return true; } std::string trigger = children[0]; //TODO Matthias: collect constraints for SMT solving //0 <= probability <= 1 if (!storm::utility::isOne(probability) && children.size() > 2) { // Introduce additional element for first capturing the proabilistic dependency std::string nameAdditional = name + "_additional"; addBasicElement(nameAdditional, storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>()); // First consider probabilistic dependency addDepElement(name + "_pdep", {children.front(), nameAdditional}, probability); // Then consider dependencies to the children if probabilistic dependency failed std::vector<std::string> newChildren = children; newChildren[0] = nameAdditional; addDepElement(name, newChildren, storm::utility::one<ValueType>()); return true; } else { // Add dependencies for (size_t i = 1; i < children.size(); ++i) { std::string nameDep = name + "_" + std::to_string(i); if(mElements.count(nameDep) != 0) { // Element with that name already exists. STORM_LOG_ERROR("Element with name: " << nameDep << " already exists."); return false; } STORM_LOG_ASSERT(storm::utility::isOne(probability) || children.size() == 2, "PDep with multiple children supported."); DFTDependencyPointer element = std::make_shared<DFTDependency<ValueType>>(mNextId++, nameDep, trigger, children[i], probability); mElements[element->name()] = element; mDependencies.push_back(element); } return true; } } bool addVotElement(std::string const& name, unsigned threshold, std::vector<std::string> const& children) { STORM_LOG_ASSERT(children.size() > 0, "Has no child."); if(mElements.count(name) != 0) { STORM_LOG_ERROR("Element with name: " << name << " already exists."); return false; } // It is an and-gate if(children.size() == threshold) { return addAndElement(name, children); } // It is an or-gate if(threshold == 1) { return addOrElement(name, children); } if(threshold > children.size()) { STORM_LOG_ERROR("Voting gates with threshold higher than the number of children is not supported."); return false; } DFTElementPointer element = std::make_shared<DFTVot<ValueType>>(mNextId++, name, threshold); mElements[name] = element; mChildNames[element] = children; return true; } bool addBasicElement(std::string const& name, ValueType failureRate, ValueType dormancyFactor) { //TODO Matthias: collect constraints for SMT solving //failureRate > 0 //0 <= dormancyFactor <= 1 mElements[name] = std::make_shared<DFTBE<ValueType>>(mNextId++, name, failureRate, dormancyFactor); return true; } bool setTopLevel(std::string const& tle) { mTopLevelIdentifier = tle; return mElements.count(tle) > 0; } std::string getUniqueName(std::string name); DFT<ValueType> build(); /** * Copy element and insert it again in the builder. * * @param element Element to copy. */ void copyElement(DFTElementPointer element); /** * Copy gate with given children and insert it again in the builder. The current children of the element * are discarded. * * @param gate Gate to copy. * @param children New children of copied element. */ void copyGate(DFTGatePointer gate, std::vector<std::string> const& children); private: unsigned computeRank(DFTElementPointer const& elem); bool addStandardGate(std::string const& name, std::vector<std::string> const& children, DFTElementType tp); bool addRestriction(std::string const& name, std::vector<std::string> const& children, DFTElementType tp); enum class topoSortColour {WHITE, BLACK, GREY}; void topoVisit(DFTElementPointer const& n, std::map<DFTElementPointer, topoSortColour, OrderElementsById<ValueType>>& visited, DFTElementVector& L); DFTElementVector topoSort(); // If true, the standard gate adders make a pand inclusive, and exclusive otherwise. bool pandDefaultInclusive; // If true, the standard gate adders make a pand inclusive, and exclusive otherwise. bool porDefaultInclusive; }; } }