From b4bd898f1b34baf345c8d63f7cf85b4fb75f9a0a Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 13 Mar 2019 14:15:59 +0100 Subject: [PATCH 01/40] Fixed arguments for exploration heuristic settings --- src/storm-dft/settings/modules/FaultTreeSettings.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/storm-dft/settings/modules/FaultTreeSettings.cpp b/src/storm-dft/settings/modules/FaultTreeSettings.cpp index 7c9ef14af..a110ea0a7 100644 --- a/src/storm-dft/settings/modules/FaultTreeSettings.cpp +++ b/src/storm-dft/settings/modules/FaultTreeSettings.cpp @@ -31,7 +31,10 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, disableDCOptionName, false, "Disable Dont Care propagation.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, firstDependencyOptionName, false, "Avoid non-determinism by always taking the first possible dependency.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, approximationErrorOptionName, false, "Approximation error allowed.").setShortName(approximationErrorOptionShortName).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("error", "The relative approximation error to use.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterEqualValidator(0.0)).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, approximationHeuristicOptionName, false, "Set the heuristic used for approximation.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("heuristic", "Sets which heuristic is used for approximation. Must be in {depth, probability}. Default is").setDefaultValueString("depth").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator({"depth", "rateratio"})).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, approximationHeuristicOptionName, false, "Set the heuristic used for approximation.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("heuristic", "Sets which heuristic is used for approximation. Must be in {none, depth, probability, bounddifference}. Default is") + .setDefaultValueString("depth") + .addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator({"none", "depth", "probability", "bounddifference"})).build()).build()); #ifdef STORM_HAVE_Z3 this->addOption(storm::settings::OptionBuilder(moduleName, solveWithSmtOptionName, true, "Solve the DFT with SMT.").build()); #endif @@ -63,10 +66,14 @@ namespace storm { return storm::builder::ApproximationHeuristic::NONE; } std::string heuristicAsString = this->getOption(approximationHeuristicOptionName).getArgumentByName("heuristic").getValueAsString(); - if (heuristicAsString == "depth") { + if (heuristicAsString == "none") { + return storm::builder::ApproximationHeuristic::NONE; + } else if (heuristicAsString == "depth") { return storm::builder::ApproximationHeuristic::DEPTH; } else if (heuristicAsString == "probability") { return storm::builder::ApproximationHeuristic::PROBABILITY; + } else if (heuristicAsString == "bounddifference") { + return storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE; } STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Illegal value '" << heuristicAsString << "' set as heuristic for approximation."); } From bb5d8b478ab289511af0a19217d54e7d3807977f Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Mon, 18 Mar 2019 22:01:07 +0100 Subject: [PATCH 02/40] Refactored DftExplorationHeuristic --- .../builder/DftExplorationHeuristic.cpp | 63 ++------------ .../builder/DftExplorationHeuristic.h | 86 ++++++++----------- 2 files changed, 44 insertions(+), 105 deletions(-) diff --git a/src/storm-dft/builder/DftExplorationHeuristic.cpp b/src/storm-dft/builder/DftExplorationHeuristic.cpp index a8a11ae18..d46736268 100644 --- a/src/storm-dft/builder/DftExplorationHeuristic.cpp +++ b/src/storm-dft/builder/DftExplorationHeuristic.cpp @@ -1,81 +1,30 @@ #include "DftExplorationHeuristic.h" #include "storm/adapters/RationalFunctionAdapter.h" -#include "storm/utility/macros.h" -#include "storm/utility/constants.h" #include "storm/exceptions/NotImplementedException.h" namespace storm { namespace builder { - template - DFTExplorationHeuristic::DFTExplorationHeuristic(size_t id) : id(id), expand(true), lowerBound(storm::utility::zero()), upperBound(storm::utility::infinity()), depth(0), probability(storm::utility::one()) { - // Intentionally left empty - } - - template - DFTExplorationHeuristic::DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) : id(id), expand(false), lowerBound(storm::utility::zero()), upperBound(storm::utility::zero()), depth(predecessor.depth + 1) { - STORM_LOG_ASSERT(storm::utility::zero() < exitRate, "Exit rate is 0"); - probability = predecessor.probability * rate/exitRate; - } - - template - void DFTExplorationHeuristic::setBounds(ValueType lowerBound, ValueType upperBound) { - this->lowerBound = lowerBound; - this->upperBound = upperBound; - } - - template<> - bool DFTExplorationHeuristicProbability::updateHeuristicValues(DFTExplorationHeuristic const& predecessor, double rate, double exitRate) { - STORM_LOG_ASSERT(exitRate > 0, "Exit rate is 0"); - probability += predecessor.getProbability() * rate/exitRate; - return true; - } - - template<> - bool DFTExplorationHeuristicProbability::updateHeuristicValues(DFTExplorationHeuristic const& predecessor, storm::RationalFunction rate, storm::RationalFunction exitRate) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work for rational functions."); - return false; - } - template<> double DFTExplorationHeuristicProbability::getPriority() const { return probability; } - template<> - double DFTExplorationHeuristicProbability::getPriority() const { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work for rational functions."); - } - - template<> - bool DFTExplorationHeuristicBoundDifference::updateHeuristicValues(DFTExplorationHeuristic const& predecessor, double rate, double exitRate) { - STORM_LOG_ASSERT(exitRate > 0, "Exit rate is 0"); - probability += predecessor.getProbability() * rate/exitRate; - return true; - } - - template<> - bool DFTExplorationHeuristicBoundDifference::updateHeuristicValues(DFTExplorationHeuristic const& predecessor, storm::RationalFunction rate, storm::RationalFunction exitRate) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic rate ration does not work for rational functions."); - return false; - } - template - void DFTExplorationHeuristicBoundDifference::setBounds(ValueType lowerBound, ValueType upperBound) { - this->lowerBound = lowerBound; - this->upperBound = upperBound; - difference = (storm::utility::one() / upperBound) - (storm::utility::one() / lowerBound); + double DFTExplorationHeuristicProbability::getPriority() const { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic 'probability' does not work for this data type."); } template<> double DFTExplorationHeuristicBoundDifference::getPriority() const { + double difference = (storm::utility::one() / upperBound) - (storm::utility::one() / lowerBound); return probability * difference; } - template<> - double DFTExplorationHeuristicBoundDifference::getPriority() const { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic bound difference does not work for rational functions."); + template + double DFTExplorationHeuristicBoundDifference::getPriority() const { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Heuristic 'bound difference' does not work for this data type."); } // Instantiate templates. diff --git a/src/storm-dft/builder/DftExplorationHeuristic.h b/src/storm-dft/builder/DftExplorationHeuristic.h index 2de704e29..f49f5925a 100644 --- a/src/storm-dft/builder/DftExplorationHeuristic.h +++ b/src/storm-dft/builder/DftExplorationHeuristic.h @@ -1,6 +1,10 @@ #pragma once #include +#include "storm/utility/constants.h" +#include "storm/utility/macros.h" + + namespace storm { namespace builder { @@ -12,25 +16,32 @@ namespace storm { /*! - * General super class for appoximation heuristics. + * General super class for approximation heuristics. */ template class DFTExplorationHeuristic { public: - DFTExplorationHeuristic(size_t id); + explicit DFTExplorationHeuristic(size_t id) : id(id), expand(true), lowerBound(storm::utility::zero()), upperBound(storm::utility::infinity()), depth(0), probability(storm::utility::one()) { + // Intentionally left empty + } - DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate); + DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) : id(id), expand(false), lowerBound(storm::utility::zero()), upperBound(storm::utility::zero()), depth(predecessor.depth + 1), probability(storm::utility::one()) { + this->updateHeuristicValues(predecessor, rate, exitRate); + } virtual ~DFTExplorationHeuristic() = default; - void setBounds(ValueType lowerBound, ValueType upperBound); - - virtual bool updateHeuristicValues(DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) = 0; - - virtual double getPriority() const = 0; + void setBounds(ValueType lowerBound, ValueType upperBound) { + this->lowerBound = lowerBound; + this->upperBound = upperBound; + } - virtual bool isSkip(double approximationThreshold) const = 0; + virtual bool updateHeuristicValues(DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) { + STORM_LOG_ASSERT(!storm::utility::isZero(exitRate), "Exit rate is 0"); + probability += predecessor.getProbability() * rate/exitRate; + return true; + } void markExpand() { expand = true; @@ -40,7 +51,7 @@ namespace storm { return id; } - bool isExpand() { + bool isExpand() const { return expand; } @@ -60,6 +71,16 @@ namespace storm { return upperBound; } + virtual double getPriority() const = 0; + + virtual bool isSkip(double approximationThreshold) const { + return !this->isExpand() && this->getPriority() < approximationThreshold; + } + + virtual bool operator<(DFTExplorationHeuristic const& other) const { + return this->getPriority() < other.getPriority(); + } + protected: size_t id; bool expand; @@ -76,7 +97,7 @@ namespace storm { // Intentionally left empty } - DFTExplorationHeuristicNone(size_t id, DFTExplorationHeuristicNone const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic(id, predecessor, rate, exitRate) { + DFTExplorationHeuristicNone(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic(id, predecessor, rate, exitRate) { // Intentionally left empty } @@ -91,10 +112,6 @@ namespace storm { bool isSkip(double) const override { return false; } - - bool operator<(DFTExplorationHeuristicNone const& other) const { - return this->id > other.id; - } }; template @@ -104,7 +121,7 @@ namespace storm { // Intentionally left empty } - DFTExplorationHeuristicDepth(size_t id, DFTExplorationHeuristicDepth const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic(id, predecessor, rate, exitRate) { + DFTExplorationHeuristicDepth(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic(id, predecessor, rate, exitRate) { // Intentionally left empty } @@ -116,17 +133,16 @@ namespace storm { return false; } - double getPriority() const override { return this->depth; } bool isSkip(double approximationThreshold) const override { - return !this->expand && this->depth > approximationThreshold; + return !this->expand && this->getPriority() > approximationThreshold; } - bool operator<(DFTExplorationHeuristicDepth const& other) const { - return this->depth > other.depth; + bool operator<(DFTExplorationHeuristic const& other) const override { + return this->getPriority() > other.getPriority(); } }; @@ -137,21 +153,11 @@ namespace storm { // Intentionally left empty } - DFTExplorationHeuristicProbability(size_t id, DFTExplorationHeuristicProbability const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic(id, predecessor, rate, exitRate) { + DFTExplorationHeuristicProbability(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic(id, predecessor, rate, exitRate) { // Intentionally left empty } - bool updateHeuristicValues(DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) override; - double getPriority() const override; - - bool isSkip(double approximationThreshold) const override { - return !this->expand && this->getPriority() < approximationThreshold; - } - - bool operator<(DFTExplorationHeuristicProbability const& other) const { - return this->getPriority() < other.getPriority(); - } }; template @@ -161,28 +167,12 @@ namespace storm { // Intentionally left empty } - DFTExplorationHeuristicBoundDifference(size_t id, DFTExplorationHeuristicBoundDifference const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic(id, predecessor, rate, exitRate) { + DFTExplorationHeuristicBoundDifference(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic(id, predecessor, rate, exitRate) { // Intentionally left empty } - void setBounds(ValueType lowerBound, ValueType upperBound); - - bool updateHeuristicValues(DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) override; - double getPriority() const override; - - bool isSkip(double approximationThreshold) const override { - return !this->expand && this->getPriority() < approximationThreshold; - } - - bool operator<(DFTExplorationHeuristicBoundDifference const& other) const { - return this->getPriority() < other.getPriority(); - } - - private: - ValueType difference; }; - } } From 3dd0bffef9194492e1a86821ac5317f7296aa417 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Mon, 18 Mar 2019 22:02:36 +0100 Subject: [PATCH 03/40] Refactored BucketPriorityQueue --- .../builder/ExplicitDFTModelBuilder.cpp | 2 +- src/storm-dft/storage/BucketPriorityQueue.cpp | 86 ++++++++-------- src/storm-dft/storage/BucketPriorityQueue.h | 98 ++++++++++++++----- 3 files changed, 121 insertions(+), 65 deletions(-) diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index 466cba537..3e1436ba7 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -325,7 +325,7 @@ namespace storm { // TODO Matthias: do not empty queue every time but break before while (!explorationQueue.empty()) { // Get the first state in the queue - ExplorationHeuristicPointer currentExplorationHeuristic = explorationQueue.popTop(); + ExplorationHeuristicPointer currentExplorationHeuristic = explorationQueue.pop(); StateType currentId = currentExplorationHeuristic->getId(); auto itFind = statesNotExplored.find(currentId); STORM_LOG_ASSERT(itFind != statesNotExplored.end(), "Id " << currentId << " not found"); diff --git a/src/storm-dft/storage/BucketPriorityQueue.cpp b/src/storm-dft/storage/BucketPriorityQueue.cpp index a591764ac..a0926e70c 100644 --- a/src/storm-dft/storage/BucketPriorityQueue.cpp +++ b/src/storm-dft/storage/BucketPriorityQueue.cpp @@ -7,29 +7,29 @@ namespace storm { namespace storage { - template - BucketPriorityQueue::BucketPriorityQueue(size_t nrBuckets, double lowerValue, double ratio, bool higher) : lowerValue(lowerValue), higher(higher), logBase(std::log(ratio)), nrBuckets(nrBuckets), nrUnsortedItems(0), buckets(nrBuckets), currentBucket(nrBuckets) { - compare = ([](HeuristicPointer a, HeuristicPointer b) { + template + BucketPriorityQueue::BucketPriorityQueue(size_t nrBuckets, double lowerValue, double ratio, bool higher) : buckets(nrBuckets), currentBucket(nrBuckets), nrUnsortedItems(0), lowerValue(lowerValue), higher(higher), logBase(std::log(ratio)), nrBuckets(nrBuckets) { + compare = ([](PriorityTypePointer a, PriorityTypePointer b) { return *a < *b; }); } - template - void BucketPriorityQueue::fix() { + template + void BucketPriorityQueue::fix() { if (currentBucket < nrBuckets && nrUnsortedItems > buckets[currentBucket].size() / 10) { - // Fix current bucket + // Sort current bucket std::make_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare); nrUnsortedItems = 0; } } - template - bool BucketPriorityQueue::empty() const { + template + bool BucketPriorityQueue::empty() const { return currentBucket == nrBuckets && immediateBucket.empty(); } - template - std::size_t BucketPriorityQueue::size() const { + template + size_t BucketPriorityQueue::size() const { size_t size = immediateBucket.size(); for (size_t i = currentBucket; currentBucket < nrBuckets; ++i) { size += buckets[i].size(); @@ -37,8 +37,8 @@ namespace storm { return size; } - template - typename BucketPriorityQueue::HeuristicPointer const& BucketPriorityQueue::top() const { + template + typename BucketPriorityQueue::PriorityTypePointer const& BucketPriorityQueue::top() const { if (!immediateBucket.empty()) { return immediateBucket.back(); } @@ -46,8 +46,8 @@ namespace storm { return buckets[currentBucket].front(); } - template - void BucketPriorityQueue::push(HeuristicPointer const& item) { + template + void BucketPriorityQueue::push(PriorityTypePointer const& item) { if (item->isExpand()) { immediateBucket.push_back(item); return; @@ -59,7 +59,7 @@ namespace storm { } buckets[bucket].push_back(item); if (bucket == currentBucket) { - // Insert in first bucket + // Inserted in first bucket if (AUTOSORT) { std::push_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare); } else { @@ -68,8 +68,8 @@ namespace storm { } } - template - void BucketPriorityQueue::update(HeuristicPointer const& item, double oldPriority) { + template + void BucketPriorityQueue::update(PriorityTypePointer const& item, double oldPriority) { STORM_LOG_ASSERT(!item->isExpand(), "Item is marked for expansion"); size_t newBucket = getBucket(item->getPriority()); size_t oldBucket = getBucket(oldPriority); @@ -95,7 +95,7 @@ namespace storm { // Remove old entry by swap-and-pop if (buckets[oldBucket].size() >= 2) { // Find old index by linear search - // Notice: using a map to rememeber index was not efficient + // Notice: using a map to remember index was not efficient size_t oldIndex = 0; for ( ; oldIndex < buckets[oldBucket].size(); ++oldIndex) { if (buckets[oldBucket][oldIndex]->getId() == item->getId()) { @@ -120,14 +120,16 @@ namespace storm { } - template - void BucketPriorityQueue::pop() { + template + typename BucketPriorityQueue::PriorityTypePointer BucketPriorityQueue::pop() { if (!immediateBucket.empty()) { + PriorityTypePointer item = immediateBucket.back(); immediateBucket.pop_back(); - return; + return item; } STORM_LOG_ASSERT(!empty(), "BucketPriorityQueue is empty"); std::pop_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare); + PriorityTypePointer item = buckets[currentBucket].back(); buckets[currentBucket].pop_back(); if (buckets[currentBucket].empty()) { // Find next bucket with elements @@ -141,17 +143,11 @@ namespace storm { } } } - } - - template - typename BucketPriorityQueue::HeuristicPointer BucketPriorityQueue::popTop() { - HeuristicPointer item = top(); - pop(); return item; } - template - size_t BucketPriorityQueue::getBucket(double priority) const { + template + size_t BucketPriorityQueue::getBucket(double priority) const { STORM_LOG_ASSERT(priority >= lowerValue, "Priority " << priority << " is too low"); // For possible values greater 1 @@ -160,41 +156,39 @@ namespace storm { if (tmpBucket < 0) { tmpBucket = 0; } - size_t newBucket = tmpBucket; + size_t newBucket = static_cast(tmpBucket); // For values ensured to be lower 1 - //size_t newBucket = std::log(priority - lowerValue) / logBase; if (newBucket >= nrBuckets) { newBucket = nrBuckets - 1; } if (!higher) { newBucket = nrBuckets-1 - newBucket; } - //std::cout << "get Bucket: " << priority << ", " << newBucket << std::endl; STORM_LOG_ASSERT(newBucket < nrBuckets, "Priority " << priority << " is too high"); return newBucket; } - template - void BucketPriorityQueue::print(std::ostream& out) const { + template + void BucketPriorityQueue::print(std::ostream& out) const { out << "Bucket priority queue with size " << buckets.size() << ", lower value: " << lowerValue << " and logBase: " << logBase << std::endl; out << "Immediate bucket: "; - for (HeuristicPointer heuristic : immediateBucket) { - out << heuristic->getId() << ", "; + for (auto item : immediateBucket) { + out << item->getId() << ", "; } out << std::endl; out << "Current bucket (" << currentBucket << ") has " << nrUnsortedItems << " unsorted items" << std::endl; for (size_t bucket = 0; bucket < buckets.size(); ++bucket) { if (!buckets[bucket].empty()) { out << "Bucket " << bucket << ":" << std::endl; - for (HeuristicPointer heuristic : buckets[bucket]) { - out << "\t" << heuristic->getId() << ": " << heuristic->getPriority() << std::endl; + for (auto item : buckets[bucket]) { + out << "\t" << item->getId() << ": " << item->getPriority() << std::endl; } } } } - template - void BucketPriorityQueue::printSizes(std::ostream& out) const { + template + void BucketPriorityQueue::printSizes(std::ostream& out) const { out << "Bucket sizes: " << immediateBucket.size() << " | "; for (size_t bucket = 0; bucket < buckets.size(); ++bucket) { out << buckets[bucket].size() << " "; @@ -203,10 +197,18 @@ namespace storm { } // Template instantiations - template class BucketPriorityQueue; + template class BucketPriorityQueue>; + template class BucketPriorityQueue>; + template class BucketPriorityQueue>; + template class BucketPriorityQueue>; + template class BucketPriorityQueue>; #ifdef STORM_HAVE_CARL - template class BucketPriorityQueue; + template class BucketPriorityQueue>; + template class BucketPriorityQueue>; + template class BucketPriorityQueue>; + template class BucketPriorityQueue>; + template class BucketPriorityQueue>; #endif } } diff --git a/src/storm-dft/storage/BucketPriorityQueue.h b/src/storm-dft/storage/BucketPriorityQueue.h index 10c753763..2c0c3cb37 100644 --- a/src/storm-dft/storage/BucketPriorityQueue.h +++ b/src/storm-dft/storage/BucketPriorityQueue.h @@ -10,38 +10,102 @@ namespace storm { namespace storage { - template + /*! + * Priority queue based on buckets. + * Can be used to keep track of states during state space exploration. + * @tparam PriorityType Underlying priority data type + */ + template class BucketPriorityQueue { - using HeuristicPointer = std::shared_ptr>; + using PriorityTypePointer = std::shared_ptr; public: + /*! + * Create new priority queue. + * @param nrBuckets + * @param lowerValue + * @param ratio + * @param higher + */ explicit BucketPriorityQueue(size_t nrBuckets, double lowerValue, double ratio, bool higher); void fix(); + /*! + * Check whether queue is empty. + * @return True iff queue is empty. + */ bool empty() const; + /*! + * Return number of entries. + * @return Size of queue. + */ std::size_t size() const; - HeuristicPointer const& top() const; + /*! + * Get element with highest priority. + * @return Top element. + */ + PriorityTypePointer const& top() const; + + /*! + * Add element. + * @param item Element. + */ + void push(PriorityTypePointer const& item); + + /*! + * Update existing element. + * @param item Element with changes. + * @param oldPriority Old priority. + */ + void update(PriorityTypePointer const& item, double oldPriority); + + /*! + * Get element with highest priority and remove it from the queue. + * @return Top element. + */ + PriorityTypePointer pop(); + + /*! + * Print info about priority queue. + * @param out Output stream. + */ + void print(std::ostream& out) const; - void push(HeuristicPointer const& item); + /*! + * Print sizes of buckets. + * @param out Output stream. + */ + void printSizes(std::ostream& out) const; - void update(HeuristicPointer const& item, double oldPriority); + private: - void pop(); + /*! + * Get bucket for given priority. + * @param priority Priority. + * @return Bucket containing the priority. + */ + size_t getBucket(double priority) const; - HeuristicPointer popTop(); + // List of buckets + std::vector> buckets; - void print(std::ostream& out) const; + // Bucket containing all items which should be considered immediately + std::vector immediateBucket; - void printSizes(std::ostream& out) const; + // Index of first bucket which contains items + size_t currentBucket; - private: + // Number of unsorted items in current bucket + size_t nrUnsortedItems; - size_t getBucket(double priority) const; + // Comparison function for priorities + std::function compare; + // Minimal value const double lowerValue; const bool higher; @@ -50,20 +114,10 @@ namespace storm { const double logBase; + // Number of available buckets const size_t nrBuckets; - size_t nrUnsortedItems; - - // List of buckets - std::vector> buckets; - - // Bucket containing all items which should be considered immediately - std::vector immediateBucket; - - // Index of first bucket which contains items - size_t currentBucket; - std::function compare; }; From 970430a6fbe92d4877ad19a8faacdf0aaa60165a Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Mon, 18 Mar 2019 22:39:39 +0100 Subject: [PATCH 04/40] Make exploration heuristic choosable --- .../builder/ExplicitDFTModelBuilder.cpp | 40 +++++++++++++++---- .../builder/ExplicitDFTModelBuilder.h | 5 +-- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index 3e1436ba7..21a9e97f8 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -60,14 +60,9 @@ namespace storm { generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates), matrixBuilder(!generator.isDeterministicModel()), stateStorage(dft.stateBitVectorSize()), - // TODO Matthias: make choosable //explorationQueue(dft.nrElements()+1, 0, 1) explorationQueue(200, 0, 0.9, false) { - // Intentionally left empty. - // TODO Matthias: remove again - usedHeuristic = storm::builder::ApproximationHeuristic::DEPTH; - // Compute independent subtrees if (dft.topLevelType() == storm::storage::DFTElementType::OR) { // We only support this for approximation with top level element OR @@ -163,7 +158,21 @@ namespace storm { STORM_LOG_TRACE("Initial state: " << initialStateIndex); // Initialize heuristic values for inital state STORM_LOG_ASSERT(!statesNotExplored.at(initialStateIndex).second, "Heuristic for initial state is already initialized"); - ExplorationHeuristicPointer heuristic = std::make_shared(initialStateIndex); + ExplorationHeuristicPointer heuristic; + switch (usedHeuristic) { + case storm::builder::ApproximationHeuristic::NONE: + heuristic = std::make_shared>(initialStateIndex); + break; + case storm::builder::ApproximationHeuristic::DEPTH: + heuristic = std::make_shared>(initialStateIndex); + break; + case storm::builder::ApproximationHeuristic::PROBABILITY: + heuristic = std::make_shared>(initialStateIndex); + break; + case storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE: + heuristic = std::make_shared>(initialStateIndex); + break; + } heuristic->markExpand(); statesNotExplored[initialStateIndex].second = heuristic; explorationQueue.push(heuristic); @@ -171,7 +180,7 @@ namespace storm { initializeNextIteration(); } - if (approximationThreshold > 0) { + if (approximationThreshold > 0.0) { switch (usedHeuristic) { case storm::builder::ApproximationHeuristic::NONE: // Do not change anything @@ -385,7 +394,22 @@ namespace storm { DFTStatePointer state = iter->second.first; if (!iter->second.second) { // Initialize heuristic values - ExplorationHeuristicPointer heuristic = std::make_shared(stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass()); + ExplorationHeuristicPointer heuristic; + switch (usedHeuristic) { + case storm::builder::ApproximationHeuristic::NONE: + heuristic = std::make_shared>(stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass()); + break; + case storm::builder::ApproximationHeuristic::DEPTH: + heuristic = std::make_shared>(stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass()); + break; + case storm::builder::ApproximationHeuristic::PROBABILITY: + heuristic = std::make_shared>(stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass()); + break; + case storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE: + heuristic = std::make_shared>(stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass()); + break; + } + iter->second.second = heuristic; if (state->hasFailed(dft.getTopLevelIndex()) || state->isFailsafe(dft.getTopLevelIndex()) || state->getFailableElements().hasDependencies() || (!state->getFailableElements().hasDependencies() && state->getFailableElements().hasBEs())) { // Do not skip absorbing state or if reached by dependencies diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.h b/src/storm-dft/builder/ExplicitDFTModelBuilder.h index b96dea410..9858000ec 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.h +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.h @@ -29,8 +29,7 @@ namespace storm { class ExplicitDFTModelBuilder { using DFTStatePointer = std::shared_ptr>; - // TODO Matthias: make choosable - using ExplorationHeuristic = DFTExplorationHeuristicDepth; + using ExplorationHeuristic = DFTExplorationHeuristic; using ExplorationHeuristicPointer = std::shared_ptr; @@ -343,7 +342,7 @@ namespace storm { storm::storage::sparse::StateStorage stateStorage; // A priority queue of states that still need to be explored. - storm::storage::BucketPriorityQueue explorationQueue; + storm::storage::BucketPriorityQueue explorationQueue; // A mapping of not yet explored states from the id to the tuple (state object, heuristic values). std::map> statesNotExplored; From 42a79dfe8831a19f559fc2ae0020837c756f940e Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Mon, 18 Mar 2019 22:40:40 +0100 Subject: [PATCH 05/40] Fixed crucial bug marking all states as 'to expand'. As a result no states were skipped during exploration and no approximation took place. --- src/storm-dft/builder/ExplicitDFTModelBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index 21a9e97f8..13647880e 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -411,7 +411,7 @@ namespace storm { } iter->second.second = heuristic; - if (state->hasFailed(dft.getTopLevelIndex()) || state->isFailsafe(dft.getTopLevelIndex()) || state->getFailableElements().hasDependencies() || (!state->getFailableElements().hasDependencies() && state->getFailableElements().hasBEs())) { + if (state->hasFailed(dft.getTopLevelIndex()) || state->isFailsafe(dft.getTopLevelIndex()) || state->getFailableElements().hasDependencies() || (!state->getFailableElements().hasDependencies() && !state->getFailableElements().hasBEs())) { // Do not skip absorbing state or if reached by dependencies iter->second.second->markExpand(); } From 5d80c356e28935d318b89c7a4f06de2f38248cb0 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 19 Mar 2019 11:14:27 +0100 Subject: [PATCH 06/40] Some fixes for approximation --- src/storm-dft/builder/DftExplorationHeuristic.cpp | 3 ++- src/storm-dft/builder/DftExplorationHeuristic.h | 2 +- src/storm-dft/builder/ExplicitDFTModelBuilder.cpp | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/storm-dft/builder/DftExplorationHeuristic.cpp b/src/storm-dft/builder/DftExplorationHeuristic.cpp index d46736268..43b3ad96b 100644 --- a/src/storm-dft/builder/DftExplorationHeuristic.cpp +++ b/src/storm-dft/builder/DftExplorationHeuristic.cpp @@ -18,7 +18,8 @@ namespace storm { template<> double DFTExplorationHeuristicBoundDifference::getPriority() const { - double difference = (storm::utility::one() / upperBound) - (storm::utility::one() / lowerBound); + double difference = lowerBound - upperBound; // Lower bound is larger than upper bound + difference = 2 * difference / (upperBound + lowerBound); return probability * difference; } diff --git a/src/storm-dft/builder/DftExplorationHeuristic.h b/src/storm-dft/builder/DftExplorationHeuristic.h index f49f5925a..de4b5cfc5 100644 --- a/src/storm-dft/builder/DftExplorationHeuristic.h +++ b/src/storm-dft/builder/DftExplorationHeuristic.h @@ -26,7 +26,7 @@ namespace storm { // Intentionally left empty } - DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) : id(id), expand(false), lowerBound(storm::utility::zero()), upperBound(storm::utility::zero()), depth(predecessor.depth + 1), probability(storm::utility::one()) { + DFTExplorationHeuristic(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) : id(id), expand(false), lowerBound(storm::utility::zero()), upperBound(storm::utility::infinity()), depth(predecessor.depth + 1), probability(storm::utility::zero()) { this->updateHeuristicValues(predecessor, rate, exitRate); } diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index 13647880e..f9e4b54f6 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -191,7 +191,8 @@ namespace storm { break; case storm::builder::ApproximationHeuristic::PROBABILITY: case storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE: - approximationThreshold = 10 * std::pow(2, iteration); + double exponent = iteration; // Need conversion to avoid overflow when negating + approximationThreshold = std::pow(2, -exponent); break; } } @@ -646,7 +647,7 @@ namespace storm { STORM_LOG_ASSERT(!it->second.first->isPseudoState(), "State is still pseudo state."); ExplorationHeuristicPointer heuristic = it->second.second; - if (storm::utility::isZero(heuristic->getUpperBound())) { + if (storm::utility::isInfinity(heuristic->getUpperBound())) { // Initialize bounds ValueType lowerBound = getLowerBound(it->second.first); ValueType upperBound = getUpperBound(it->second.first); @@ -669,6 +670,7 @@ namespace storm { for (state->getFailableElements().init(false); !state->getFailableElements().isEnd(); state->getFailableElements().next()) { lowerBound += state->getBERate(state->getFailableElements().get()); } + STORM_LOG_TRACE("Lower bound is " << lowerBound << " for state " << state->getId()); return lowerBound; } From 7b4a51effefcc7479b74dc70b5673af3cf4e2db9 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 19 Mar 2019 11:28:14 +0100 Subject: [PATCH 07/40] Removed approximation heuristic NONE --- .../builder/DftExplorationHeuristic.cpp | 2 -- .../builder/DftExplorationHeuristic.h | 26 +------------------ .../builder/ExplicitDFTModelBuilder.cpp | 10 ------- .../settings/modules/FaultTreeSettings.cpp | 12 +++------ src/storm-dft/storage/BucketPriorityQueue.cpp | 2 -- 5 files changed, 4 insertions(+), 48 deletions(-) diff --git a/src/storm-dft/builder/DftExplorationHeuristic.cpp b/src/storm-dft/builder/DftExplorationHeuristic.cpp index 43b3ad96b..dcb031f2a 100644 --- a/src/storm-dft/builder/DftExplorationHeuristic.cpp +++ b/src/storm-dft/builder/DftExplorationHeuristic.cpp @@ -30,14 +30,12 @@ namespace storm { // Instantiate templates. template class DFTExplorationHeuristic; - template class DFTExplorationHeuristicNone; template class DFTExplorationHeuristicDepth; template class DFTExplorationHeuristicProbability; template class DFTExplorationHeuristicBoundDifference; #ifdef STORM_HAVE_CARL template class DFTExplorationHeuristic; - template class DFTExplorationHeuristicNone; template class DFTExplorationHeuristicDepth; template class DFTExplorationHeuristicProbability; template class DFTExplorationHeuristicBoundDifference; diff --git a/src/storm-dft/builder/DftExplorationHeuristic.h b/src/storm-dft/builder/DftExplorationHeuristic.h index de4b5cfc5..b0fd73a66 100644 --- a/src/storm-dft/builder/DftExplorationHeuristic.h +++ b/src/storm-dft/builder/DftExplorationHeuristic.h @@ -12,7 +12,7 @@ namespace storm { /*! * Enum representing the heuristic used for deciding which states to expand. */ - enum class ApproximationHeuristic { NONE, DEPTH, PROBABILITY, BOUNDDIFFERENCE }; + enum class ApproximationHeuristic { DEPTH, PROBABILITY, BOUNDDIFFERENCE }; /*! @@ -90,30 +90,6 @@ namespace storm { ValueType probability; }; - template - class DFTExplorationHeuristicNone : public DFTExplorationHeuristic { - public: - DFTExplorationHeuristicNone(size_t id) : DFTExplorationHeuristic(id) { - // Intentionally left empty - } - - DFTExplorationHeuristicNone(size_t id, DFTExplorationHeuristic const& predecessor, ValueType rate, ValueType exitRate) : DFTExplorationHeuristic(id, predecessor, rate, exitRate) { - // Intentionally left empty - } - - bool updateHeuristicValues(DFTExplorationHeuristic const&, ValueType, ValueType) override { - return false; - } - - double getPriority() const override { - return 0; - } - - bool isSkip(double) const override { - return false; - } - }; - template class DFTExplorationHeuristicDepth : public DFTExplorationHeuristic { public: diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index f9e4b54f6..922f680e9 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -160,9 +160,6 @@ namespace storm { STORM_LOG_ASSERT(!statesNotExplored.at(initialStateIndex).second, "Heuristic for initial state is already initialized"); ExplorationHeuristicPointer heuristic; switch (usedHeuristic) { - case storm::builder::ApproximationHeuristic::NONE: - heuristic = std::make_shared>(initialStateIndex); - break; case storm::builder::ApproximationHeuristic::DEPTH: heuristic = std::make_shared>(initialStateIndex); break; @@ -182,10 +179,6 @@ namespace storm { if (approximationThreshold > 0.0) { switch (usedHeuristic) { - case storm::builder::ApproximationHeuristic::NONE: - // Do not change anything - approximationThreshold = dft.nrElements()+10; - break; case storm::builder::ApproximationHeuristic::DEPTH: approximationThreshold = iteration + 1; break; @@ -397,9 +390,6 @@ namespace storm { // Initialize heuristic values ExplorationHeuristicPointer heuristic; switch (usedHeuristic) { - case storm::builder::ApproximationHeuristic::NONE: - heuristic = std::make_shared>(stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass()); - break; case storm::builder::ApproximationHeuristic::DEPTH: heuristic = std::make_shared>(stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass()); break; diff --git a/src/storm-dft/settings/modules/FaultTreeSettings.cpp b/src/storm-dft/settings/modules/FaultTreeSettings.cpp index a110ea0a7..740c6aa54 100644 --- a/src/storm-dft/settings/modules/FaultTreeSettings.cpp +++ b/src/storm-dft/settings/modules/FaultTreeSettings.cpp @@ -32,9 +32,9 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, firstDependencyOptionName, false, "Avoid non-determinism by always taking the first possible dependency.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, approximationErrorOptionName, false, "Approximation error allowed.").setShortName(approximationErrorOptionShortName).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("error", "The relative approximation error to use.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterEqualValidator(0.0)).build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, approximationHeuristicOptionName, false, "Set the heuristic used for approximation.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("heuristic", "Sets which heuristic is used for approximation. Must be in {none, depth, probability, bounddifference}. Default is") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("heuristic", "The name of the heuristic used for approximation.") .setDefaultValueString("depth") - .addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator({"none", "depth", "probability", "bounddifference"})).build()).build()); + .addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator({"depth", "probability", "bounddifference"})).build()).build()); #ifdef STORM_HAVE_Z3 this->addOption(storm::settings::OptionBuilder(moduleName, solveWithSmtOptionName, true, "Solve the DFT with SMT.").build()); #endif @@ -61,14 +61,8 @@ namespace storm { } storm::builder::ApproximationHeuristic FaultTreeSettings::getApproximationHeuristic() const { - if (!isApproximationErrorSet() || getApproximationError() == 0.0) { - // No approximation is done - return storm::builder::ApproximationHeuristic::NONE; - } std::string heuristicAsString = this->getOption(approximationHeuristicOptionName).getArgumentByName("heuristic").getValueAsString(); - if (heuristicAsString == "none") { - return storm::builder::ApproximationHeuristic::NONE; - } else if (heuristicAsString == "depth") { + if (heuristicAsString == "depth") { return storm::builder::ApproximationHeuristic::DEPTH; } else if (heuristicAsString == "probability") { return storm::builder::ApproximationHeuristic::PROBABILITY; diff --git a/src/storm-dft/storage/BucketPriorityQueue.cpp b/src/storm-dft/storage/BucketPriorityQueue.cpp index a0926e70c..3ce3659b5 100644 --- a/src/storm-dft/storage/BucketPriorityQueue.cpp +++ b/src/storm-dft/storage/BucketPriorityQueue.cpp @@ -198,14 +198,12 @@ namespace storm { // Template instantiations template class BucketPriorityQueue>; - template class BucketPriorityQueue>; template class BucketPriorityQueue>; template class BucketPriorityQueue>; template class BucketPriorityQueue>; #ifdef STORM_HAVE_CARL template class BucketPriorityQueue>; - template class BucketPriorityQueue>; template class BucketPriorityQueue>; template class BucketPriorityQueue>; template class BucketPriorityQueue>; From a410b6d7bc26235a886fde3f46b14cd9658b3f2d Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 19 Mar 2019 14:45:30 +0100 Subject: [PATCH 08/40] Heuristic is argument for functions in approximation algorithm --- src/storm-dft-cli/storm-dft.cpp | 2 +- src/storm-dft/api/storm-dft.h | 5 +- .../builder/ExplicitDFTModelBuilder.cpp | 4 +- .../builder/ExplicitDFTModelBuilder.h | 7 ++- .../modelchecker/dft/DFTModelChecker.cpp | 16 +++--- .../modelchecker/dft/DFTModelChecker.h | 56 ++++++++++--------- 6 files changed, 46 insertions(+), 44 deletions(-) diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index f6a7d3863..eb4b1b837 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -126,7 +126,7 @@ void processOptions() { if (faultTreeSettings.isApproximationErrorSet()) { // Approximate analysis storm::api::analyzeDFTApprox(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), - faultTreeSettings.getApproximationError(), true); + faultTreeSettings.getApproximationError(), faultTreeSettings.getApproximationHeuristic(), true); } else { storm::api::analyzeDFT(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), true); } diff --git a/src/storm-dft/api/storm-dft.h b/src/storm-dft/api/storm-dft.h index 8b4f0ae9c..e960fb69c 100644 --- a/src/storm-dft/api/storm-dft.h +++ b/src/storm-dft/api/storm-dft.h @@ -101,10 +101,9 @@ namespace storm { template typename storm::modelchecker::DFTModelChecker::dft_results analyzeDFTApprox(storm::storage::DFT const& dft, std::vector> const& properties, bool symred, - bool allowModularisation, bool enableDC, double approximationError, bool printOutput) { + bool allowModularisation, bool enableDC, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic, bool printOutput) { storm::modelchecker::DFTModelChecker modelChecker(printOutput); - typename storm::modelchecker::DFTModelChecker::dft_results results = modelChecker.check(dft, properties, symred, allowModularisation, enableDC, - approximationError); + typename storm::modelchecker::DFTModelChecker::dft_results results = modelChecker.check(dft, properties, symred, allowModularisation, enableDC, approximationError, approximationHeuristic); if (printOutput) { modelChecker.printTimings(); modelChecker.printResults(); diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index 922f680e9..298936440 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -56,7 +56,6 @@ namespace storm { dft(dft), stateGenerationInfo(std::make_shared(dft.buildStateGenerationInfo(symmetries))), enableDC(enableDC), - usedHeuristic(storm::settings::getModule().getApproximationHeuristic()), generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates), matrixBuilder(!generator.isDeterministicModel()), stateStorage(dft.stateBitVectorSize()), @@ -120,8 +119,9 @@ namespace storm { } template - void ExplicitDFTModelBuilder::buildModel(LabelOptions const& labelOpts, size_t iteration, double approximationThreshold) { + void ExplicitDFTModelBuilder::buildModel(LabelOptions const& labelOpts, size_t iteration, double approximationThreshold, storm::builder::ApproximationHeuristic approximationHeuristic) { STORM_LOG_TRACE("Generating DFT state space"); + usedHeuristic = approximationHeuristic; if (iteration < 1) { // Initialize diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.h b/src/storm-dft/builder/ExplicitDFTModelBuilder.h index 9858000ec..379918f9b 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.h +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.h @@ -181,11 +181,12 @@ namespace storm { /*! * Build model from DFT. * - * @param labelOpts Options for labeling. - * @param iteration Current number of iteration. + * @param labelOpts Options for labeling. + * @param iteration Current number of iteration. * @param approximationThreshold Threshold determining when to skip exploring states. + * @param approximationHeuristic Heuristic used for exploring states. */ - void buildModel(LabelOptions const& labelOpts, size_t iteration, double approximationThreshold = 0.0); + void buildModel(LabelOptions const& labelOpts, size_t iteration, double approximationThreshold = 0.0, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); /*! * Get the built model. diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp index d96aacfc4..467125c35 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp @@ -17,7 +17,7 @@ namespace storm { namespace modelchecker { template - typename DFTModelChecker::dft_results DFTModelChecker::check(storm::storage::DFT const& origDft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError) { + typename DFTModelChecker::dft_results DFTModelChecker::check(storm::storage::DFT const& origDft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { // Initialize this->approximationError = approximationError; totalTimer.start(); @@ -30,21 +30,21 @@ namespace storm { // Checking DFT if (properties[0]->isTimeOperatorFormula() && allowModularisation) { // Use parallel composition as modularisation approach for expected time - std::shared_ptr> model = buildModelViaComposition(dft, properties, symred, true, enableDC, approximationError); + std::shared_ptr> model = buildModelViaComposition(dft, properties, symred, true, enableDC); // Model checking std::vector resultsValue = checkModel(model, properties); for (ValueType result : resultsValue) { checkResults.push_back(result); } } else { - checkResults = checkHelper(dft, properties, symred, allowModularisation, enableDC, approximationError); + checkResults = checkHelper(dft, properties, symred, allowModularisation, enableDC, approximationError, approximationHeuristic); } totalTimer.stop(); return checkResults; } template - typename DFTModelChecker::dft_results DFTModelChecker::checkHelper(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError) { + typename DFTModelChecker::dft_results DFTModelChecker::checkHelper(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { STORM_LOG_TRACE("Check helper called"); std::vector> dfts; bool invResults = false; @@ -138,12 +138,12 @@ namespace storm { return results; } else { // No modularisation was possible - return checkDFT(dft, properties, symred, enableDC, approximationError); + return checkDFT(dft, properties, symred, enableDC, approximationError, approximationHeuristic); } } template - std::shared_ptr> DFTModelChecker::buildModelViaComposition(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError) { + std::shared_ptr> DFTModelChecker::buildModelViaComposition(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, bool enableDC) { // TODO Matthias: use approximation? STORM_LOG_TRACE("Build model via composition"); std::vector> dfts; @@ -258,7 +258,7 @@ namespace storm { } template - typename DFTModelChecker::dft_results DFTModelChecker::checkDFT(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool enableDC, double approximationError) { + typename DFTModelChecker::dft_results DFTModelChecker::checkDFT(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool enableDC, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { explorationTimer.start(); // Find symmetries @@ -297,7 +297,7 @@ namespace storm { } STORM_LOG_DEBUG("Building model..."); // TODO Matthias refine model using existing model and MC results - builder.buildModel(labeloptions, iteration, approximationError); + builder.buildModel(labeloptions, iteration, approximationError, approximationHeuristic); explorationTimer.stop(); buildingTimer.start(); diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.h b/src/storm-dft/modelchecker/dft/DFTModelChecker.h index cf05cbb8f..56d1b4fad 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.h +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.h @@ -31,16 +31,17 @@ namespace storm { /*! * Main method for checking DFTs. * - * @param origDft Original DFT - * @param properties Properties to check for - * @param symred Flag indicating if symmetry reduction should be used - * @param allowModularisation Flag indication if modularisation is allowed - * @param enableDC Flag indicating if dont care propagation should be used - * @param approximationError Error allowed for approximation. Value 0 indicates no approximation + * @param origDft Original DFT. + * @param properties Properties to check for. + * @param symred Flag indicating if symmetry reduction should be used. + * @param allowModularisation Flag indicating if modularisation is allowed. + * @param enableDC Flag indicating if Don't Care propagation should be used. + * @param approximationError Error allowed for approximation. Value 0 indicates no approximation. + * @param approximationHeuristic Heuristic used for approximation. * * @return Model checking results for the given properties. */ - dft_results check(storm::storage::DFT const& origDft, property_vector const& properties, bool symred = true, bool allowModularisation = true, bool enableDC = true, double approximationError = 0.0); + dft_results check(storm::storage::DFT const& origDft, property_vector const& properties, bool symred = true, bool allowModularisation = true, bool enableDC = true, double approximationError = 0.0, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); /*! * Print timings of all operations to stream. @@ -76,43 +77,44 @@ namespace storm { /*! * Internal helper for model checking a DFT. * - * @param dft DFT - * @param properties Properties to check for - * @param symred Flag indicating if symmetry reduction should be used - * @param allowModularisation Flag indication if modularisation is allowed - * @param enableDC Flag indicating if dont care propagation should be used - * @param approximationError Error allowed for approximation. Value 0 indicates no approximation + * @param dft DFT. + * @param properties Properties to check for. + * @param symred Flag indicating if symmetry reduction should be used. + * @param allowModularisation Flag indicating if modularisation is allowed. + * @param enableDC Flag indicating if Don't Caree propagation should be used. + * @param approximationError Error allowed for approximation. Value 0 indicates no approximation. + * @param approximationHeuristic Heuristic used for approximation. * * @return Model checking results (or in case of approximation two results for lower and upper bound) */ - dft_results checkHelper(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError); + dft_results checkHelper(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); /*! * Internal helper for building a CTMC from a DFT via parallel composition. * - * @param dft DFT - * @param properties Properties to check for - * @param symred Flag indicating if symmetry reduction should be used - * @param allowModularisation Flag indication if modularisation is allowed - * @param enableDC Flag indicating if dont care propagation should be used - * @param approximationError Error allowed for approximation. Value 0 indicates no approximation + * @param dft DFT. + * @param properties Properties to check for. + * @param symred Flag indicating if symmetry reduction should be used. + * @param allowModularisation Flag indicating if modularisation is allowed. + * @param enableDC Flag indicating if Don't Care propagation should be used. * * @return CTMC representing the DFT */ - std::shared_ptr> buildModelViaComposition(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError); + std::shared_ptr> buildModelViaComposition(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, bool enableDC); /*! * Check model generated from DFT. * - * @param dft The DFT - * @param properties Properties to check for - * @param symred Flag indicating if symmetry reduction should be used - * @param enableDC Flag indicating if dont care propagation should be used - * @param approximationError Error allowed for approximation. Value 0 indicates no approximation + * @param dft The DFT. + * @param properties Properties to check for. + * @param symred Flag indicating if symmetry reduction should be used. + * @param enableDC Flag indicating if Don't Care propagation should be used. + * @param approximationError Error allowed for approximation. Value 0 indicates no approximation. + * @param approximationHeuristic Heuristic used for approximation. * * @return Model checking result */ - dft_results checkDFT(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool enableDC, double approximationError = 0.0); + dft_results checkDFT(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool enableDC, double approximationError = 0.0, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); /*! * Check the given markov model for the given properties. From 23233afe0b677dcf6db0bd1dc2bcac40b36ad69e Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 19 Mar 2019 14:46:25 +0100 Subject: [PATCH 09/40] Added test cases for DFT approximation --- .../examples/testfiles/dft/hecs_3_2_2_np.dft | 71 ++++++++++++ .../storm-dft/api/DftApproximationTest.cpp | 103 ++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 resources/examples/testfiles/dft/hecs_3_2_2_np.dft create mode 100644 src/test/storm-dft/api/DftApproximationTest.cpp diff --git a/resources/examples/testfiles/dft/hecs_3_2_2_np.dft b/resources/examples/testfiles/dft/hecs_3_2_2_np.dft new file mode 100644 index 000000000..f1c73a649 --- /dev/null +++ b/resources/examples/testfiles/dft/hecs_3_2_2_np.dft @@ -0,0 +1,71 @@ +toplevel "n58"; +"n58" 2of3 "n1" "n48" "n60"; +"n60" or "n233" "n308" "n263" "n57"; +"n308" wsp "n310" "n45"; +"n48" or "n235" "n287" "n271" "n64"; +"n287" wsp "n289" "n66"; +"n64" 3of5 "n248" "n254" "n252" "n255" "n246"; +"n254" or "n59" "n6"; +"n255" or "n24" "n70"; +"n246" or "n22" "n62"; +"n62" and "n6" "n70"; +"n263" wsp "n261" "n306" "n5"; +"n271" wsp "n269" "n302" "n34"; +"n57" 3of5 "n250" "n253" "n260" "n249" "n257"; +"n249" or "n8" "n0"; +"n257" or "n15" "n40"; +"n40" and "n0" "n23"; +"n250" or "n61" "n23"; +"n260" or "n46" "n0"; +"n248" or "n9" "n6"; +"n1" or "n234" "n296" "n267" "n68"; +"n267" wsp "n265" "n294" "n3"; +"n296" wsp "n298" "n69"; +"n68" 3of5 "n247" "n251" "n256" "n259" "n258"; +"n251" or "n47" "n53"; +"n247" or "n49" "n53"; +"n258" or "n20" "n4"; +"n4" and "n67" "n53"; +"n256" or "n10" "n67"; +"n253" or "n36" "n23"; +"n259" or "n78" "n67"; +"n252" or "n33" "n70"; +"n233" lambda=0.0010999999999999998 dorm=0.0; +"n45" lambda=1.0E-5 dorm=0.0; +"n310" lambda=2.0E-5 dorm=0.0; +"n235" lambda=0.0010999999999999998 dorm=0.0; +"n24" lambda=6.0E-4 dorm=0.0; +"n22" lambda=6.0E-4 dorm=0.0; +"n5" lambda=0.001 dorm=0.0; +"n306" lambda=0.002 dorm=0.0; +"n261" lambda=0.002 dorm=0.0; +"n34" lambda=0.001 dorm=0.0; +"n302" lambda=0.002 dorm=0.0; +"n8" lambda=6.0E-4 dorm=0.0; +"n15" lambda=6.0E-4 dorm=0.0; +"n61" lambda=6.0E-4 dorm=0.0; +"n269" lambda=0.002 dorm=0.0; +"n59" lambda=6.0E-4 dorm=0.0; +"n289" lambda=2.0E-5 dorm=0.0; +"n46" lambda=6.0E-4 dorm=0.0; +"n0" lambda=5.0E-4 dorm=0.0; +"n6" lambda=5.0E-4 dorm=0.0; +"n9" lambda=6.0E-4 dorm=0.0; +"n234" lambda=0.0010999999999999998 dorm=0.0; +"n3" lambda=0.001 dorm=0.0; +"n265" lambda=0.002 dorm=0.0; +"n298" lambda=2.0E-5 dorm=0.0; +"n47" lambda=6.0E-4 dorm=0.0; +"n49" lambda=6.0E-4 dorm=0.0; +"n53" lambda=5.0E-4 dorm=0.0; +"n10" lambda=6.0E-4 dorm=0.0; +"n23" lambda=5.0E-4 dorm=0.0; +"n36" lambda=6.0E-4 dorm=0.0; +"n78" lambda=6.0E-4 dorm=0.0; +"n67" lambda=5.0E-4 dorm=0.0; +"n66" lambda=1.0E-5 dorm=0.0; +"n20" lambda=6.0E-4 dorm=0.0; +"n69" lambda=1.0E-5 dorm=0.0; +"n70" lambda=5.0E-4 dorm=0.0; +"n33" lambda=6.0E-4 dorm=0.0; +"n294" lambda=0.002 dorm=0.0; diff --git a/src/test/storm-dft/api/DftApproximationTest.cpp b/src/test/storm-dft/api/DftApproximationTest.cpp new file mode 100644 index 000000000..f552fa608 --- /dev/null +++ b/src/test/storm-dft/api/DftApproximationTest.cpp @@ -0,0 +1,103 @@ +#include "gtest/gtest.h" +#include "storm-config.h" + +#include "storm-dft/api/storm-dft.h" +#include "storm-parsers/api/storm-parsers.h" + +namespace { + + // Configurations for DFT approximation + struct DftAnalysisConfig { + storm::builder::ApproximationHeuristic heuristic; + bool useSR; + }; + + class ApproxDepthConfig { + public: + typedef double ValueType; + static DftAnalysisConfig createConfig() { + return DftAnalysisConfig {storm::builder::ApproximationHeuristic::DEPTH, false}; + } + }; + class ApproxProbabilityConfig { + public: + typedef double ValueType; + static DftAnalysisConfig createConfig() { + return DftAnalysisConfig {storm::builder::ApproximationHeuristic::PROBABILITY, false}; + } + }; + class ApproxBoundDifferenceConfig { + public: + typedef double ValueType; + static DftAnalysisConfig createConfig() { + return DftAnalysisConfig {storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE, false}; + } + }; + + // General base class for testing of DFT approximation + template + class DftApproximationTest : public ::testing::Test { + public: + typedef typename TestType::ValueType ValueType; + + DftApproximationTest() : config(TestType::createConfig()) { + } + + DftApproximationTest const& getConfig() const { + return config; + } + + std::pair analyzeMTTF(std::string const& file, double errorBound) { + std::shared_ptr> dft = storm::api::loadDFTGalileoFile(file); + EXPECT_TRUE(storm::api::isWellFormed(*dft)); + std::string property = "T=? [F \"failed\"]"; + std::vector> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(property)); + typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFTApprox(*dft, properties, config.useSR, false, true, errorBound, config.heuristic, false); + return boost::get::approximation_result>(results[0]); + } + + std::pair analyzeTimebound(std::string const& file, double timeBound, double errorBound) { + std::shared_ptr> dft = storm::api::loadDFTGalileoFile(file); + EXPECT_TRUE(storm::api::isWellFormed(*dft)); + std::stringstream propertyStream; + propertyStream << "P=? [F<=" << timeBound << " \"failed\"]"; + std::vector> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(propertyStream.str())); + typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFTApprox(*dft, properties, config.useSR, false, true, errorBound, config.heuristic, false); + return boost::get::approximation_result>(results[0]); + } + + private: + DftAnalysisConfig config; + }; + + typedef ::testing::Types< + ApproxDepthConfig, + ApproxProbabilityConfig, + ApproxBoundDifferenceConfig + > TestingTypes; + + TYPED_TEST_CASE(DftApproximationTest, TestingTypes); + + TYPED_TEST(DftApproximationTest, HecsMTTF) { + double errorBound = 2; + std::pair approxResult = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/hecs_3_2_2_np.dft", errorBound); + EXPECT_LE(approxResult.first, 417.9436693); + EXPECT_GE(approxResult.second, 417.9436693); + EXPECT_LE(2*(approxResult.second - approxResult.first) / (approxResult.first + approxResult.second), errorBound); + // Ensure results are not equal -> not exact values were computed + EXPECT_GE(approxResult.second - approxResult.first, errorBound * approxResult.first / 10); + } + + TYPED_TEST(DftApproximationTest, HecsTimebound) { + //double errorBound = 0.01; + double errorBound = 0.5; + double timeBound = 100; + std::pair approxResult = this->analyzeTimebound(STORM_TEST_RESOURCES_DIR "/dft/hecs_3_2_2_np.dft", timeBound, errorBound); + EXPECT_LE(approxResult.first, 0.0410018417); + EXPECT_GE(approxResult.second, 0.0410018417); + EXPECT_LE(approxResult.second - approxResult.first, errorBound); + // Ensure results are not equal -> not exact values were computed + EXPECT_GE(approxResult.second - approxResult.first, errorBound / 10); + } + +} From 2c1855f69ae8c82fca1e638e067dda38e7d19716 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 19 Mar 2019 16:23:52 +0100 Subject: [PATCH 10/40] Removed unnecessary members --- src/storm-dft/api/storm-dft.h | 4 +-- .../modelchecker/dft/DFTModelChecker.cpp | 25 +++++++------------ .../modelchecker/dft/DFTModelChecker.h | 25 +++++++++++++------ 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/storm-dft/api/storm-dft.h b/src/storm-dft/api/storm-dft.h index e960fb69c..6cd701e83 100644 --- a/src/storm-dft/api/storm-dft.h +++ b/src/storm-dft/api/storm-dft.h @@ -80,7 +80,7 @@ namespace storm { typename storm::modelchecker::DFTModelChecker::dft_results results = modelChecker.check(dft, properties, symred, allowModularisation, enableDC, 0.0); if (printOutput) { modelChecker.printTimings(); - modelChecker.printResults(); + modelChecker.printResults(results); } return results; } @@ -106,7 +106,7 @@ namespace storm { typename storm::modelchecker::DFTModelChecker::dft_results results = modelChecker.check(dft, properties, symred, allowModularisation, enableDC, approximationError, approximationHeuristic); if (printOutput) { modelChecker.printTimings(); - modelChecker.printResults(); + modelChecker.printResults(results); } return results; } diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp index 467125c35..c76495177 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp @@ -18,9 +18,8 @@ namespace storm { template typename DFTModelChecker::dft_results DFTModelChecker::check(storm::storage::DFT const& origDft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { - // Initialize - this->approximationError = approximationError; totalTimer.start(); + dft_results results; // Optimizing DFT storm::storage::DFT dft = origDft.optimize(); @@ -34,13 +33,13 @@ namespace storm { // Model checking std::vector resultsValue = checkModel(model, properties); for (ValueType result : resultsValue) { - checkResults.push_back(result); + results.push_back(result); } } else { - checkResults = checkHelper(dft, properties, symred, allowModularisation, enableDC, approximationError, approximationHeuristic); + results = checkHelper(dft, properties, symred, allowModularisation, enableDC, approximationError, approximationHeuristic); } totalTimer.stop(); - return checkResults; + return results; } template @@ -442,22 +441,16 @@ namespace storm { } template - void DFTModelChecker::printResults(std::ostream& os) { + void DFTModelChecker::printResults(dft_results const& results, std::ostream& os) { bool first = true; os << "Result: ["; - for (auto result : checkResults) { - if (!first) { - os << ", "; - } - if (this->approximationError > 0.0) { - approximation_result resultApprox = boost::get(result); - os << "(" << resultApprox.first << ", " << resultApprox.second << ")"; - } else { - os << boost::get(result); - } + for (auto result : results) { if (first) { first = false; + } else { + os << ", "; } + os << boost::apply_visitor(ResultOutputVisitor(), result); } os << "]" << std::endl; } diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.h b/src/storm-dft/modelchecker/dft/DFTModelChecker.h index 56d1b4fad..7bc07e30e 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.h +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.h @@ -22,6 +22,22 @@ namespace storm { typedef std::vector> dft_results; typedef std::vector> property_vector; + class ResultOutputVisitor : public boost::static_visitor { + public: + std::string operator()(ValueType result) const { + std::stringstream stream; + stream << result; + return stream.str(); + } + + std::string operator()(std::pair const& result) const { + std::stringstream stream; + stream << "(" << result.first << ", " << result.second << ")"; + return stream.str(); + } + + }; + /*! * Constructor. */ @@ -53,9 +69,10 @@ namespace storm { /*! * Print result to stream. * + * @param results List of results. * @param os Output stream to write to. */ - void printResults(std::ostream& os = std::cout); + void printResults(dft_results const& results, std::ostream& os = std::cout); private: @@ -68,12 +85,6 @@ namespace storm { storm::utility::Stopwatch modelCheckingTimer; storm::utility::Stopwatch totalTimer; - // Model checking results - dft_results checkResults; - - // Allowed error bound for approximation - double approximationError; - /*! * Internal helper for model checking a DFT. * From 01461bbf574416eedfdb9d1f8d1ed633a74a63a0 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 22 Mar 2019 10:15:37 +0100 Subject: [PATCH 11/40] Throw exception instead of assertion --- src/storm-dft/builder/DFTBuilder.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/storm-dft/builder/DFTBuilder.cpp b/src/storm-dft/builder/DFTBuilder.cpp index 87bd5f407..3bc2cf71b 100644 --- a/src/storm-dft/builder/DFTBuilder.cpp +++ b/src/storm-dft/builder/DFTBuilder.cpp @@ -36,8 +36,8 @@ namespace storm { // 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_THROW(itFind != mElements.end(), storm::exceptions::WrongFormatException, "Child '" << child << "' for gate '" << gate->name() << "' not found."); + STORM_LOG_THROW(itFind->second->isDependency(), storm::exceptions::WrongFormatException, "Child '" << child << "'is no dependency."); STORM_LOG_TRACE("Ignore functional dependency " << child << " in gate " << gate->name()); } } @@ -47,7 +47,7 @@ namespace storm { for(auto& elem : mRestrictionChildNames) { for(auto const& childName : elem.second) { auto itFind = mElements.find(childName); - STORM_LOG_ASSERT(itFind != mElements.end(), "Child not found."); + STORM_LOG_THROW(itFind != mElements.end(), storm::exceptions::WrongFormatException, "Child '" << childName << "' for gate '" << elem.first->name() << "' not found."); DFTElementPointer childElement = itFind->second; STORM_LOG_THROW(childElement->isGate() || childElement->isBasicElement(), storm::exceptions::WrongFormatException, "Child '" << childElement->name() << "' of restriction '" << elem.first->name() << "' must be gate or BE."); elem.first->pushBackChild(childElement); @@ -61,7 +61,7 @@ namespace storm { std::vector>> dependencies; for(auto const& childName : elem.second) { auto itFind = mElements.find(childName); - STORM_LOG_ASSERT(itFind != mElements.end(), "Child '" << childName << "' not found"); + STORM_LOG_THROW(itFind != mElements.end(), storm::exceptions::WrongFormatException, "Child '" << childName << "' for gate '" << elem.first->name() << "' not found."); DFTElementPointer childElement = itFind->second; if (!first) { STORM_LOG_THROW(childElement->isBasicElement(), storm::exceptions::WrongFormatException, "Child '" << childName << "' of dependency '" << elem.first->name() << "' must be BE."); From bd3e062988071a6dc3824da3e4b1407d032451df Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 22 Mar 2019 18:58:34 +0100 Subject: [PATCH 12/40] Added default case for switch --- src/storm-dft/builder/ExplicitDFTModelBuilder.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index 298936440..2ecabe6e4 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -1,6 +1,7 @@ #include "ExplicitDFTModelBuilder.h" #include +#include #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/models/sparse/Ctmc.h" @@ -169,6 +170,8 @@ namespace storm { case storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE: heuristic = std::make_shared>(initialStateIndex); break; + default: + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Heuristic not known."); } heuristic->markExpand(); statesNotExplored[initialStateIndex].second = heuristic; @@ -184,9 +187,10 @@ namespace storm { break; case storm::builder::ApproximationHeuristic::PROBABILITY: case storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE: - double exponent = iteration; // Need conversion to avoid overflow when negating - approximationThreshold = std::pow(2, -exponent); + approximationThreshold = std::pow(2, -(double)iteration); // Need conversion to avoid overflow when negating break; + default: + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Heuristic not known."); } } exploreStateSpace(approximationThreshold); @@ -399,6 +403,8 @@ namespace storm { case storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE: heuristic = std::make_shared>(stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass()); break; + default: + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Heuristic not known."); } iter->second.second = heuristic; From f2e9d20a8de8b921c8d45ca39b563ad2f48dc4c7 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 22 Mar 2019 19:04:01 +0100 Subject: [PATCH 13/40] Set correct order for priorities according to heuristic --- .../builder/ExplicitDFTModelBuilder.cpp | 16 ++++++++++++++-- src/storm-dft/storage/BucketPriorityQueue.cpp | 2 +- src/storm-dft/storage/BucketPriorityQueue.h | 16 +++++++++------- src/test/storm-dft/api/DftApproximationTest.cpp | 2 +- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index 2ecabe6e4..eb7d50e06 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -60,8 +60,7 @@ namespace storm { generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates), matrixBuilder(!generator.isDeterministicModel()), stateStorage(dft.stateBitVectorSize()), - //explorationQueue(dft.nrElements()+1, 0, 1) - explorationQueue(200, 0, 0.9, false) + explorationQueue(1, 0, 0.9, false) { // Compute independent subtrees if (dft.topLevelType() == storm::storage::DFTElementType::OR) { @@ -126,6 +125,19 @@ namespace storm { if (iteration < 1) { // Initialize + switch (usedHeuristic) { + case storm::builder::ApproximationHeuristic::DEPTH: + explorationQueue = storm::storage::BucketPriorityQueue(dft.nrElements()+1, 0, 0.9, false); + break; + case storm::builder::ApproximationHeuristic::PROBABILITY: + explorationQueue = storm::storage::BucketPriorityQueue(200, 0, 0.9, true); + break; + case storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE: + explorationQueue = storm::storage::BucketPriorityQueue(200, 0, 0.9, true); + break; + default: + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Heuristic not known."); + } modelComponents.markovianStates = storm::storage::BitVector(INITIAL_BITVECTOR_SIZE); if(mergeFailedStates) { diff --git a/src/storm-dft/storage/BucketPriorityQueue.cpp b/src/storm-dft/storage/BucketPriorityQueue.cpp index 3ce3659b5..ceafc00fb 100644 --- a/src/storm-dft/storage/BucketPriorityQueue.cpp +++ b/src/storm-dft/storage/BucketPriorityQueue.cpp @@ -87,7 +87,7 @@ namespace storm { } } else { // Move to new bucket - STORM_LOG_ASSERT(newBucket < oldBucket, "Will update to higher bucket"); + STORM_LOG_ASSERT(newBucket < oldBucket, "Will update item "<< item->getId() << " from " << oldBucket << " to higher bucket " << newBucket); if (newBucket < currentBucket) { currentBucket = newBucket; nrUnsortedItems = 0; diff --git a/src/storm-dft/storage/BucketPriorityQueue.h b/src/storm-dft/storage/BucketPriorityQueue.h index 2c0c3cb37..51a2ec94c 100644 --- a/src/storm-dft/storage/BucketPriorityQueue.h +++ b/src/storm-dft/storage/BucketPriorityQueue.h @@ -30,6 +30,10 @@ namespace storm { */ explicit BucketPriorityQueue(size_t nrBuckets, double lowerValue, double ratio, bool higher); + BucketPriorityQueue(BucketPriorityQueue const& queue) = default; + + virtual ~BucketPriorityQueue() = default; + void fix(); /*! @@ -106,18 +110,16 @@ namespace storm { std::function compare; // Minimal value - const double lowerValue; + double lowerValue; - const bool higher; + bool higher; - const bool AUTOSORT = false; + bool AUTOSORT = false; - const double logBase; + double logBase; // Number of available buckets - const size_t nrBuckets; - - + size_t nrBuckets; }; diff --git a/src/test/storm-dft/api/DftApproximationTest.cpp b/src/test/storm-dft/api/DftApproximationTest.cpp index f552fa608..d00973da1 100644 --- a/src/test/storm-dft/api/DftApproximationTest.cpp +++ b/src/test/storm-dft/api/DftApproximationTest.cpp @@ -90,7 +90,7 @@ namespace { TYPED_TEST(DftApproximationTest, HecsTimebound) { //double errorBound = 0.01; - double errorBound = 0.5; + double errorBound = 0.1; double timeBound = 100; std::pair approxResult = this->analyzeTimebound(STORM_TEST_RESOURCES_DIR "/dft/hecs_3_2_2_np.dft", timeBound, errorBound); EXPECT_LE(approxResult.first, 0.0410018417); From 87180e1000dec45452b5b35b89bc54909cfcecf6 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Sun, 24 Mar 2019 18:05:21 +0100 Subject: [PATCH 14/40] Correct initialization of priority queue --- .../generator/DftNextStateGenerator.cpp | 32 ++++++++++++------- .../generator/DftNextStateGenerator.h | 4 ++- src/storm-dft/storage/dft/DFTState.cpp | 10 +++--- src/storm-dft/storage/dft/DFTState.h | 3 +- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/storm-dft/generator/DftNextStateGenerator.cpp b/src/storm-dft/generator/DftNextStateGenerator.cpp index 2a3502c5e..69751ea62 100644 --- a/src/storm-dft/generator/DftNextStateGenerator.cpp +++ b/src/storm-dft/generator/DftNextStateGenerator.cpp @@ -46,16 +46,19 @@ namespace storm { template StateBehavior DftNextStateGenerator::expand(StateToIdCallback const& stateToIdCallback) { STORM_LOG_DEBUG("Explore state: " << mDft.getStateString(state)); + // Initialization + bool hasDependencies = state->getFailableElements().hasDependencies(); + return exploreState(stateToIdCallback, hasDependencies); + } + template + StateBehavior DftNextStateGenerator::exploreState(StateToIdCallback const& stateToIdCallback, bool exploreDependencies) { // Prepare the result, in case we return early. StateBehavior result; - // Initialization - bool hasDependencies = state->getFailableElements().hasDependencies(); //size_t failableCount = hasDependencies ? state->nrFailableDependencies() : state->nrFailableBEs(); //size_t currentFailable = 0; - state->getFailableElements().init(hasDependencies); - + state->getFailableElements().init(exploreDependencies); // Check for absorbing state if (mDft.hasFailed(state) || mDft.isFailsafe(state) || state->getFailableElements().isEnd()) { Choice choice(0, true); @@ -68,12 +71,12 @@ namespace storm { return result; } - Choice choice(0, !hasDependencies); + Choice choice(0, !exploreDependencies); // Let BE fail bool isFirst = true; while (!state->getFailableElements().isEnd()) { - if (storm::settings::getModule().isTakeFirstDependency() && hasDependencies && !isFirst) { + if (storm::settings::getModule().isTakeFirstDependency() && exploreDependencies && !isFirst) { // We discard further exploration as we already chose one dependent event break; } @@ -82,10 +85,10 @@ namespace storm { // Construct new state as copy from original one DFTStatePointer newState = state->copy(); - std::pair const>, bool> nextBEPair = newState->letNextBEFail(state->getFailableElements().get()); + std::pair const>, bool> nextBEPair = newState->letNextBEFail(state->getFailableElements().get(), exploreDependencies); std::shared_ptr const>& nextBE = nextBEPair.first; STORM_LOG_ASSERT(nextBE, "NextBE is null."); - STORM_LOG_ASSERT(nextBEPair.second == hasDependencies, "Failure due to dependencies does not match."); + STORM_LOG_ASSERT(nextBEPair.second == exploreDependencies, "Failure due to dependencies does not match."); STORM_LOG_TRACE("With the failure of: " << nextBE->name() << " [" << nextBE->id() << "] in " << mDft.getStateString(state)); // Propagate @@ -149,7 +152,7 @@ namespace storm { } // Set transitions - if (hasDependencies) { + if (exploreDependencies) { // Failure is due to dependency -> add non-deterministic choice ValueType probability = mDft.getDependency(state->getFailableElements().get())->probability(); choice.addProbability(newStateId, probability); @@ -184,8 +187,15 @@ namespace storm { state->getFailableElements().next(); } // end while failing BE - - if (!hasDependencies) { + + if (exploreDependencies) { + if (result.empty()) { + // Dependencies might have been prevented from sequence enforcer + // -> explore BEs now + return exploreState(stateToIdCallback, false); + } + } else { + STORM_LOG_ASSERT(choice.size() > 0, "No transitions were generated"); // Add all rates as one choice result.addChoice(std::move(choice)); } diff --git a/src/storm-dft/generator/DftNextStateGenerator.h b/src/storm-dft/generator/DftNextStateGenerator.h index 2f614afe6..08aa3739e 100644 --- a/src/storm-dft/generator/DftNextStateGenerator.h +++ b/src/storm-dft/generator/DftNextStateGenerator.h @@ -43,7 +43,9 @@ namespace storm { StateBehavior createMergeFailedState(StateToIdCallback const& stateToIdCallback); private: - + + StateBehavior exploreState(StateToIdCallback const& stateToIdCallback, bool exploreDependencies); + // The dft used for the generation of next states. storm::storage::DFT const& mDft; diff --git a/src/storm-dft/storage/dft/DFTState.cpp b/src/storm-dft/storage/dft/DFTState.cpp index 2bbc2dfed..18b0559a0 100644 --- a/src/storm-dft/storage/dft/DFTState.cpp +++ b/src/storm-dft/storage/dft/DFTState.cpp @@ -195,7 +195,8 @@ namespace storm { if (!hasFailed(id)) { return false; } - + + bool addedFailableDependency = false; for (auto dependency : mDft.getElement(id)->outgoingDependencies()) { STORM_LOG_ASSERT(dependency->triggerEvent()->id() == id, "Ids do not match."); assert(dependency->dependentEvents().size() == 1); @@ -203,9 +204,10 @@ namespace storm { STORM_LOG_ASSERT(!isFailsafe(dependency->dependentEvents()[0]->id()), "Dependent event is failsafe."); failableElements.addDependency(dependency->id()); STORM_LOG_TRACE("New dependency failure: " << dependency->toString()); + addedFailableDependency = true; } } - return failableElements.hasDependencies(); + return addedFailableDependency; } template @@ -235,9 +237,9 @@ namespace storm { } template - std::pair const>, bool> DFTState::letNextBEFail(size_t id) { + std::pair const>, bool> DFTState::letNextBEFail(size_t id, bool dueToDependency) { STORM_LOG_TRACE("currently failable: " << getCurrentlyFailableString()); - if (failableElements.hasDependencies()) { + if (dueToDependency) { // Consider failure due to dependency std::shared_ptr const> dependency = mDft.getDependency(id); STORM_LOG_ASSERT(dependency->dependentEvents().size() == 1, "More than one dependent event"); diff --git a/src/storm-dft/storage/dft/DFTState.h b/src/storm-dft/storage/dft/DFTState.h index 427115de4..e569e8d49 100644 --- a/src/storm-dft/storage/dft/DFTState.h +++ b/src/storm-dft/storage/dft/DFTState.h @@ -299,9 +299,10 @@ namespace storm { /** * Sets the next BE as failed * @param index Index in currentlyFailableBE of BE to fail + * @param dueToDependency Whether the failure is due to a dependency. * @return Pair of BE which fails and flag indicating if the failure was due to functional dependencies */ - std::pair const>, bool> letNextBEFail(size_t index = 0); + std::pair const>, bool> letNextBEFail(size_t index, bool dueToDependency); /** * Sets the dependency as unsuccesful meaning no BE will fail. From fdf89e71a54bdf8e60b610ad65f6f510ad7426e2 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Sun, 24 Mar 2019 18:06:24 +0100 Subject: [PATCH 15/40] Started on support for constant failed/failsafe BEs --- src/storm-dft/builder/DFTBuilder.cpp | 8 ++-- src/storm-dft/builder/DFTBuilder.h | 37 +++++++++++++++++-- src/storm-dft/parser/DFTGalileoParser.cpp | 13 ++++--- src/storm-dft/parser/DFTJsonParser.cpp | 3 +- src/storm-dft/storage/dft/elements/DFTConst.h | 17 +++++++-- 5 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/storm-dft/builder/DFTBuilder.cpp b/src/storm-dft/builder/DFTBuilder.cpp index 3bc2cf71b..2c3f4a656 100644 --- a/src/storm-dft/builder/DFTBuilder.cpp +++ b/src/storm-dft/builder/DFTBuilder.cpp @@ -273,14 +273,16 @@ namespace storm { case storm::storage::DFTElementType::BE: { std::shared_ptr> be = std::static_pointer_cast>(element); - addBasicElement(be->name(), be->activeFailureRate(), be->dormancyFactor(), be->isTransient()); + addBasicElementExponential(be->name(), be->activeFailureRate(), be->dormancyFactor(), be->isTransient()); break; } case storm::storage::DFTElementType::CONSTF: case storm::storage::DFTElementType::CONSTS: - // TODO - STORM_LOG_ASSERT(false, "Const elements not supported."); + { + std::shared_ptr> be = std::static_pointer_cast>(element); + addBasicElementConst(be->name(), be->failed()); break; + } case storm::storage::DFTElementType::PDEP: { DFTDependencyPointer dependency = std::static_pointer_cast>(element); diff --git a/src/storm-dft/builder/DFTBuilder.h b/src/storm-dft/builder/DFTBuilder.h index 479db529c..2f89b8306 100644 --- a/src/storm-dft/builder/DFTBuilder.h +++ b/src/storm-dft/builder/DFTBuilder.h @@ -8,6 +8,8 @@ #include "storm-dft/storage/dft/DFTElements.h" #include "storm-dft/storage/dft/elements/DFTRestriction.h" #include "storm-dft/storage/dft/DFTLayoutInfo.h" +#include "storm/exceptions/NotSupportedException.h" + namespace storm { namespace storage { @@ -109,7 +111,7 @@ namespace storm { if (binaryDependencies && !storm::utility::isOne(probability) && children.size() > 2) { // Introduce additional element for first capturing the probabilistic dependency std::string nameAdditional = name + "_additional"; - addBasicElement(nameAdditional, storm::utility::zero(), storm::utility::zero(), false); + addBasicElementConst(nameAdditional, false); // First consider probabilistic dependency addDepElement(name + "_pdep", {children.front(), nameAdditional}, probability); // Then consider dependencies to the children if probabilistic dependency failed @@ -167,15 +169,42 @@ namespace storm { mChildNames[element] = children; return true; } - - bool addBasicElement(std::string const& name, ValueType failureRate, ValueType dormancyFactor, bool transient = false) { + + bool addBasicElementConst(std::string const& name, bool failed) { + if (nameInUse(name)) { + STORM_LOG_ERROR("Element with name '" << name << "' already exists."); + return false; + } + mElements[name] = std::make_shared>(mNextId++, name, failed); + return true; + } + + bool addBasicElementProbability(std::string const& name, ValueType probability, ValueType dormancyFactor, bool transient = false) { + //0 <= dormancyFactor <= 1 + if (nameInUse(name)) { + STORM_LOG_ERROR("Element with name '" << name << "' already exists."); + return false; + } + if (storm::utility::isZero(probability)) { + return addBasicElementConst(name, false); + } else if (storm::utility::isOne(probability)) { + return addBasicElementConst(name, true); + } + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Constant probability distribution is not supported for basic element '" << name << "'."); + return false; + } + + bool addBasicElementExponential(std::string const& name, ValueType failureRate, ValueType dormancyFactor, bool transient = false) { //TODO Matthias: collect constraints for SMT solving - //failureRate > 0 //0 <= dormancyFactor <= 1 if (nameInUse(name)) { STORM_LOG_ERROR("Element with name '" << name << "' already exists."); return false; } + if (storm::utility::isZero(failureRate)) { + return addBasicElementConst(name, false); + } + mElements[name] = std::make_shared>(mNextId++, name, failureRate, dormancyFactor, transient); return true; } diff --git a/src/storm-dft/parser/DFTGalileoParser.cpp b/src/storm-dft/parser/DFTGalileoParser.cpp index ef7faf350..bf1dced78 100644 --- a/src/storm-dft/parser/DFTGalileoParser.cpp +++ b/src/storm-dft/parser/DFTGalileoParser.cpp @@ -297,26 +297,29 @@ namespace storm { switch (distribution) { case Constant: + if (storm::utility::isZero(firstValDistribution) || storm::utility::isOne(firstValDistribution)) { + return builder.addBasicElementProbability(parseName(name), firstValDistribution, dormancyFactor, false); // TODO set transient BEs + } STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Constant distribution is not supported for basic element '" << name << "' in line " << lineNo << "."); break; case Exponential: - return builder.addBasicElement(parseName(name), firstValDistribution, dormancyFactor, false); // TODO set transient BEs + return builder.addBasicElementExponential(parseName(name), firstValDistribution, dormancyFactor, false); // TODO set transient BEs break; case Erlang: if (erlangPhases == 1) { // Erlang distribution reduces to exponential distribution - return builder.addBasicElement(parseName(name), firstValDistribution, dormancyFactor, false); // TODO set transient BEs + return builder.addBasicElementExponential(parseName(name), firstValDistribution, dormancyFactor, false); // TODO set transient BEs } else { // Model Erlang distribution by using SEQ over BEs instead. // For each phase a BE is added, then the SEQ ensures the ordered failure. STORM_LOG_WARN("Erlang distribution for basic element '" << name << "' in line " << lineNo << " is modelled by SEQ gate and BEs."); std::string origName = parseName(name); std::vector childNames; - bool success = builder.addBasicElement(origName, firstValDistribution, dormancyFactor, false); // TODO set transient BEs + bool success = builder.addBasicElementExponential(origName, firstValDistribution, dormancyFactor, false); // TODO set transient BEs for (size_t i = 0; i < erlangPhases - 1; ++i) { std::string beName = origName + "_" + std::to_string(i); childNames.push_back(beName); - success = success && builder.addBasicElement(beName, firstValDistribution, dormancyFactor, false); // TODO set transient BEs + success = success && builder.addBasicElementExponential(beName, firstValDistribution, dormancyFactor, false); // TODO set transient BEs } childNames.push_back(origName); return success && builder.addSequenceEnforcer(origName + "_seq", childNames); @@ -325,7 +328,7 @@ namespace storm { case Weibull: if (storm::utility::isOne(secondValDistribution)) { // Weibull distribution reduces to exponential distribution - return builder.addBasicElement(parseName(name), firstValDistribution, dormancyFactor, false); // TODO set transient BEs + return builder.addBasicElementExponential(parseName(name), firstValDistribution, dormancyFactor, false); // TODO set transient BEs } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Weibull distribution is not supported for basic element '" << name << "' in line " << lineNo << "."); } diff --git a/src/storm-dft/parser/DFTJsonParser.cpp b/src/storm-dft/parser/DFTJsonParser.cpp index c9f02b016..23d83fed2 100644 --- a/src/storm-dft/parser/DFTJsonParser.cpp +++ b/src/storm-dft/parser/DFTJsonParser.cpp @@ -93,13 +93,14 @@ namespace storm { ValueType probability = parseRationalExpression(parseJsonNumber(data.at("probability"))); success = builder.addDepElement(name, childNames, probability); } else if (type == "be") { + // TODO support different distributions ValueType failureRate = parseRationalExpression(parseJsonNumber(data.at("rate"))); ValueType dormancyFactor = parseRationalExpression(parseJsonNumber(data.at("dorm"))); bool transient = false; if (data.count("transient") > 0) { transient = data.at("transient"); } - success = builder.addBasicElement(name, failureRate, dormancyFactor, transient); + success = builder.addBasicElementExponential(name, failureRate, dormancyFactor, transient); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Type name: " << type << " not recognized."); success = false; diff --git a/src/storm-dft/storage/dft/elements/DFTConst.h b/src/storm-dft/storage/dft/elements/DFTConst.h index 144b5335c..6ff4cd39e 100644 --- a/src/storm-dft/storage/dft/elements/DFTConst.h +++ b/src/storm-dft/storage/dft/elements/DFTConst.h @@ -27,15 +27,20 @@ namespace storm { return mFailed; } - virtual bool isConstant() const { + virtual bool isConstant() const override { return true; } virtual size_t nrChildren() const override { return 0; } - - + + std::string toString() const override { + std::stringstream stream; + stream << *this; + return stream.str(); + } + bool isTypeEqualTo(DFTElement const& other) const override { if(!DFTElement::isTypeEqualTo(other)) return false; DFTConst const& otherCNST = static_cast const&>(other); @@ -43,5 +48,11 @@ namespace storm { } }; + + template + inline std::ostream& operator<<(std::ostream& os, DFTConst const& be) { + return os << "{" << be.name() << "} BE(const " << (be.failed() ? "failed" : "failsafe") << ")"; + } + } } From 36601c8187abc737b919af4cea8c602451bcb25d Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 27 Mar 2019 10:08:59 +0100 Subject: [PATCH 16/40] Added virtual destructors in cpptempl --- resources/3rdparty/cpptemplate/cpptempl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/3rdparty/cpptemplate/cpptempl.h b/resources/3rdparty/cpptemplate/cpptempl.h index b6a19d293..28c289a10 100755 --- a/resources/3rdparty/cpptemplate/cpptempl.h +++ b/resources/3rdparty/cpptemplate/cpptempl.h @@ -126,6 +126,7 @@ namespace cpptempl class Data { public: + virtual ~Data() {} virtual bool empty() = 0 ; virtual std::string getvalue(); virtual data_list& getlist(); @@ -192,6 +193,7 @@ namespace cpptempl class Token { public: + virtual ~Token() {}; virtual TokenType gettype() = 0 ; virtual void gettext(std::ostream &stream, data_map &data) = 0 ; virtual void set_children(token_vector &children); From d3479071ac1c0f3277f60e77fbe290df65293af9 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 27 Mar 2019 10:09:37 +0100 Subject: [PATCH 17/40] Set sysroot for cudd to fix issue with moved header files in macOS Mojave --- resources/3rdparty/include_cudd.cmake | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/resources/3rdparty/include_cudd.cmake b/resources/3rdparty/include_cudd.cmake index 3030f44b3..9aafb98b4 100644 --- a/resources/3rdparty/include_cudd.cmake +++ b/resources/3rdparty/include_cudd.cmake @@ -28,13 +28,19 @@ if (NOT STORM_PORTABLE) set(STORM_CUDD_FLAGS "${STORM_CUDD_FLAGS} -march=native") endif() +# Set sysroot to circumvent problems in macOS "Mojave" where the header files are no longer in /usr/include +set(CUDD_INCLUDE_FLAGS "") +if (CMAKE_OSX_SYSROOT) + set(CUDD_INCLUDE_FLAGS "CPPFLAGS=--sysroot=${CMAKE_OSX_SYSROOT}") +endif() + ExternalProject_Add( cudd3 DOWNLOAD_COMMAND "" SOURCE_DIR ${STORM_3RDPARTY_SOURCE_DIR}/cudd-3.0.0 PREFIX ${STORM_3RDPARTY_BINARY_DIR}/cudd-3.0.0 PATCH_COMMAND ${AUTORECONF} - CONFIGURE_COMMAND ${STORM_3RDPARTY_SOURCE_DIR}/cudd-3.0.0/configure --enable-shared --enable-obj --with-pic=yes --prefix=${STORM_3RDPARTY_BINARY_DIR}/cudd-3.0.0 --libdir=${CUDD_LIB_DIR} CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} + CONFIGURE_COMMAND ${STORM_3RDPARTY_SOURCE_DIR}/cudd-3.0.0/configure --enable-shared --enable-obj --with-pic=yes --prefix=${STORM_3RDPARTY_BINARY_DIR}/cudd-3.0.0 --libdir=${CUDD_LIB_DIR} CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} ${CUDD_INCLUDE_FLAGS} BUILD_COMMAND make ${STORM_CUDD_FLAGS} INSTALL_COMMAND make install BUILD_IN_SOURCE 0 From 9dbb66a9bd6bd92bd27ea100cf7e8e41e050b652 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 3 Apr 2019 17:15:11 +0200 Subject: [PATCH 18/40] Larger refactoring for DFT BEs. Split into BEExponential and BEConst --- src/storm-dft/builder/DFTBuilder.cpp | 22 ++- src/storm-dft/builder/DFTBuilder.h | 4 +- .../builder/ExplicitDFTModelBuilder.cpp | 26 +++- .../generator/DftNextStateGenerator.cpp | 16 +- .../modelchecker/dft/DFTASFChecker.cpp | 8 +- src/storm-dft/parser/DFTJsonParser.cpp | 25 ++- src/storm-dft/storage/dft/DFT.cpp | 25 ++- src/storm-dft/storage/dft/DFT.h | 21 ++- src/storm-dft/storage/dft/DFTElementType.h | 70 +++++---- src/storm-dft/storage/dft/DFTElements.h | 3 +- src/storm-dft/storage/dft/DFTIsomorphism.h | 83 +++++++++- src/storm-dft/storage/dft/DFTState.cpp | 58 +++++-- src/storm-dft/storage/dft/DftJsonExporter.cpp | 34 ++++- src/storm-dft/storage/dft/elements/BEConst.h | 61 ++++++++ .../storage/dft/elements/BEExponential.h | 103 +++++++++++++ src/storm-dft/storage/dft/elements/DFTAnd.h | 6 - src/storm-dft/storage/dft/elements/DFTBE.h | 143 +++++++----------- src/storm-dft/storage/dft/elements/DFTConst.h | 58 ------- .../storage/dft/elements/DFTDependency.h | 10 +- .../storage/dft/elements/DFTElement.h | 112 +++++++++----- src/storm-dft/storage/dft/elements/DFTOr.h | 4 - src/storm-dft/storage/dft/elements/DFTPand.h | 5 - src/storm-dft/storage/dft/elements/DFTPor.h | 5 - .../storage/dft/elements/DFTRestriction.h | 30 ++-- src/storm-dft/storage/dft/elements/DFTSpare.h | 1 + src/storm-dft/storage/dft/elements/DFTVot.h | 5 - .../DftToGspnTransformator.cpp | 63 ++++---- .../transformations/DftToGspnTransformator.h | 19 +-- 28 files changed, 635 insertions(+), 385 deletions(-) create mode 100644 src/storm-dft/storage/dft/elements/BEConst.h create mode 100644 src/storm-dft/storage/dft/elements/BEExponential.h delete mode 100644 src/storm-dft/storage/dft/elements/DFTConst.h diff --git a/src/storm-dft/builder/DFTBuilder.cpp b/src/storm-dft/builder/DFTBuilder.cpp index 2c3f4a656..56fda6401 100644 --- a/src/storm-dft/builder/DFTBuilder.cpp +++ b/src/storm-dft/builder/DFTBuilder.cpp @@ -3,6 +3,7 @@ #include #include "storm/utility/macros.h" +#include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/NotSupportedException.h" #include "storm/exceptions/WrongFormatException.h" @@ -188,14 +189,12 @@ namespace storm { case storm::storage::DFTElementType::SPARE: element = std::make_shared>(mNextId++, name); break; - case storm::storage::DFTElementType::BE: + case storm::storage::DFTElementType::BE_EXP: + case storm::storage::DFTElementType::BE_CONST: case storm::storage::DFTElementType::VOT: case storm::storage::DFTElementType::PDEP: // Handled separately STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type handled separately."); - case storm::storage::DFTElementType::CONSTF: - case storm::storage::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."); } @@ -270,17 +269,16 @@ namespace storm { copyGate(std::static_pointer_cast>(element), children); break; } - case storm::storage::DFTElementType::BE: + case storm::storage::DFTElementType::BE_EXP: { - std::shared_ptr> be = std::static_pointer_cast>(element); - addBasicElementExponential(be->name(), be->activeFailureRate(), be->dormancyFactor(), be->isTransient()); + auto beExp = std::static_pointer_cast>(element); + addBasicElementExponential(beExp->name(), beExp->activeFailureRate(), beExp->dormancyFactor(), beExp->isTransient()); break; } - case storm::storage::DFTElementType::CONSTF: - case storm::storage::DFTElementType::CONSTS: + case storm::storage::DFTElementType::BE_CONST: { - std::shared_ptr> be = std::static_pointer_cast>(element); - addBasicElementConst(be->name(), be->failed()); + auto beConst = std::static_pointer_cast>(element); + addBasicElementConst(beConst->name(), beConst->failed()); break; } case storm::storage::DFTElementType::PDEP: @@ -303,7 +301,7 @@ namespace storm { break; } default: - STORM_LOG_ASSERT(false, "Dft type not known."); + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "DFT type '" << element->type() << "' not known."); break; } } diff --git a/src/storm-dft/builder/DFTBuilder.h b/src/storm-dft/builder/DFTBuilder.h index 2f89b8306..b12013fc7 100644 --- a/src/storm-dft/builder/DFTBuilder.h +++ b/src/storm-dft/builder/DFTBuilder.h @@ -175,7 +175,7 @@ namespace storm { STORM_LOG_ERROR("Element with name '" << name << "' already exists."); return false; } - mElements[name] = std::make_shared>(mNextId++, name, failed); + mElements[name] = std::make_shared>(mNextId++, name, failed); return true; } @@ -205,7 +205,7 @@ namespace storm { return addBasicElementConst(name, false); } - mElements[name] = std::make_shared>(mNextId++, name, failureRate, dormancyFactor, transient); + mElements[name] = std::make_shared>(mNextId++, name, failureRate, dormancyFactor, transient); return true; } diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index eb7d50e06..8c23c6d6a 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -9,6 +9,7 @@ #include "storm/utility/vector.h" #include "storm/utility/bitoperations.h" #include "storm/utility/ProgressMeasurement.h" +#include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/UnexpectedException.h" #include "storm/settings/SettingsManager.h" #include "storm/logic/AtomicLabelFormula.h" @@ -704,13 +705,26 @@ namespace storm { ValueType rate = state->getBERate(id); if (storm::utility::isZero(rate)) { // Get active failure rate for cold BE - rate = dft.getBasicElement(id)->activeFailureRate(); - if (storm::utility::isZero(rate)) { - // Ignore BE which cannot fail - continue; + auto be = dft.getBasicElement(id); + switch (be->type()) { + case storm::storage::DFTElementType::BE_EXP: + { + auto beExp = std::static_pointer_cast const>(be); + rate = beExp->activeFailureRate(); + STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Failure rate should not be zero."); + // Mark BE as cold + coldBEs.set(i, true); + break; + } + case storm::storage::DFTElementType::BE_CONST: + { + // Ignore BE which cannot fail + continue; + } + default: + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "BE of type '" << be->type() << "' is not known."); + break; } - // Mark BE as cold - coldBEs.set(i, true); } rates.push_back(rate); rateSum += rate; diff --git a/src/storm-dft/generator/DftNextStateGenerator.cpp b/src/storm-dft/generator/DftNextStateGenerator.cpp index 69751ea62..b59e91d52 100644 --- a/src/storm-dft/generator/DftNextStateGenerator.cpp +++ b/src/storm-dft/generator/DftNextStateGenerator.cpp @@ -118,7 +118,13 @@ namespace storm { newState->updateFailableDependencies(next->id()); } - if(newState->isInvalid() || (nextBE->isTransient() && !newState->hasFailed(mDft.getTopLevelIndex()))) { + bool transient = false; + if (nextBE->type() == storm::storage::DFTElementType::BE_EXP) { + auto beExp = std::static_pointer_cast const>(nextBE); + transient = beExp->isTransient(); + } + + if(newState->isInvalid() || (transient && !newState->hasFailed(mDft.getTopLevelIndex()))) { // Continue with next possible state state->getFailableElements().next(); STORM_LOG_TRACE("State is ignored because " << (newState->isInvalid() ? "it is invalid" : "the transient fault is ignored")); @@ -173,12 +179,14 @@ namespace storm { } else { // Failure is due to "normal" BE failure // Set failure rate according to activation + STORM_LOG_THROW(nextBE->type() == storm::storage::DFTElementType::BE_EXP, storm::exceptions::NotSupportedException, "BE of type '" << nextBE->type() << "' is not supported."); + auto beExp = std::static_pointer_cast const>(nextBE); bool isActive = true; - if (mDft.hasRepresentant(nextBE->id())) { + if (mDft.hasRepresentant(beExp->id())) { // Active must be checked for the state we are coming from as this state is responsible for the rate - isActive = state->isActive(mDft.getRepresentant(nextBE->id())); + isActive = state->isActive(mDft.getRepresentant(beExp->id())); } - ValueType rate = isActive ? nextBE->activeFailureRate() : nextBE->passiveFailureRate(); + ValueType rate = isActive ? beExp->activeFailureRate() : beExp->passiveFailureRate(); STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Rate is 0."); choice.addProbability(newStateId, rate); STORM_LOG_TRACE("Added transition to " << newStateId << " with " << (isActive ? "active" : "passive") << " failure rate " << rate); diff --git a/src/storm-dft/modelchecker/dft/DFTASFChecker.cpp b/src/storm-dft/modelchecker/dft/DFTASFChecker.cpp index 41f688da0..1b9a2ea89 100644 --- a/src/storm-dft/modelchecker/dft/DFTASFChecker.cpp +++ b/src/storm-dft/modelchecker/dft/DFTASFChecker.cpp @@ -417,9 +417,12 @@ namespace storm { varNames.push_back("t_" + element->name()); timePointVariables.emplace(i, varNames.size() - 1); switch (element->type()) { - case storm::storage::DFTElementType::BE: + case storm::storage::DFTElementType::BE_EXP: beVariables.push_back(varNames.size() - 1); break; + case storm::storage::DFTElementType::BE_CONST: + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Constant BEs are not supported in SMT translation."); + break; case storm::storage::DFTElementType::SPARE: { auto spare = std::static_pointer_cast const>(element); @@ -721,8 +724,7 @@ namespace storm { std::shared_ptr nextFailure = std::make_shared(timePointVariables.at(j), i+1); // BE is not cold // TODO: implement use of activation variables here - bool cold = storm::utility::isZero(be->activeFailureRate()); - notColdC[i].push_back(std::make_shared(nextFailure, std::make_shared(!cold))); + notColdC[i].push_back(std::make_shared(nextFailure, std::make_shared(be->canFail()))); } } } diff --git a/src/storm-dft/parser/DFTJsonParser.cpp b/src/storm-dft/parser/DFTJsonParser.cpp index 23d83fed2..1272e033e 100644 --- a/src/storm-dft/parser/DFTJsonParser.cpp +++ b/src/storm-dft/parser/DFTJsonParser.cpp @@ -93,14 +93,25 @@ namespace storm { ValueType probability = parseRationalExpression(parseJsonNumber(data.at("probability"))); success = builder.addDepElement(name, childNames, probability); } else if (type == "be") { - // TODO support different distributions - ValueType failureRate = parseRationalExpression(parseJsonNumber(data.at("rate"))); - ValueType dormancyFactor = parseRationalExpression(parseJsonNumber(data.at("dorm"))); - bool transient = false; - if (data.count("transient") > 0) { - transient = data.at("transient"); + std::string distribution = "exp"; // Set default of exponential distribution + if (data.count("distribution") > 0) { + distribution = data.at("distribution"); + } + if (distribution == "exp") { + ValueType failureRate = parseRationalExpression(parseJsonNumber(data.at("rate"))); + ValueType dormancyFactor = parseRationalExpression(parseJsonNumber(data.at("dorm"))); + bool transient = false; + if (data.count("transient") > 0) { + transient = data.at("transient"); + } + success = builder.addBasicElementExponential(name, failureRate, dormancyFactor, transient); + } else if (distribution == "const") { + bool failed = data.at("failed"); + success = builder.addBasicElementConst(name, failed); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Distribution: " << distribution << " not supported."); + success = false; } - success = builder.addBasicElementExponential(name, failureRate, dormancyFactor, transient); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Type name: " << type << " not recognized."); success = false; diff --git a/src/storm-dft/storage/dft/DFT.cpp b/src/storm-dft/storage/dft/DFT.cpp index 5caa0d555..c66af8550 100644 --- a/src/storm-dft/storage/dft/DFT.cpp +++ b/src/storm-dft/storage/dft/DFT.cpp @@ -3,6 +3,7 @@ #include #include +#include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/NotSupportedException.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/utility/iota_n.h" @@ -348,9 +349,8 @@ namespace storm { case DFTElementType::OR: builder.addOrElement(newParentName, childrenNames); break; - case DFTElementType::BE: - case DFTElementType::CONSTF: - case DFTElementType::CONSTS: + case DFTElementType::BE_EXP: + case DFTElementType::BE_CONST: case DFTElementType::VOT: case DFTElementType::PAND: case DFTElementType::SPARE: @@ -391,9 +391,8 @@ namespace storm { case DFTElementType::AND: case DFTElementType::OR: case DFTElementType::VOT: - case DFTElementType::BE: - case DFTElementType::CONSTF: - case DFTElementType::CONSTS: + case DFTElementType::BE_EXP: + case DFTElementType::BE_CONST: break; case DFTElementType::PAND: case DFTElementType::SPARE: @@ -421,9 +420,8 @@ namespace storm { case DFTElementType::VOT: ++noStatic; break; - case DFTElementType::BE: - case DFTElementType::CONSTF: - case DFTElementType::CONSTS: + case DFTElementType::BE_EXP: + case DFTElementType::BE_CONST: case DFTElementType::PAND: case DFTElementType::SPARE: case DFTElementType::POR: @@ -443,7 +441,7 @@ namespace storm { std::string DFT::getElementsString() const { std::stringstream stream; for (auto const& elem : mElements) { - stream << "[" << elem->id() << "]" << elem->toString() << std::endl; + stream << "[" << elem->id() << "]" << *elem << std::endl; } return stream.str(); } @@ -495,7 +493,7 @@ namespace storm { std::stringstream stream; for (auto const& elem : mElements) { stream << "[" << elem->id() << "]"; - stream << elem->toString(); + stream << *elem; if (elem->isDependency()) { stream << "\t** " << storm::storage::toChar(state->getDependencyState(elem->id())) << "[dep]"; } else { @@ -860,9 +858,8 @@ namespace storm { size_t noRestriction = 0; for (auto const& elem : mElements) { switch (elem->type()) { - case DFTElementType::BE: - case DFTElementType::CONSTF: - case DFTElementType::CONSTS: + case DFTElementType::BE_EXP: + case DFTElementType::BE_CONST: ++noBE; break; case DFTElementType::AND: diff --git a/src/storm-dft/storage/dft/DFT.h b/src/storm-dft/storage/dft/DFT.h index aef5036d8..b902d6218 100644 --- a/src/storm-dft/storage/dft/DFT.h +++ b/src/storm-dft/storage/dft/DFT.h @@ -11,6 +11,7 @@ #include "storm/storage/BitVector.h" #include "storm/utility/math.h" #include "storm/utility/macros.h" +#include "storm/exceptions/NotSupportedException.h" #include "storm-dft/storage/dft/DFTElements.h" #include "storm-dft/storage/dft/SymmetricUnits.h" @@ -134,11 +135,23 @@ namespace storm { std::vector nonColdBEs() const { std::vector result; - for(DFTElementPointer elem : mElements) { - if(elem->isBasicElement()) { + for (DFTElementPointer elem : mElements) { + if (elem->isBasicElement()) { std::shared_ptr> be = std::static_pointer_cast>(elem); - if (be->canFail() && !be->isColdBasicElement()) { - result.push_back(be->id()); + if (be->canFail()) { + switch (be->type()) { + case storm::storage::DFTElementType::BE_EXP: { + auto beExp = std::static_pointer_cast>(be); + if (!beExp->isColdBasicElement()) { + result.push_back(be->id()); + } + break; + } + case storm::storage::DFTElementType::BE_CONST: + result.push_back(be->id()); + default: + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "BE type '" << be->type() << "' is not supported."); + } } } } diff --git a/src/storm-dft/storage/dft/DFTElementType.h b/src/storm-dft/storage/dft/DFTElementType.h index 1527efe25..c76b071fe 100644 --- a/src/storm-dft/storage/dft/DFTElementType.h +++ b/src/storm-dft/storage/dft/DFTElementType.h @@ -5,80 +5,94 @@ namespace storm { namespace storage { - enum class DFTElementType : int {AND = 0, OR = 2, VOT = 3, BE = 4, CONSTF = 5, CONSTS = 6, PAND = 7, SPARE = 8, POR = 9, PDEP = 10, SEQ = 11, MUTEX=12}; + /*! + * Element types in a DFT. + */ + enum class DFTElementType { + BE_EXP, BE_CONST, + AND, OR, VOT, + BE, + PAND, + POR, + SPARE, + PDEP, + SEQ, + MUTEX + }; - inline bool isGateType(DFTElementType const& tp) { - switch(tp) { + inline bool isGateType(DFTElementType const& type) { + switch (type) { case DFTElementType::AND: case DFTElementType::OR: case DFTElementType::VOT: case DFTElementType::PAND: - case DFTElementType::SPARE: case DFTElementType::POR: + case DFTElementType::SPARE: return true; + case DFTElementType::BE_EXP: + case DFTElementType::BE_CONST: + case DFTElementType::PDEP: case DFTElementType::SEQ: case DFTElementType::MUTEX: - case DFTElementType::BE: - case DFTElementType::CONSTF: - case DFTElementType::CONSTS: - case DFTElementType::PDEP: return false; default: - STORM_LOG_ASSERT(false, "Dft type not known."); + STORM_LOG_ASSERT(false, "DFT type not known."); return false; } } - inline bool isStaticGateType(DFTElementType const& tp) { - if(!isGateType(tp)) return false; - switch(tp) { + inline bool isStaticGateType(DFTElementType const& type) { + if (!isGateType(type)) { + return false; + } + switch (type) { case DFTElementType::AND: case DFTElementType::OR: case DFTElementType::VOT: return true; + case DFTElementType::PAND: case DFTElementType::POR: case DFTElementType::SPARE: - case DFTElementType::PAND: return false; default: - STORM_LOG_ASSERT(false, "Dft gate type not known."); + STORM_LOG_ASSERT(false, "DFT gate type not known."); return false; } } inline std::string toString(DFTElementType const& tp) { - switch(tp) { - case DFTElementType::BE: - return "BE"; - case DFTElementType::OR: - return "OR"; + switch (tp) { + case DFTElementType::BE_EXP: + return "BE_EXP"; + case DFTElementType::BE_CONST: + return "BE_CONST"; case DFTElementType::AND: return "AND"; + case DFTElementType::OR: + return "OR"; case DFTElementType::VOT: return "VOT"; - case DFTElementType::POR: - return "POR"; case DFTElementType::PAND: return "PAND"; + case DFTElementType::POR: + return "POR"; case DFTElementType::SPARE: return "SPARE"; + case DFTElementType::PDEP: + return "PDEP"; case DFTElementType::SEQ: return "SEQ"; case DFTElementType::MUTEX: return "MUTEX"; - case DFTElementType::PDEP: - return "PDEP"; default: - STORM_LOG_ASSERT(false, "Dft type not known."); + STORM_LOG_ASSERT(false, "DFT type not known."); return ""; } } - inline std::ostream& operator<<(std::ostream& os, DFTElementType const& tp) { - return os << toString(tp); + inline std::ostream& operator<<(std::ostream& os, DFTElementType const& type) { + return os << toString(type); } - - } } diff --git a/src/storm-dft/storage/dft/DFTElements.h b/src/storm-dft/storage/dft/DFTElements.h index 8cbfec680..42aaa4b18 100644 --- a/src/storm-dft/storage/dft/DFTElements.h +++ b/src/storm-dft/storage/dft/DFTElements.h @@ -2,8 +2,9 @@ #include "storm-dft/storage/dft/elements/DFTAnd.h" #include "storm-dft/storage/dft/elements/DFTBE.h" -#include "storm-dft/storage/dft/elements/DFTConst.h" +#include "storm-dft/storage/dft/elements/BEConst.h" #include "storm-dft/storage/dft/elements/DFTDependency.h" +#include "storm-dft/storage/dft/elements/BEExponential.h" #include "storm-dft/storage/dft/elements/DFTOr.h" #include "storm-dft/storage/dft/elements/DFTPand.h" #include "storm-dft/storage/dft/elements/DFTPor.h" diff --git a/src/storm-dft/storage/dft/DFTIsomorphism.h b/src/storm-dft/storage/dft/DFTIsomorphism.h index f8fd27d8f..ab823b00a 100644 --- a/src/storm-dft/storage/dft/DFTIsomorphism.h +++ b/src/storm-dft/storage/dft/DFTIsomorphism.h @@ -54,17 +54,39 @@ namespace storage { template struct BEColourClass { + BEColourClass() = default; - BEColourClass(ValueType a, ValueType p, size_t h) : aRate(a), pRate(p), hash(h) {} + BEColourClass(storm::storage::DFTElementType t, ValueType a, ValueType p, size_t h) : type(t), hash(h), aRate(a), pRate(p) { + STORM_LOG_ASSERT(t == storm::storage::DFTElementType::BE_EXP, "Expected type BE_EXP but got type " << t); + } + + BEColourClass(storm::storage::DFTElementType t, bool fail, size_t h) : type(t), hash(h), failed(fail) { + STORM_LOG_ASSERT(t == storm::storage::DFTElementType::BE_CONST, "Expected type BE_CONST but got type " << t); + } + + storm::storage::DFTElementType type; + size_t hash; ValueType aRate; ValueType pRate; - size_t hash; + bool failed; }; + template bool operator==(BEColourClass const& lhs, BEColourClass const& rhs) { - return lhs.hash == rhs.hash && lhs.aRate == rhs.aRate && lhs.pRate == rhs.pRate; + if (lhs.type != rhs.type) { + return false; + } + switch (lhs.type) { + case storm::storage::DFTElementType::BE_EXP: + return lhs.hash == rhs.hash && lhs.aRate == rhs.aRate && lhs.pRate == rhs.pRate; + case storm::storage::DFTElementType::BE_CONST: + return lhs.hash == rhs.hash && lhs.failed == rhs.failed; + default: + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "BE of type '" << lhs.type << "' is not known."); + break; + } } /** @@ -249,7 +271,23 @@ namespace storage { protected: void colourize(std::shared_ptr> const& be) { - beColour[be->id()] = BEColourClass(be->activeFailureRate(), be->passiveFailureRate(), be->nrParents()); + switch (be->type()) { + case storm::storage::DFTElementType::BE_EXP: + { + auto beExp = std::static_pointer_cast const>(be); + beColour[beExp->id()] = BEColourClass(beExp->type(), beExp->activeFailureRate(), beExp->passiveFailureRate(), beExp->nrParents()); + break; + } + case storm::storage::DFTElementType::BE_CONST: + { + auto beConst = std::static_pointer_cast const>(be); + beColour[beConst->id()] = BEColourClass(beConst->type(), beConst->failed(), beConst->nrParents()); + break; + } + default: + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "BE of type '" << be->type() << "' is not known."); + break; + } } void colourize(std::shared_ptr> const& gate) { @@ -260,7 +298,24 @@ namespace storage { void colourize(std::shared_ptr> const& dep) { // TODO this can be improved for n-ary dependencies. - depColour[dep->id()] = std::pair(dep->probability(), dep->dependentEvents()[0]->activeFailureRate()); + std::shared_ptr const> be = dep->dependentEvents()[0]; + switch (be->type()) { + case storm::storage::DFTElementType::BE_EXP: + { + auto beExp = std::static_pointer_cast const>(be); + depColour[dep->id()] = std::pair(dep->probability(), beExp->activeFailureRate()); + break; + } + case storm::storage::DFTElementType::BE_CONST: + { + auto beConst = std::static_pointer_cast const>(be); + depColour[dep->id()] = std::pair(dep->probability(), beConst->failed()); + break; + } + default: + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "BE of type '" << be->type() << "' is not known."); + break; + } } void colourize(std::shared_ptr> const& restr) { @@ -644,11 +699,27 @@ namespace std { template struct hash> { size_t operator()(storm::storage::BEColourClass const& bcc) const { + constexpr uint_fast64_t fivebitmask = (1 << 6) - 1; + constexpr uint_fast64_t eightbitmask = (1 << 9) - 1; std::hash hasher; - return (hasher(bcc.aRate) ^ hasher(bcc.pRate) << 8) | bcc.hash; + uint_fast64_t groupHash = static_cast(1) << 63; + groupHash |= (static_cast(bcc.type) & fivebitmask) << (62 - 5); + + switch (bcc.type) { + case storm::storage::DFTElementType::BE_EXP: + return (hasher(bcc.aRate) ^ hasher(bcc.pRate) << 8); + case storm::storage::DFTElementType::BE_CONST: + return (bcc.failed << 8); + default: + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "BE of type '" << bcc.type << "' is not known."); + break; + } + groupHash |= static_cast(bcc.hash) & eightbitmask; + return groupHash; } }; + template struct hash> { size_t operator()(std::pair const& p) const { diff --git a/src/storm-dft/storage/dft/DFTState.cpp b/src/storm-dft/storage/dft/DFTState.cpp index 18b0559a0..13d9c5279 100644 --- a/src/storm-dft/storage/dft/DFTState.cpp +++ b/src/storm-dft/storage/dft/DFTState.cpp @@ -42,9 +42,25 @@ namespace storm { // Initialize currently failable BE if (mDft.isBasicElement(index) && isOperational(index)) { std::shared_ptr> be = mDft.getBasicElement(index); - if (be->canFail() && (!be->isColdBasicElement() || !mDft.hasRepresentant(index) || isActive(mDft.getRepresentant(index)))) { - failableElements.addBE(index); - STORM_LOG_TRACE("Currently failable: " << be->toString()); + if (be->canFail()) { + switch (be->type()) { + case storm::storage::DFTElementType::BE_EXP: + { + auto beExp = std::static_pointer_cast const>(be); + if (!beExp->isColdBasicElement() || !mDft.hasRepresentant(index) || isActive(mDft.getRepresentant(index))) { + failableElements.addBE(index); + STORM_LOG_TRACE("Currently failable: " << *beExp); + } + break; + } + case storm::storage::DFTElementType::BE_CONST: + failableElements.addBE(index); + STORM_LOG_TRACE("Currently failable: " << *be); + break; + default: + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "BE type '" << be->type() << "' is not supported."); + break; + } } } else if (mDft.getElement(index)->isSpareGate()) { // Initialize used representants @@ -61,7 +77,7 @@ namespace storm { assert(dependency->dependentEvents().size() == 1); if (hasFailed(dependency->triggerEvent()->id()) && getElementState(dependency->dependentEvents()[0]->id()) == DFTElementState::Operational) { failableElements.addDependency(dependencyId); - STORM_LOG_TRACE("New dependency failure: " << dependency->toString()); + STORM_LOG_TRACE("New dependency failure: " << *dependency); } } mPseudoState = false; @@ -203,7 +219,7 @@ namespace storm { if (getElementState(dependency->dependentEvents()[0]->id()) == DFTElementState::Operational) { STORM_LOG_ASSERT(!isFailsafe(dependency->dependentEvents()[0]->id()), "Dependent event is failsafe."); failableElements.addDependency(dependency->id()); - STORM_LOG_TRACE("New dependency failure: " << dependency->toString()); + STORM_LOG_TRACE("New dependency failure: " << *dependency); addedFailableDependency = true; } } @@ -226,13 +242,14 @@ namespace storm { template ValueType DFTState::getBERate(size_t id) const { STORM_LOG_ASSERT(mDft.isBasicElement(id), "Element is no BE."); - + STORM_LOG_THROW(mDft.getBasicElement(id)->type() == storm::storage::DFTElementType::BE_EXP, storm::exceptions::NotSupportedException, "BE of type '" << mDft.getBasicElement(id)->type() << "' is not supported."); + auto beExp = std::static_pointer_cast const>(mDft.getBasicElement(id)); if (mDft.hasRepresentant(id) && !isActive(mDft.getRepresentant(id))) { // Return passive failure rate - return mDft.getBasicElement(id)->passiveFailureRate(); + return beExp->passiveFailureRate(); } else { // Return active failure rate - return mDft.getBasicElement(id)->activeFailureRate(); + return beExp->activeFailureRate(); } } @@ -244,7 +261,7 @@ namespace storm { std::shared_ptr const> dependency = mDft.getDependency(id); STORM_LOG_ASSERT(dependency->dependentEvents().size() == 1, "More than one dependent event"); std::pair const>,bool> res(mDft.getBasicElement(dependency->dependentEvents()[0]->id()), true); - STORM_LOG_ASSERT(!hasFailed(res.first->id()), "Element " << res.first->toString() << " has already failed."); + STORM_LOG_ASSERT(!hasFailed(res.first->id()), "Element " << *(res.first) << " has already failed."); failableElements.removeDependency(id); setFailed(res.first->id()); setDependencySuccessful(dependency->id()); @@ -253,7 +270,7 @@ namespace storm { } else { // Consider "normal" failure std::pair const>,bool> res(mDft.getBasicElement(id), false); - STORM_LOG_ASSERT(!hasFailed(res.first->id()), "Element " << res.first->toString() << " has already failed."); + STORM_LOG_ASSERT(!hasFailed(res.first->id()), "Element " << *(res.first) << " has already failed."); STORM_LOG_ASSERT(res.first->canFail(), "Element " << *(res.first) << " cannot fail."); failableElements.removeBE(id); setFailed(res.first->id()); @@ -277,7 +294,7 @@ namespace storm { template bool DFTState::isActive(size_t id) const { - STORM_LOG_ASSERT(mDft.isRepresentative(id), "Element " << mDft.getElement(id)->toString() << " is no representative."); + STORM_LOG_ASSERT(mDft.isRepresentative(id), "Element " << *(mDft.getElement(id)) << " is no representative."); return mStatus[mStateGenerationInfo.getSpareActivationIndex(id)]; } @@ -289,9 +306,22 @@ namespace storm { for(size_t elem : mDft.module(representativeId)) { if(mDft.isBasicElement(elem) && isOperational(elem)) { std::shared_ptr> be = mDft.getBasicElement(elem); - if (be->isColdBasicElement() && be->canFail()) { - // Add to failable BEs - failableElements.addBE(elem); + if (be->canFail()) { + switch (be->type()) { + case storm::storage::DFTElementType::BE_EXP: { + auto beExp = std::static_pointer_cast const>(be); + if (beExp->isColdBasicElement()) { + // Add to failable BEs + failableElements.addBE(elem); + } + break; + } + case storm::storage::DFTElementType::BE_CONST: + // Nothing to do + break; + default: + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "BE type '" << be->type() << "' is not supported."); + } } } else if (mDft.getElement(elem)->isSpareGate() && !isActive(uses(elem))) { propagateActivation(uses(elem)); diff --git a/src/storm-dft/storage/dft/DftJsonExporter.cpp b/src/storm-dft/storage/dft/DftJsonExporter.cpp index 6dd3d2299..2eb811095 100644 --- a/src/storm-dft/storage/dft/DftJsonExporter.cpp +++ b/src/storm-dft/storage/dft/DftJsonExporter.cpp @@ -5,6 +5,7 @@ #include #include +#include namespace storm { namespace storage { @@ -84,14 +85,33 @@ namespace storm { nodeData["type"] = "fdep"; } } else if (element->isBasicElement()) { - // Set BE specific data std::shared_ptr const> be = std::static_pointer_cast const>(element); - std::stringstream stream; - stream << be->activeFailureRate(); - nodeData["rate"] = stream.str(); - stream.str(std::string()); // Clear stringstream - stream << be->dormancyFactor(); - nodeData["dorm"] = stream.str(); + // Set BE specific data + switch (element->type()) { + case storm::storage::DFTElementType::BE_EXP: + { + auto beExp = std::static_pointer_cast const>(be); + std::stringstream stream; + nodeData["distribution"] = "exp"; + stream << beExp->activeFailureRate(); + nodeData["rate"] = stream.str(); + stream.str(std::string()); // Clear stringstream + stream << beExp->dormancyFactor(); + nodeData["dorm"] = stream.str(); + break; + } + case storm::storage::DFTElementType::BE_CONST: + { + auto beConst = std::static_pointer_cast const>(be); + std::stringstream stream; + nodeData["distribution"] = "const"; + nodeData["failed"] = beConst->failed(); + break; + } + default: + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "BE of type '" << be->type() << "' is not known."); + break; + } } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Element of type '" << element->type() << "' is not supported."); } diff --git a/src/storm-dft/storage/dft/elements/BEConst.h b/src/storm-dft/storage/dft/elements/BEConst.h new file mode 100644 index 000000000..22cb13b9a --- /dev/null +++ b/src/storm-dft/storage/dft/elements/BEConst.h @@ -0,0 +1,61 @@ +#pragma once + +#include "DFTBE.h" + +namespace storm { + namespace storage { + + /*! + * BE which is either constant failed or constant failsafe. + */ + template + class BEConst : public DFTBE { + + public: + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param failed True iff the const BE is failed, otherwise it is failsafe. + */ + BEConst(size_t id, std::string const& name, bool failed) : DFTBE(id, name), mFailed(failed) { + // Intentionally empty + } + + DFTElementType type() const override { + return DFTElementType::BE_CONST; + } + + /*! + * Return whether the BE has failed. + * @return True iff the BE is const failed. + */ + bool failed() const { + return mFailed; + } + + bool canFail() const override { + return this->failed(); + } + + bool isTypeEqualTo(DFTElement const& other) const override { + if (!DFTElement::isTypeEqualTo(other)) { + return false; + } + auto& otherBE = static_cast const&>(other); + return this->failed() == otherBE.failed(); + } + + std::string toString() const override { + std::stringstream stream; + stream << "{" << this->name() << "} BE(const " << (this->failed() ? "failed" : "failsafe") << ")"; + return stream.str(); + } + + private: + bool mFailed; + + }; + + } +} diff --git a/src/storm-dft/storage/dft/elements/BEExponential.h b/src/storm-dft/storage/dft/elements/BEExponential.h new file mode 100644 index 000000000..3275aac15 --- /dev/null +++ b/src/storm-dft/storage/dft/elements/BEExponential.h @@ -0,0 +1,103 @@ +#pragma once + +#include "DFTBE.h" + +namespace storm { + namespace storage { + + /*! + * BE with exponential failure rate. + */ + template + class BEExponential : public DFTBE { + + public: + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param failureRate Active failure rate. + * @param dormancyFactor Dormancy factor. + * @param transient True iff the BE experiences transient failures. + */ + BEExponential(size_t id, std::string const& name, ValueType failureRate, ValueType dormancyFactor, bool transient = false) : + DFTBE(id, name), mActiveFailureRate(failureRate), mPassiveFailureRate(dormancyFactor * failureRate), mTransient(transient) { + STORM_LOG_ASSERT(!storm::utility::isZero(failureRate), "Exponential failure rate should not be zero."); + } + + DFTElementType type() const override { + return DFTElementType::BE_EXP; + } + + /*! + * Return failure rate in active state. + * @return Active failure rate. + */ + ValueType const& activeFailureRate() const { + return mActiveFailureRate; + } + + /*! + * Return failure rate in passive state. + * @return Passive failure rate. + */ + ValueType const& passiveFailureRate() const { + return mPassiveFailureRate; + } + + /*! + * Return dormancy factor given by passive_failure_rate/active_failure_rate. + * @return Dormancy factor. + */ + ValueType dormancyFactor() const { + if (storm::utility::isZero(this->activeFailureRate())) { + // Return default value of 1 + return storm::utility::one(); + } else { + return this->passiveFailureRate() / this->activeFailureRate(); + } + } + + /*! + * Return whether the BE experiences transient failures. + * @return True iff BE is transient. + */ + bool isTransient() const { + return mTransient; + } + + bool canFail() const override { + return !storm::utility::isZero(this->activeFailureRate()); + } + + /*! + * Return whether the BE is a cold BE, i.e., passive failure rate = 0. + * @return True iff BE is cold BE. + */ + bool isColdBasicElement() const { + return storm::utility::isZero(this->passiveFailureRate()); + } + + bool isTypeEqualTo(DFTElement const& other) const override { + if (!DFTElement::isTypeEqualTo(other)) { + return false; + } + auto& otherBE = static_cast const&>(other); + return (this->activeFailureRate() == otherBE.activeFailureRate()) && (this->passiveFailureRate() == otherBE.passiveFailureRate()); + } + + std::string toString() const override { + std::stringstream stream; + stream << "{" << this->name() << "} BE exp(" << this->activeFailureRate() << ", " << this->passiveFailureRate() << ")"; + return stream.str(); + } + + private: + ValueType mActiveFailureRate; + ValueType mPassiveFailureRate; + bool mTransient; + + }; + + } +} diff --git a/src/storm-dft/storage/dft/elements/DFTAnd.h b/src/storm-dft/storage/dft/elements/DFTAnd.h index 00f671837..c57e54c3b 100644 --- a/src/storm-dft/storage/dft/elements/DFTAnd.h +++ b/src/storm-dft/storage/dft/elements/DFTAnd.h @@ -39,12 +39,6 @@ namespace storm { return "AND"; } }; - - template - inline std::ostream& operator<<(std::ostream& os, DFTAnd const& gate) { - return os << gate.toString(); - } - } } diff --git a/src/storm-dft/storage/dft/elements/DFTBE.h b/src/storm-dft/storage/dft/elements/DFTBE.h index 84f05b5b1..912c4b42b 100644 --- a/src/storm-dft/storage/dft/elements/DFTBE.h +++ b/src/storm-dft/storage/dft/elements/DFTBE.h @@ -1,131 +1,98 @@ #pragma once + +#include "DFTElement.h" + namespace storm { namespace storage { + + /*! + * Abstract base class for basic elements (BEs) in DFTs. + */ template class DFTBE : public DFTElement { - - using DFTDependencyPointer = std::shared_ptr>; - using DFTDependencyVector = std::vector; - - protected: - ValueType mActiveFailureRate; - ValueType mPassiveFailureRate; - DFTDependencyVector mIngoingDependencies; - bool mTransient; public: - DFTBE(size_t id, std::string const& name, ValueType failureRate, ValueType dormancyFactor, bool transient = false) : - DFTElement(id, name), mActiveFailureRate(failureRate), mPassiveFailureRate(dormancyFactor * failureRate), mTransient(transient) - {} - - DFTElementType type() const override { - return DFTElementType::BE; + /*! + * Constructor. + * @param id Id. + * @param name Name. + */ + DFTBE(size_t id, std::string const& name) : DFTElement(id, name) { + // Intentionally empty } - virtual size_t nrChildren() const override { + size_t nrChildren() const override { return 0; } - ValueType const& activeFailureRate() const { - return mActiveFailureRate; - } - - ValueType const& passiveFailureRate() const { - return mPassiveFailureRate; - } - - ValueType dormancyFactor() const { - if (storm::utility::isZero(this->activeFailureRate())) { - // Return default value of 0 - return storm::utility::zero(); - } else { - return this->passiveFailureRate() / this->activeFailureRate(); - } - } + /*! + * Return whether the BE can fail. + * @return True iff BE is not failsafe. + */ + virtual bool canFail() const = 0; - bool isTransient() const { - return mTransient; - } - - bool canFail() const { - return !storm::utility::isZero(mActiveFailureRate); - } - - bool addIngoingDependency(DFTDependencyPointer const& e) { - // TODO write this assertion for n-ary dependencies, probably by addign a method to the dependencies to support this. + /*! + * Add dependency which can trigger this BE. + * @param dependency Ingoing dependency. + */ + void addIngoingDependency(std::shared_ptr> const& dependency) { + // TODO write this assertion for n-ary dependencies, probably by adding a method to the dependencies to support this. //STORM_LOG_ASSERT(e->dependentEvent()->id() == this->id(), "Ids do not match."); - if(std::find(mIngoingDependencies.begin(), mIngoingDependencies.end(), e) != mIngoingDependencies.end()) { - return false; - } - else - { - mIngoingDependencies.push_back(e); - return true; - } + STORM_LOG_ASSERT(std::find(mIngoingDependencies.begin(), mIngoingDependencies.end(), dependency) == mIngoingDependencies.end(), + "Ingoing Dependency " << dependency << " already present."); + mIngoingDependencies.push_back(dependency); } - + + /*! + * Return whether the BE has ingoing dependencies. + * @return True iff BE can be triggered by dependencies. + */ bool hasIngoingDependencies() const { return !mIngoingDependencies.empty(); } - - size_t nrIngoingDependencies() const { - return mIngoingDependencies.size(); - } - - DFTDependencyVector const& ingoingDependencies() const { + + /*! + * Return ingoing dependencies. + * @return List of dependencies which can trigger this BE. + */ + std::vector>> const& ingoingDependencies() const { return mIngoingDependencies; } - - std::string toString() const override { - std::stringstream stream; - stream << *this; - return stream.str(); - } - + bool isBasicElement() const override { return true; } - - bool isColdBasicElement() const { - return storm::utility::isZero(mPassiveFailureRate); - } - - virtual void extendSubDft(std::set& elemsInSubtree, std::vector const& parentsOfSubRoot, bool blockParents, bool sparesAsLeaves) const override { - if(elemsInSubtree.count(this->id())) { + + void extendSubDft(std::set& elemsInSubtree, std::vector const& parentsOfSubRoot, bool blockParents, bool sparesAsLeaves) const override { + if (elemsInSubtree.count(this->id())) { return; } DFTElement::extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); - if(elemsInSubtree.empty()) { + if (elemsInSubtree.empty()) { // Parent in the subdft, ie it is *not* a subdft return; } - for(auto const& incDep : mIngoingDependencies) { + for (auto const& incDep : ingoingDependencies()) { incDep->extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); - if(elemsInSubtree.empty()) { + if (elemsInSubtree.empty()) { // Parent in the subdft, ie it is *not* a subdft return; } } } - - bool isTypeEqualTo(DFTElement const& other) const override { - if(!DFTElement::isTypeEqualTo(other)) return false; - DFTBE const& otherBE = static_cast const&>(other); - return (mActiveFailureRate == otherBE.mActiveFailureRate) && (mPassiveFailureRate == otherBE.mPassiveFailureRate); - } - - virtual bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { - if(DFTElement::checkDontCareAnymore(state, queues)) { - state.beNoLongerFailable(this->mId); + + bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { + if (DFTElement::checkDontCareAnymore(state, queues)) { + state.beNoLongerFailable(this->id()); return true; } return false; } + + private: + std::vector>> mIngoingDependencies; + }; - template - inline std::ostream& operator<<(std::ostream& os, DFTBE const& be) { - return os << "{" << be.name() << "} BE(" << be.activeFailureRate() << ", " << be.passiveFailureRate() << ")"; - } } } diff --git a/src/storm-dft/storage/dft/elements/DFTConst.h b/src/storm-dft/storage/dft/elements/DFTConst.h deleted file mode 100644 index 6ff4cd39e..000000000 --- a/src/storm-dft/storage/dft/elements/DFTConst.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - - -#include "DFTElement.h" -namespace storm { - namespace storage { - template - class DFTConst : public DFTElement { - - bool mFailed; - - public: - DFTConst(size_t id, std::string const& name, bool failed) : - DFTElement(id, name), mFailed(failed) - {} - - DFTElementType type() const override { - if(mFailed) { - return DFTElementType::CONSTF; - } else { - return DFTElementType::CONSTS; - } - } - - - bool failed() const { - return mFailed; - } - - virtual bool isConstant() const override { - return true; - } - - virtual size_t nrChildren() const override { - return 0; - } - - std::string toString() const override { - std::stringstream stream; - stream << *this; - return stream.str(); - } - - bool isTypeEqualTo(DFTElement const& other) const override { - if(!DFTElement::isTypeEqualTo(other)) return false; - DFTConst const& otherCNST = static_cast const&>(other); - return (mFailed == otherCNST.mFailed); - } - - }; - - template - inline std::ostream& operator<<(std::ostream& os, DFTConst const& be) { - return os << "{" << be.name() << "} BE(const " << (be.failed() ? "failed" : "failsafe") << ")"; - } - - } -} diff --git a/src/storm-dft/storage/dft/elements/DFTDependency.h b/src/storm-dft/storage/dft/elements/DFTDependency.h index c1d877cb3..b398518ad 100644 --- a/src/storm-dft/storage/dft/elements/DFTDependency.h +++ b/src/storm-dft/storage/dft/elements/DFTDependency.h @@ -102,14 +102,14 @@ namespace storm { virtual std::string toString() const override { std::stringstream stream; - bool fdep = storm::utility::isOne(mProbability); - stream << "{" << this->name() << "} " << (fdep ? "FDEP" : "PDEP") << "(" << mTriggerEvent->name() << " => { "; - for(auto const& depEv : mDependentEvents) { + bool isFDEP = storm::utility::isOne(this->probability()); + stream << "{" << this->name() << "} " << (isFDEP ? "FDEP" : "PDEP") << "(" << this->triggerEvent()->name() << " => { "; + for(auto const& depEv : this->dependentEvents()) { stream << depEv->name() << " "; } stream << "}"; - if (!fdep) { - stream << " with probability " << mProbability; + if (!isFDEP) { + stream << " with probability " << this->probability(); } return stream.str(); } diff --git a/src/storm-dft/storage/dft/elements/DFTElement.h b/src/storm-dft/storage/dft/elements/DFTElement.h index d5d82db5a..2c43bdab8 100644 --- a/src/storm-dft/storage/dft/elements/DFTElement.h +++ b/src/storm-dft/storage/dft/elements/DFTElement.h @@ -9,11 +9,9 @@ #include #include - - -#include "../DFTElementType.h" -#include "../DFTState.h" -#include "../DFTStateSpaceGenerationQueues.h" +#include "storm-dft/storage/dft/DFTElementType.h" +#include "storm-dft/storage/dft/DFTState.h" +#include "storm-dft/storage/dft/DFTStateSpaceGenerationQueues.h" #include "storm/utility/constants.h" #include "storm/adapters/RationalFunctionAdapter.h" @@ -24,6 +22,8 @@ namespace storm { namespace storage { using std::size_t; + + // Forward declarations template class DFTGate; @@ -54,41 +54,84 @@ namespace storm { public: - DFTElement(size_t id, std::string const& name) : - mId(id), mName(name) - {} + /*! + * Constructor. + * @param id Id. + * @param name Name. + */ + DFTElement(size_t id, std::string const& name) : mId(id), mName(name) { + } - virtual ~DFTElement() {} + /*! + * Destructor. + */ + virtual ~DFTElement() { + } - /** - * Returns the id + /*! + * Get id. + * @return Id. */ virtual size_t id() const { return mId; } - virtual DFTElementType type() const = 0; + /*! + * Set id. + * @param id Id. + */ + virtual void setId(size_t id) { + this->mId = id; + } - virtual void setRank(size_t rank) { - mRank = rank; + /*! + * Get name. + * @return Name. + */ + virtual std::string const& name() const { + return mName; } - + + + /*! + * Get type. + * @return Type. + */ + virtual DFTElementType type() const = 0; + + /*! + * Get rank. + * @return Rank. + */ virtual size_t rank() const { return mRank; } - + + /*! + * Set rank. + * @param rank Rank. + */ + virtual void setRank(size_t rank) { + this->mRank = rank; + } + virtual bool isConstant() const { return false; } - - virtual bool isGate() const { + + /*! + * Checks whether the element is a basic element. + * @return True iff element is a BE. + */ + virtual bool isBasicElement() const { return false; } - /** - * Returns true if the element is a BE + /*! + * Check wether the element is a gate. + * @return True iff element is a gate. */ - virtual bool isBasicElement() const { + virtual bool isGate() const { return false; } @@ -107,17 +150,7 @@ namespace storm { return false; } - virtual void setId(size_t newId) { - mId = newId; - } - /** - * Returns the name - */ - virtual std::string const& name() const { - return mName; - } - bool addParent(DFTGatePointer const& e) { if(std::find(mParents.begin(), mParents.end(), e) != mParents.end()) { return false; @@ -260,8 +293,6 @@ namespace storm { virtual std::size_t nrChildren() const = 0; - virtual std::string toString() const = 0; - virtual bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const; /** @@ -292,14 +323,23 @@ namespace storm { return type() == other.type(); } + /*! + * Print information about element to string. + * @return Element information. + */ + virtual std::string toString() const = 0; + protected: // virtual bool checkIsomorphicSubDftHelper(DFTElement const& otherElem, std::vector>& mapping, std::vector const& order ) const = 0; }; - - - + + + template + inline std::ostream& operator<<(std::ostream& os, DFTElement const& element) { + return os << element.toString(); + } template bool equalType(DFTElement const& e1, DFTElement const& e2) { diff --git a/src/storm-dft/storage/dft/elements/DFTOr.h b/src/storm-dft/storage/dft/elements/DFTOr.h index d614b095a..f45bb4b5b 100644 --- a/src/storm-dft/storage/dft/elements/DFTOr.h +++ b/src/storm-dft/storage/dft/elements/DFTOr.h @@ -36,10 +36,6 @@ namespace storm { } }; - template - inline std::ostream& operator<<(std::ostream& os, DFTOr const& gate) { - return os << gate.toString(); - } } } diff --git a/src/storm-dft/storage/dft/elements/DFTPand.h b/src/storm-dft/storage/dft/elements/DFTPand.h index 21cda29a9..7b03b7196 100644 --- a/src/storm-dft/storage/dft/elements/DFTPand.h +++ b/src/storm-dft/storage/dft/elements/DFTPand.h @@ -55,11 +55,6 @@ namespace storm { protected: bool inclusive; }; - - template - inline std::ostream& operator<<(std::ostream& os, DFTPand const& gate) { - return os << gate.toString(); - } } } diff --git a/src/storm-dft/storage/dft/elements/DFTPor.h b/src/storm-dft/storage/dft/elements/DFTPor.h index 857e19714..1e92384cd 100644 --- a/src/storm-dft/storage/dft/elements/DFTPor.h +++ b/src/storm-dft/storage/dft/elements/DFTPor.h @@ -52,10 +52,5 @@ namespace storm { bool inclusive; }; - template - inline std::ostream& operator<<(std::ostream& os, DFTPor const& gate) { - return os << gate.toString(); - } - } } diff --git a/src/storm-dft/storage/dft/elements/DFTRestriction.h b/src/storm-dft/storage/dft/elements/DFTRestriction.h index d4efde050..10392e05c 100644 --- a/src/storm-dft/storage/dft/elements/DFTRestriction.h +++ b/src/storm-dft/storage/dft/elements/DFTRestriction.h @@ -106,21 +106,6 @@ namespace storm { } } - - virtual std::string toString() const override { - std::stringstream stream; - stream << "{" << this->name() << "} " << typestring() << "( "; - typename DFTElementVector::const_iterator it = mChildren.begin(); - stream << (*it)->name(); - ++it; - while(it != mChildren.end()) { - stream << ", " << (*it)->name(); - ++it; - } - stream << ")"; - return stream.str(); - } - virtual bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { return false; } @@ -155,11 +140,24 @@ namespace storm { return false; } - + virtual std::string toString() const override { + std::stringstream stream; + stream << "{" << this->name() << "} " << this->typestring() << "( "; + auto it = this->children().begin(); + stream << (*it)->name(); + ++it; + while(it != this->children().end()) { + stream << ", " << (*it)->name(); + ++it; + } + stream << ")"; + return stream.str(); + } }; + template class DFTSeq : public DFTRestriction { diff --git a/src/storm-dft/storage/dft/elements/DFTSpare.h b/src/storm-dft/storage/dft/elements/DFTSpare.h index 8593c6fd1..7584a1f94 100644 --- a/src/storm-dft/storage/dft/elements/DFTSpare.h +++ b/src/storm-dft/storage/dft/elements/DFTSpare.h @@ -105,5 +105,6 @@ namespace storm { }; + } } diff --git a/src/storm-dft/storage/dft/elements/DFTVot.h b/src/storm-dft/storage/dft/elements/DFTVot.h index 0b03954ca..791926a97 100644 --- a/src/storm-dft/storage/dft/elements/DFTVot.h +++ b/src/storm-dft/storage/dft/elements/DFTVot.h @@ -71,10 +71,5 @@ namespace storm { } }; - template - inline std::ostream& operator<<(std::ostream& os, DFTVot const& gate) { - return os << gate.toString(); - } - } } diff --git a/src/storm-dft/transformations/DftToGspnTransformator.cpp b/src/storm-dft/transformations/DftToGspnTransformator.cpp index 144981117..60a4d04e5 100644 --- a/src/storm-dft/transformations/DftToGspnTransformator.cpp +++ b/src/storm-dft/transformations/DftToGspnTransformator.cpp @@ -122,14 +122,11 @@ namespace storm { // Check which type the element is and call the corresponding translate-function. switch (dftElement->type()) { - case storm::storage::DFTElementType::BE: - translateBE(std::static_pointer_cast const>(dftElement)); + case storm::storage::DFTElementType::BE_EXP: + translateBEExponential(std::static_pointer_cast const>(dftElement)); break; - case storm::storage::DFTElementType::CONSTF: - translateCONSTF(dftElement); - break; - case storm::storage::DFTElementType::CONSTS: - translateCONSTS(dftElement); + case storm::storage::DFTElementType::BE_CONST: + translateBEConst(std::static_pointer_cast const>(dftElement)); break; case storm::storage::DFTElementType::AND: translateAND(std::static_pointer_cast const>(dftElement)); @@ -163,7 +160,7 @@ namespace storm { translateSeq(std::static_pointer_cast const>(dftElement)); break; default: - STORM_LOG_ASSERT(false, "DFT type " << dftElement->type() << " unknown."); + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "DFT type '" << dftElement->type() << "' not known."); break; } } @@ -171,8 +168,7 @@ namespace storm { } template - void DftToGspnTransformator::translateBE( - std::shared_ptr const> dftBE) { + void DftToGspnTransformator::translateBEExponential(std::shared_ptr const> dftBE) { double xcenter = mDft.getElementLayoutInfo(dftBE->id()).x; double ycenter = mDft.getElementLayoutInfo(dftBE->id()).y; @@ -260,35 +256,30 @@ namespace storm { } template - void DftToGspnTransformator::translateCONSTF( - std::shared_ptr const> dftConstF) { - double xcenter = mDft.getElementLayoutInfo(dftConstF->id()).x; - double ycenter = mDft.getElementLayoutInfo(dftConstF->id()).y; - - addFailedPlace(dftConstF, storm::gspn::LayoutInfo(xcenter, ycenter - 3.0), true); - - if (!smart || mDft.isRepresentative(dftConstF->id())) { - addUnavailablePlace(dftConstF, storm::gspn::LayoutInfo(xcenter, ycenter + 3.0), false); - } - } - - template - void DftToGspnTransformator::translateCONSTS( - std::shared_ptr const> dftConstS) { - double xcenter = mDft.getElementLayoutInfo(dftConstS->id()).x; - double ycenter = mDft.getElementLayoutInfo(dftConstS->id()).y; + void DftToGspnTransformator::translateBEConst(std::shared_ptr const> dftConst) { + double xcenter = mDft.getElementLayoutInfo(dftConst->id()).x; + double ycenter = mDft.getElementLayoutInfo(dftConst->id()).y; - size_t capacity = 0; // It cannot contain a token, because it cannot fail. + if (dftConst->failed()) { + // Constant failed BE + addFailedPlace(dftConst, storm::gspn::LayoutInfo(xcenter, ycenter - 3.0), true); - uint64_t failedPlace = builder.addPlace(capacity, 0, dftConstS->name() + STR_FAILED); - assert(failedPlaces.size() == dftConstS->id()); - failedPlaces.push_back(failedPlace); - builder.setPlaceLayoutInfo(failedPlace, storm::gspn::LayoutInfo(xcenter, ycenter - 3.0)); + if (!smart || mDft.isRepresentative(dftConst->id())) { + addUnavailablePlace(dftConst, storm::gspn::LayoutInfo(xcenter, ycenter + 3.0), false); + } + } else { + // Constant failsafe BE + size_t capacity = 0; // It cannot contain a token, because it cannot fail. + uint64_t failedPlace = builder.addPlace(capacity, 0, dftConst->name() + STR_FAILED); + assert(failedPlaces.size() == dftConst->id()); + failedPlaces.push_back(failedPlace); + builder.setPlaceLayoutInfo(failedPlace, storm::gspn::LayoutInfo(xcenter, ycenter - 3.0)); - if (!smart || mDft.isRepresentative(dftConstS->id())) { - uint64_t unavailablePlace = builder.addPlace(capacity, 0, dftConstS->name() + "_unavail"); - unavailablePlaces.emplace(dftConstS->id(), unavailablePlace); - builder.setPlaceLayoutInfo(unavailablePlace, storm::gspn::LayoutInfo(xcenter, ycenter + 3.0)); + if (!smart || mDft.isRepresentative(dftConst->id())) { + uint64_t unavailablePlace = builder.addPlace(capacity, 0, dftConst->name() + "_unavail"); + unavailablePlaces.emplace(dftConst->id(), unavailablePlace); + builder.setPlaceLayoutInfo(unavailablePlace, storm::gspn::LayoutInfo(xcenter, ycenter + 3.0)); + } } } diff --git a/src/storm-dft/transformations/DftToGspnTransformator.h b/src/storm-dft/transformations/DftToGspnTransformator.h index 0e60866fc..72b6d1831 100644 --- a/src/storm-dft/transformations/DftToGspnTransformator.h +++ b/src/storm-dft/transformations/DftToGspnTransformator.h @@ -62,25 +62,18 @@ namespace storm { void translateGSPNElements(); /*! - * Translate a GSPN Basic Event. + * Translate an exponential BE. * - * @param dftBE The Basic Event. + * @param dftBE The exponential Basic Event. */ - void translateBE(std::shared_ptr const> dftBE); + void translateBEExponential(std::shared_ptr const> dftBE); /*! - * Translate a GSPN CONSTF (Constant Failure, a Basic Event that has already failed). + * Translate a constant BE * - * @param dftPor The CONSTF Basic Event. + * @param dftConst The constant Basic Event. */ - void translateCONSTF(std::shared_ptr const> dftConstF); - - /*! - * Translate a GSPN CONSTS (Constant Save, a Basic Event that cannot fail). - * - * @param dftPor The CONSTS Basic Event. - */ - void translateCONSTS(std::shared_ptr const> dftConstS); + void translateBEConst(std::shared_ptr const> dftConst); /*! * Translate a GSPN AND. From 1d7c5caaf2b08140690d333cd0c6d0a2a2555cf2 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 3 Apr 2019 17:26:32 +0200 Subject: [PATCH 19/40] Fixed bitshift for DFT isomorphism --- src/storm-dft/storage/dft/DFTIsomorphism.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-dft/storage/dft/DFTIsomorphism.h b/src/storm-dft/storage/dft/DFTIsomorphism.h index ab823b00a..24a7e4252 100644 --- a/src/storm-dft/storage/dft/DFTIsomorphism.h +++ b/src/storm-dft/storage/dft/DFTIsomorphism.h @@ -14,7 +14,7 @@ namespace storage { struct GateGroupToHash { static constexpr uint_fast64_t fivebitmask = (1 << 6) - 1; - static constexpr uint_fast64_t eightbitmask = (1 << 8) - 1; + static constexpr uint_fast64_t eightbitmask = (1 << 9) - 1; /** * Hash function, which ensures that the colours are sorted according to their rank. From ff22a973debacd1c455ebf258974635c07d19f90 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 3 Apr 2019 23:17:43 +0200 Subject: [PATCH 20/40] Refactoring DFT elements --- src/storm-dft/builder/DFTBuilder.cpp | 10 +- src/storm-dft/storage/dft/DFT.cpp | 1 + src/storm-dft/storage/dft/elements/BEConst.h | 3 +- .../storage/dft/elements/BEExponential.h | 2 +- src/storm-dft/storage/dft/elements/DFTAnd.h | 45 +++--- src/storm-dft/storage/dft/elements/DFTBE.h | 16 +- .../storage/dft/elements/DFTDependency.h | 147 ++++++++++++------ src/storm-dft/storage/dft/elements/DFTGate.h | 4 +- src/storm-dft/storage/dft/elements/DFTOr.h | 46 +++--- src/storm-dft/storage/dft/elements/DFTPand.h | 77 +++++---- src/storm-dft/storage/dft/elements/DFTPor.h | 81 ++++++---- src/storm-dft/storage/dft/elements/DFTVot.h | 92 ++++++----- 12 files changed, 330 insertions(+), 194 deletions(-) diff --git a/src/storm-dft/builder/DFTBuilder.cpp b/src/storm-dft/builder/DFTBuilder.cpp index 56fda6401..3c856407b 100644 --- a/src/storm-dft/builder/DFTBuilder.cpp +++ b/src/storm-dft/builder/DFTBuilder.cpp @@ -74,12 +74,10 @@ namespace storm { childElement->addOutgoingDependency(elem.first); } } - if (binaryDependencies) { - STORM_LOG_ASSERT(dependencies.size() == 1, "Dependency '" << elem.first->name() << "' should only have one dependent element."); - } - elem.first->setDependentEvents(dependencies); - for (auto& dependency : dependencies) { - dependency->addIngoingDependency(elem.first); + STORM_LOG_ASSERT(!binaryDependencies || dependencies.size() == 1, "Dependency '" << elem.first->name() << "' should only have one dependent element."); + for (auto& be : dependencies) { + elem.first->addDependentEvent(be); + be->addIngoingDependency(elem.first); } } diff --git a/src/storm-dft/storage/dft/DFT.cpp b/src/storm-dft/storage/dft/DFT.cpp index c66af8550..a9ecb8a5a 100644 --- a/src/storm-dft/storage/dft/DFT.cpp +++ b/src/storm-dft/storage/dft/DFT.cpp @@ -621,6 +621,7 @@ namespace storm { } } } + // TODO check VOT gates return wellformed; } diff --git a/src/storm-dft/storage/dft/elements/BEConst.h b/src/storm-dft/storage/dft/elements/BEConst.h index 22cb13b9a..2cbf9fd38 100644 --- a/src/storm-dft/storage/dft/elements/BEConst.h +++ b/src/storm-dft/storage/dft/elements/BEConst.h @@ -7,6 +7,7 @@ namespace storm { /*! * BE which is either constant failed or constant failsafe. + * The BE is either always failed (from the beginning) or can never fail (failsafe). */ template class BEConst : public DFTBE { @@ -38,7 +39,7 @@ namespace storm { return this->failed(); } - bool isTypeEqualTo(DFTElement const& other) const override { + bool isTypeEqualTo(DFTElement const& other) const override { if (!DFTElement::isTypeEqualTo(other)) { return false; } diff --git a/src/storm-dft/storage/dft/elements/BEExponential.h b/src/storm-dft/storage/dft/elements/BEExponential.h index 3275aac15..8347f3179 100644 --- a/src/storm-dft/storage/dft/elements/BEExponential.h +++ b/src/storm-dft/storage/dft/elements/BEExponential.h @@ -78,7 +78,7 @@ namespace storm { return storm::utility::isZero(this->passiveFailureRate()); } - bool isTypeEqualTo(DFTElement const& other) const override { + bool isTypeEqualTo(DFTElement const& other) const override { if (!DFTElement::isTypeEqualTo(other)) { return false; } diff --git a/src/storm-dft/storage/dft/elements/DFTAnd.h b/src/storm-dft/storage/dft/elements/DFTAnd.h index c57e54c3b..aab72d436 100644 --- a/src/storm-dft/storage/dft/elements/DFTAnd.h +++ b/src/storm-dft/storage/dft/elements/DFTAnd.h @@ -1,44 +1,53 @@ -#pragma once +#pragma once + #include "DFTGate.h" namespace storm { namespace storage { + + /*! + * AND gate. + * Fails if all children have failed. + */ template class DFTAnd : public DFTGate { - + public: - DFTAnd(size_t id, std::string const& name, std::vector>> const& children = {}) : - DFTGate(id, name, children) - {} + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param children Children. + */ + DFTAnd(size_t id, std::string const& name, std::vector>> const& children = {}) : DFTGate(id, name, children) { + // Intentionally empty + } + + DFTElementType type() const override { + return DFTElementType::AND; + } void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { - if(state.isOperational(this->mId)) { - for(auto const& child : this->mChildren) - { - if(!state.hasFailed(child->id())) { + if (state.isOperational(this->mId)) { + for (auto const& child : this->mChildren) { + if (!state.hasFailed(child->id())) { return; } } + // All children have failed this->fail(state, queues); } } void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { STORM_LOG_ASSERT(this->hasFailsafeChild(state), "No failsafe child."); - if(state.isOperational(this->mId)) { + if (state.isOperational(this->mId)) { this->failsafe(state, queues); this->childrenDontCare(state, queues); } } - virtual DFTElementType type() const override { - return DFTElementType::AND; - } - - std::string typestring() const override { - return "AND"; - } }; - + } } diff --git a/src/storm-dft/storage/dft/elements/DFTBE.h b/src/storm-dft/storage/dft/elements/DFTBE.h index 912c4b42b..38eeb4de1 100644 --- a/src/storm-dft/storage/dft/elements/DFTBE.h +++ b/src/storm-dft/storage/dft/elements/DFTBE.h @@ -6,7 +6,8 @@ namespace storm { namespace storage { /*! - * Abstract base class for basic elements (BEs) in DFTs. + * Abstract base class for basic events (BEs) in DFTs. + * BEs are atomic and not further subdivided. */ template class DFTBE : public DFTElement { @@ -36,8 +37,7 @@ namespace storm { * @param dependency Ingoing dependency. */ void addIngoingDependency(std::shared_ptr> const& dependency) { - // TODO write this assertion for n-ary dependencies, probably by adding a method to the dependencies to support this. - //STORM_LOG_ASSERT(e->dependentEvent()->id() == this->id(), "Ids do not match."); + STORM_LOG_ASSERT(dependency->containsDependentEvent(this->id()), "Dependency " << *dependency << " has no dependent BE " << *this << "."); STORM_LOG_ASSERT(std::find(mIngoingDependencies.begin(), mIngoingDependencies.end(), dependency) == mIngoingDependencies.end(), "Ingoing Dependency " << dependency << " already present."); mIngoingDependencies.push_back(dependency); @@ -69,19 +69,19 @@ namespace storm { } DFTElement::extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); if (elemsInSubtree.empty()) { - // Parent in the subdft, ie it is *not* a subdft + // Parent in the subDFT, i.e., it is *not* a subDFT return; } - for (auto const& incDep : ingoingDependencies()) { - incDep->extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); + for (auto const& inDep : ingoingDependencies()) { + inDep->extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); if (elemsInSubtree.empty()) { - // Parent in the subdft, ie it is *not* a subdft + // Parent in the subDFT, i.e., it is *not* a subDFT return; } } } - bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { + bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { if (DFTElement::checkDontCareAnymore(state, queues)) { state.beNoLongerFailable(this->id()); return true; diff --git a/src/storm-dft/storage/dft/elements/DFTDependency.h b/src/storm-dft/storage/dft/elements/DFTDependency.h index b398518ad..2ef183693 100644 --- a/src/storm-dft/storage/dft/elements/DFTDependency.h +++ b/src/storm-dft/storage/dft/elements/DFTDependency.h @@ -1,120 +1,175 @@ #pragma once - #include "DFTElement.h" + namespace storm { namespace storage { - + + /*! + * Dependency gate with probability p. + * If p=1 the gate is a functional dependency (FDEP), otherwise it is a probabilistic dependency (PDEP). + * + * If the trigger event (i.e., the first child) fails, a coin is flipped. + * With probability p the failure is forwarded to all other children. + * With probability 1-p the failure is not forwarded and the dependency has no effect. + * + * The failure forwarding to the children happens in a strict (non-deterministically chosen) order. + */ template class DFTDependency : public DFTElement { using DFTGatePointer = std::shared_ptr>; using DFTBEPointer = std::shared_ptr>; - - protected: - ValueType mProbability; - DFTGatePointer mTriggerEvent; - std::vector mDependentEvents; public: - DFTDependency(size_t id, std::string const& name, ValueType probability) : - DFTElement(id, name), mProbability(probability) - { + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param probability Probability p of failure forwarding. + */ + DFTDependency(size_t id, std::string const& name, ValueType probability) : DFTElement(id, name), mProbability(probability) { + // We cannot assert 0<=p<=1 in general, because ValueType might be RationalFunction. } - virtual ~DFTDependency() {} - - void setTriggerElement(DFTGatePointer const& triggerEvent) { - mTriggerEvent = triggerEvent; - - } - - void setDependentEvents(std::vector const& dependentEvents) { - mDependentEvents = dependentEvents; + DFTElementType type() const override { + return DFTElementType::PDEP; } - + /*! + * Get probability of forwarding the failure. + * @return Probability. + */ ValueType const& probability() const { return mProbability; } + /*! + * Get trigger event, i.e., the first child. + * @return Trigger event. + */ DFTGatePointer const& triggerEvent() const { STORM_LOG_ASSERT(mTriggerEvent, "Trigger does not exist."); return mTriggerEvent; } + /*! + * Set the trigger event, i.e., the first child. + * @param triggerEvent Trigger event. + */ + void setTriggerElement(DFTGatePointer const& triggerEvent) { + mTriggerEvent = triggerEvent; + } + + /*! + * Get dependent events. + * @return Dependent events. + */ std::vector const& dependentEvents() const { - STORM_LOG_ASSERT(mDependentEvents.size() > 0, "Dependent element does not exists."); + STORM_LOG_ASSERT(mDependentEvents.size() > 0, "Dependent event does not exists."); return mDependentEvents; } - DFTElementType type() const override { - return DFTElementType::PDEP; + /*! + * Add dependent event. + * @param dependentEvent Dependent event. + */ + void addDependentEvent(DFTBEPointer const& dependentEvent) { + mDependentEvents.push_back(dependentEvent); } + /*! + * Check whether the given element is a dependent event. + * @param id Id of element to search for. + * @return True iff element was found in dependent events. + */ + bool containsDependentEvent(size_t id) { + auto it = std::find_if(this->mDependentEvents.begin(), this->mDependentEvents.end(), [&id](DFTBEPointer be) -> bool { + return be->id() == id; + }); + return it != this->mDependentEvents.end(); + } + + virtual size_t nrChildren() const override { return 1; } - virtual bool isDependency() const override { + bool isDependency() const override { return true; } - - virtual bool isTypeEqualTo(DFTElement const& other) const override { - if(!DFTElement::isTypeEqualTo(other)) return false; - DFTDependency const& otherDEP= static_cast const&>(other); - return (mProbability == otherDEP.mProbability); + + /*! + * Check whether the dependency is an FDEP, i.e., p=1. + * @return True iff p=1. + */ + bool isFDEP() const { + return storm::utility::isOne(this->probability()); + } + + bool isTypeEqualTo(DFTElement const& other) const override { + if (!DFTElement::isTypeEqualTo(other)) { + return false; + } + auto& otherDEP = static_cast const&>(other); + return this->probability() == otherDEP.probability(); } - virtual void extendSpareModule(std::set& elementsInSpareModule) const override { + void extendSpareModule(std::set& elementsInSpareModule) const override { // Do nothing } - virtual std::vector independentUnit() const override { + std::vector independentUnit() const override { std::set unit = {this->mId}; - for(auto const& depEv : mDependentEvents) { + for (auto const& depEv : mDependentEvents) { depEv->extendUnit(unit); - if(unit.count(mTriggerEvent->id()) != 0) { + if (unit.count(mTriggerEvent->id()) != 0) { return {}; } } return std::vector(unit.begin(), unit.end()); } - virtual void extendSubDft(std::set& elemsInSubtree, std::vector const& parentsOfSubRoot, bool blockParents, bool sparesAsLeaves) const override { - if(elemsInSubtree.count(this->id())) return; + void extendSubDft(std::set& elemsInSubtree, std::vector const& parentsOfSubRoot, bool blockParents, bool sparesAsLeaves) const override { + if (elemsInSubtree.count(this->id())) { + return; + } DFTElement::extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); - if(elemsInSubtree.empty()) { + if (elemsInSubtree.empty()) { // Parent in the subdft, ie it is *not* a subdft return; } for (auto const& depEv : mDependentEvents) { depEv->extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); - if (elemsInSubtree.empty()) return; + if (elemsInSubtree.empty()) { + return; + } } - if(elemsInSubtree.empty()) { + if (elemsInSubtree.empty()) { // Parent in the subdft, ie it is *not* a subdft return; } mTriggerEvent->extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); - + } - - virtual std::string toString() const override { + + std::string toString() const override { std::stringstream stream; - bool isFDEP = storm::utility::isOne(this->probability()); - stream << "{" << this->name() << "} " << (isFDEP ? "FDEP" : "PDEP") << "(" << this->triggerEvent()->name() << " => { "; - for(auto const& depEv : this->dependentEvents()) { + stream << "{" << this->name() << "} " << (this->isFDEP() ? "FDEP" : "PDEP") << "(" << this->triggerEvent()->name() << " => { "; + for (auto const& depEv : this->dependentEvents()) { stream << depEv->name() << " "; } stream << "}"; - if (!isFDEP) { + if (!this->isFDEP()) { stream << " with probability " << this->probability(); } return stream.str(); } - protected: + private: + ValueType mProbability; + DFTGatePointer mTriggerEvent; + std::vector mDependentEvents; }; diff --git a/src/storm-dft/storage/dft/elements/DFTGate.h b/src/storm-dft/storage/dft/elements/DFTGate.h index 39020f6cc..bbf856b14 100644 --- a/src/storm-dft/storage/dft/elements/DFTGate.h +++ b/src/storm-dft/storage/dft/elements/DFTGate.h @@ -40,7 +40,9 @@ namespace storm { } - virtual std::string typestring() const = 0; + virtual std::string typestring() const { + return storm::storage::toString(this->type()); + } virtual void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const = 0; diff --git a/src/storm-dft/storage/dft/elements/DFTOr.h b/src/storm-dft/storage/dft/elements/DFTOr.h index f45bb4b5b..4f5c8b2e0 100644 --- a/src/storm-dft/storage/dft/elements/DFTOr.h +++ b/src/storm-dft/storage/dft/elements/DFTOr.h @@ -1,39 +1,49 @@ -#pragma once +#pragma once #include "DFTGate.h" + namespace storm { namespace storage { + + /*! + * OR gate. + * Fails if at least one child has failed. + */ template class DFTOr : public DFTGate { public: - DFTOr(size_t id, std::string const& name, std::vector>> const& children = {}) : - DFTGate(id, name, children) - {} + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param children Children. + */ + DFTOr(size_t id, std::string const& name, std::vector>> const& children = {}) : DFTGate(id, name, children) { + // Intentionally empty + } + + DFTElementType type() const override { + return DFTElementType::OR; + } void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { STORM_LOG_ASSERT(this->hasFailedChild(state), "No failed child."); - if(state.isOperational(this->mId)) { + if (state.isOperational(this->mId)) { this->fail(state, queues); } } void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { - for(auto const& child : this->mChildren) { - if(!state.isFailsafe(child->id())) { - return; - } - } - this->failsafe(state, queues); + for (auto const& child : this->mChildren) { + if (!state.isFailsafe(child->id())) { + return; + } + } + // All chidren are failsafe + this->failsafe(state, queues); } - virtual DFTElementType type() const override { - return DFTElementType::OR; - } - - std::string typestring() const override { - return "OR"; - } }; } diff --git a/src/storm-dft/storage/dft/elements/DFTPand.h b/src/storm-dft/storage/dft/elements/DFTPand.h index 7b03b7196..33ad6c399 100644 --- a/src/storm-dft/storage/dft/elements/DFTPand.h +++ b/src/storm-dft/storage/dft/elements/DFTPand.h @@ -1,57 +1,78 @@ -#pragma once +#pragma once #include "DFTGate.h" + namespace storm { namespace storage { - template + + /*! + * Priority AND (PAND) gate. + * Fails if all children fail in order from first to last child. + * If a child fails before its left sibling, the PAND becomes failsafe. + * For inclusive PAND<= gates, simultaneous failures are allowed. + * For exclusive PAND< gates, simultaneous failure make the gate failsafe. + */ + template class DFTPand : public DFTGate { public: - DFTPand(size_t id, std::string const& name, bool inclusive, std::vector>> const& children = {}) : - DFTGate(id, name, children), - inclusive(inclusive) - {} - - void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { - assert(inclusive); - if(state.isOperational(this->mId)) { + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param inclusive If true, simultaneous failures are allowed. + * parame children Children. + */ + DFTPand(size_t id, std::string const& name, bool inclusive, std::vector>> const& children = {}) : DFTGate(id, name, children), inclusive(inclusive) { + // Intentionally left empty. + } + + DFTElementType type() const override { + return DFTElementType::PAND; + } + + std::string typestring() const override { + return isInclusive() ? "PAND (incl)" : "PAND (excl)"; + } + + /*! + * Return whether the PAND is inclusive. + * @return True iff PAND is inclusive. + */ + bool isInclusive() const { + return inclusive; + } + + void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { + STORM_LOG_ASSERT(isInclusive(), "Exclusive PAND not supported."); + if (state.isOperational(this->mId)) { bool childOperationalBefore = false; - for(auto const& child : this->mChildren) - { - if(!state.hasFailed(child->id())) { + for (auto const& child : this->mChildren) { + if (!state.hasFailed(child->id())) { childOperationalBefore = true; - } else if(childOperationalBefore && state.hasFailed(child->id())){ + } else if (childOperationalBefore && state.hasFailed(child->id())) { + // Child failed before sibling -> failsafe this->failsafe(state, queues); this->childrenDontCare(state, queues); return; } } - if(!childOperationalBefore) { + if (!childOperationalBefore) { + // All children have failed this->fail(state, queues); } } } void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { - assert(inclusive); + STORM_LOG_ASSERT(isInclusive(), "Exclusive PAND not supported."); STORM_LOG_ASSERT(this->hasFailsafeChild(state), "No failsafe child."); - if(state.isOperational(this->mId)) { + if (state.isOperational(this->mId)) { this->failsafe(state, queues); this->childrenDontCare(state, queues); } } - virtual DFTElementType type() const override { - return DFTElementType::PAND; - } - - bool isInclusive() const { - return inclusive; - } - - std::string typestring() const override { - return inclusive ? "PAND-inc" : "PAND-ex"; - } protected: bool inclusive; }; diff --git a/src/storm-dft/storage/dft/elements/DFTPor.h b/src/storm-dft/storage/dft/elements/DFTPor.h index 1e92384cd..885cc7300 100644 --- a/src/storm-dft/storage/dft/elements/DFTPor.h +++ b/src/storm-dft/storage/dft/elements/DFTPor.h @@ -1,53 +1,76 @@ -#pragma once +#pragma once #include "DFTGate.h" + namespace storm { namespace storage { + + /*! + * Priority OR (POR) gate. + * Fails if the leftmost child fails before all other children. + * If a child fails before the leftmost child, the POR becomes failsafe. + * For inclusive POR<= gates, simultaneous failures are allowed. + * For exclusive POR< gates, simultaneous failures make the gate failsafe. + */ template class DFTPor : public DFTGate { public: - DFTPor(size_t id, std::string const& name, bool inclusive, std::vector>> const& children = {}) : - DFTGate(id, name, children), - inclusive(inclusive) - {} - - void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { - assert(inclusive); - if(state.isOperational(this->mId)) { - if (state.hasFailed(this->mChildren.front()->id())) { + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param inclusive If true, simultaneous failures are allowed. + * parame children Children. + */ + DFTPor(size_t id, std::string const& name, bool inclusive, std::vector>> const& children = {}) : DFTGate(id, name, children), inclusive(inclusive) { + // Intentionally left empty. + } + + DFTElementType type() const override { + return DFTElementType::POR; + } + + std::string typestring() const override { + return isInclusive() ? "POR (incl)" : "POR (excl)"; + } + + /*! + * Return whether the PAND is inclusive. + * @return True iff PAND is inclusive. + */ + bool isInclusive() const { + return inclusive; + } + + void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { + STORM_LOG_ASSERT(isInclusive(), "Exclusive POR not supported."); + if (state.isOperational(this->mId)) { + auto childIter = this->mChildren.begin(); + if (state.hasFailed((*childIter)->id())) { // First child has failed before others this->fail(state, queues); - } else { - for (size_t i = 1; i < this->nrChildren(); ++i) { - if (state.hasFailed(this->mChildren[i]->id())) { - // Child has failed before first child - this->failsafe(state, queues); - this->childrenDontCare(state, queues); - } + return; + } + // Iterate over other children + for (; childIter != this->mChildren.end(); ++childIter) { + if (state.hasFailed((*childIter)->id())) { + // Child has failed before first child + this->failsafe(state, queues); + this->childrenDontCare(state, queues); } } } } void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { - assert(inclusive); + STORM_LOG_ASSERT(isInclusive(), "Exclusive POR not supported."); + // If first child is not failsafe, it could still fail. if (state.isFailsafe(this->mChildren.front()->id())) { this->failsafe(state, queues); this->childrenDontCare(state, queues); } } - virtual DFTElementType type() const override { - return DFTElementType::POR; - } - - std::string typestring() const override { - return inclusive ? "POR-inc" : "POR-ex"; - } - - bool isInclusive() const { - return inclusive; - } protected: bool inclusive; }; diff --git a/src/storm-dft/storage/dft/elements/DFTVot.h b/src/storm-dft/storage/dft/elements/DFTVot.h index 791926a97..bb40998ac 100644 --- a/src/storm-dft/storage/dft/elements/DFTVot.h +++ b/src/storm-dft/storage/dft/elements/DFTVot.h @@ -1,48 +1,70 @@ -#pragma once +#pragma once + #include "DFTGate.h" + namespace storm { namespace storage { - + /*! + * VOT gate with threshold k. + * Fails if k children have failed. + */ template class DFTVot : public DFTGate { - private: - unsigned mThreshold; - public: - DFTVot(size_t id, std::string const& name, unsigned threshold, std::vector>> const& children = {}) : - DFTGate(id, name, children), mThreshold(threshold) - {} + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param threshold Threshold k, nr of failed children needed for failure. + * @param children Children. + */ + DFTVot(size_t id, std::string const& name, unsigned threshold, std::vector>> const& children = {}) : DFTGate(id, name, children), mThreshold(threshold) { + STORM_LOG_ASSERT(mThreshold > 1, "Should use OR gate instead of VOT1"); + // k=n cannot be checked as children might be added later + } + + /*! + * Get the threshold k. + * @return Threshold. + */ + unsigned threshold() const { + return mThreshold; + } + + DFTElementType type() const override { + return DFTElementType::VOT; + } + + std::string typestring() const override { + return storm::storage::toString(this->type()) + " (" + std::to_string(mThreshold) + ")"; + } void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { - if(state.isOperational(this->mId)) { + if (state.isOperational(this->mId)) { unsigned nrFailedChildren = 0; - for(auto const& child : this->mChildren) - { - if(state.hasFailed(child->id())) { + for (auto const& child : this->mChildren) { + if (state.hasFailed(child->id())) { ++nrFailedChildren; - if(nrFailedChildren >= mThreshold) - { + if (nrFailedChildren >= mThreshold) { this->fail(state, queues); return; } } } - - } + + } } void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { STORM_LOG_ASSERT(this->hasFailsafeChild(state), "No failsafe child."); - if(state.isOperational(this->mId)) { + if (state.isOperational(this->mId)) { unsigned nrFailsafeChildren = 0; - for(auto const& child : this->mChildren) - { - if(state.isFailsafe(child->id())) { + for (auto const& child : this->mChildren) { + if (state.isFailsafe(child->id())) { ++nrFailsafeChildren; - if(nrFailsafeChildren > this->nrChildren() - mThreshold) - { + if (nrFailsafeChildren > this->nrChildren() - mThreshold) { this->failsafe(state, queues); this->childrenDontCare(state, queues); return; @@ -51,24 +73,18 @@ namespace storm { } } } - - unsigned threshold() const { - return mThreshold; - } - virtual DFTElementType type() const override { - return DFTElementType::VOT; - } - - std::string typestring() const override{ - return "VOT (" + std::to_string(mThreshold) + ")"; - } - - virtual bool isTypeEqualTo(DFTElement const& other) const override { - if(!DFTElement::isTypeEqualTo(other)) return false; - DFTVot const& otherVOT = static_cast const&>(other); - return (mThreshold == otherVOT.mThreshold); + bool isTypeEqualTo(DFTElement const& other) const override { + if (!DFTElement::isTypeEqualTo(other)) { + return false; + } + auto& otherVOT = static_cast const&>(other); + return this->threshold() == otherVOT.threshold(); } + + private: + unsigned mThreshold; + }; } From 6787d01e2904959ce7fddabf5329031d46172cce Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 4 Apr 2019 00:31:29 +0200 Subject: [PATCH 21/40] Continue refactoring --- src/storm-dft/storage/dft/DFTElements.h | 5 +- .../storage/dft/elements/DFTChildren.h | 167 ++++++++++++++ .../storage/dft/elements/DFTDependency.h | 13 +- .../storage/dft/elements/DFTElement.h | 9 +- src/storm-dft/storage/dft/elements/DFTGate.h | 152 +++---------- src/storm-dft/storage/dft/elements/DFTPand.h | 4 +- src/storm-dft/storage/dft/elements/DFTPor.h | 4 +- .../storage/dft/elements/DFTRestriction.h | 211 ++++++------------ 8 files changed, 293 insertions(+), 272 deletions(-) create mode 100644 src/storm-dft/storage/dft/elements/DFTChildren.h diff --git a/src/storm-dft/storage/dft/DFTElements.h b/src/storm-dft/storage/dft/DFTElements.h index 42aaa4b18..3173446fb 100644 --- a/src/storm-dft/storage/dft/DFTElements.h +++ b/src/storm-dft/storage/dft/DFTElements.h @@ -1,10 +1,9 @@ #pragma once -#include "storm-dft/storage/dft/elements/DFTAnd.h" -#include "storm-dft/storage/dft/elements/DFTBE.h" +#include "storm-dft/storage/dft/elements/BEExponential.h" #include "storm-dft/storage/dft/elements/BEConst.h" +#include "storm-dft/storage/dft/elements/DFTAnd.h" #include "storm-dft/storage/dft/elements/DFTDependency.h" -#include "storm-dft/storage/dft/elements/BEExponential.h" #include "storm-dft/storage/dft/elements/DFTOr.h" #include "storm-dft/storage/dft/elements/DFTPand.h" #include "storm-dft/storage/dft/elements/DFTPor.h" diff --git a/src/storm-dft/storage/dft/elements/DFTChildren.h b/src/storm-dft/storage/dft/elements/DFTChildren.h new file mode 100644 index 000000000..5a0e53776 --- /dev/null +++ b/src/storm-dft/storage/dft/elements/DFTChildren.h @@ -0,0 +1,167 @@ +#pragma once + +#include "DFTElement.h" + +namespace storm { + namespace storage { + + /*! + * Abstract base class for a DFT element with children. + */ + template + class DFTChildren : public DFTElement { + + using DFTElementPointer = std::shared_ptr>; + using DFTElementVector = std::vector; + + public: + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param children Children. + */ + DFTChildren(size_t id, std::string const& name, DFTElementVector const& children) : DFTElement(id, name), mChildren(children) { + // Intentionally left empty. + } + + /*! + * Destructor. + */ + virtual ~DFTChildren() { + // Intentionally left empty. + } + + /*! + * Add child. + * @param element Element. + */ + void pushBackChild(DFTElementPointer element) { + mChildren.push_back(element); + } + + /*! + * Get children. + * @return Children. + */ + DFTElementVector const& children() const { + return mChildren; + } + + size_t nrChildren() const override { + return mChildren.size(); + } + + virtual std::vector independentUnit() const override { + std::set unit = {this->mId}; + for (auto const& child : mChildren) { + child->extendUnit(unit); + } + return std::vector(unit.begin(), unit.end()); + } + + virtual void extendUnit(std::set& unit) const override { + DFTElement::extendUnit(unit); + for (auto const& child : mChildren) { + child->extendUnit(unit); + } + } + + virtual std::vector independentSubDft(bool blockParents, bool sparesAsLeaves = false) const override { + auto prelRes = DFTElement::independentSubDft(blockParents); + if (prelRes.empty()) { + // No elements (especially not this->id) in the prelimanry result, so we know already that it is not a subdft. + return prelRes; + } + std::set unit(prelRes.begin(), prelRes.end()); + std::vector pids = this->parentIds(); + for (auto const& child : mChildren) { + child->extendSubDft(unit, pids, blockParents, sparesAsLeaves); + if (unit.empty()) { + // Parent in the subdft, ie it is *not* a subdft + break; + } + } + return std::vector(unit.begin(), unit.end()); + } + + virtual void extendSubDft(std::set& elemsInSubtree, std::vector const& parentsOfSubRoot, bool blockParents, bool sparesAsLeaves) const override { + if (elemsInSubtree.count(this->id()) > 0) return; + DFTElement::extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); + if (elemsInSubtree.empty()) { + // Parent in the subdft, ie it is *not* a subdft + return; + } + for (auto const& child : mChildren) { + child->extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); + if (elemsInSubtree.empty()) { + // Parent in the subdft, ie it is *not* a subdft + return; + } + } + } + + /*! + * Check failed status. + * @param state Current state of DFT. + * @param queues Propagation queue for failed. + */ + virtual void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const = 0; + + /*! + * Check failsafe status. + * @param state Current state of DFT. + * @param queues Propagation queue for failsafe. + */ + virtual void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const = 0; + + virtual std::string toString() const override { + std::stringstream stream; + stream << "{" << this->name() << "} " << this->typestring() << "( "; + typename DFTElementVector::const_iterator it = mChildren.begin(); + stream << (*it)->name(); + ++it; + while (it != mChildren.end()) { + stream << ", " << (*it)->name(); + ++it; + } + stream << ")"; + return stream.str(); + } + + protected: + /*! + * Check whether it has a failsafe child. + * @param state Current state of DFT. + * @return True iff failsafe child exists. + */ + bool hasFailsafeChild(DFTState& state) const { + for (auto const& child : mChildren) { + if (state.isFailsafe(child->id())) { + return true; + } + } + return false; + } + + /*! + * Check whether it has a failed child. + * @param state Current state of DFT. + * @return True iff failed child exists. + */ + bool hasFailedChild(DFTState& state) const { + for (auto const& child : mChildren) { + if (state.hasFailed(child->id())) { + return true; + } + } + return false; + } + + private: + DFTElementVector mChildren; + + }; + + } +} diff --git a/src/storm-dft/storage/dft/elements/DFTDependency.h b/src/storm-dft/storage/dft/elements/DFTDependency.h index 2ef183693..c055c119f 100644 --- a/src/storm-dft/storage/dft/elements/DFTDependency.h +++ b/src/storm-dft/storage/dft/elements/DFTDependency.h @@ -32,10 +32,21 @@ namespace storm { // We cannot assert 0<=p<=1 in general, because ValueType might be RationalFunction. } + /*! + * Destructor + */ + virtual ~DFTDependency() { + // Intentionally left empty. + }; + DFTElementType type() const override { return DFTElementType::PDEP; } + std::string typestring() const override { + return this->isFDEP() ? "FDEP" : "PDEP"; + } + /*! * Get probability of forwarding the failure. * @return Probability. @@ -155,7 +166,7 @@ namespace storm { std::string toString() const override { std::stringstream stream; - stream << "{" << this->name() << "} " << (this->isFDEP() ? "FDEP" : "PDEP") << "(" << this->triggerEvent()->name() << " => { "; + stream << "{" << this->name() << "} " << this->typestring() << "(" << this->triggerEvent()->name() << " => { "; for (auto const& depEv : this->dependentEvents()) { stream << depEv->name() << " "; } diff --git a/src/storm-dft/storage/dft/elements/DFTElement.h b/src/storm-dft/storage/dft/elements/DFTElement.h index 2c43bdab8..5690f5f0c 100644 --- a/src/storm-dft/storage/dft/elements/DFTElement.h +++ b/src/storm-dft/storage/dft/elements/DFTElement.h @@ -99,6 +99,10 @@ namespace storm { */ virtual DFTElementType type() const = 0; + virtual std::string typestring() const { + return storm::storage::toString(this->type()); + } + /*! * Get rank. * @return Rank. @@ -290,7 +294,10 @@ namespace storm { virtual void extendSpareModule(std::set& elementsInModule) const; // virtual void extendImmediateFailureCausePathEvents(std::set& ) const; - + /*! + * Get number of children. + * @return Nr of children. + */ virtual std::size_t nrChildren() const = 0; virtual bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const; diff --git a/src/storm-dft/storage/dft/elements/DFTGate.h b/src/storm-dft/storage/dft/elements/DFTGate.h index bbf856b14..a41a14ae8 100644 --- a/src/storm-dft/storage/dft/elements/DFTGate.h +++ b/src/storm-dft/storage/dft/elements/DFTGate.h @@ -1,10 +1,15 @@ #pragma once -#include "DFTElement.h" +#include "DFTChildren.h" + namespace storm { namespace storage { - template - class DFTGate : public DFTElement { + + /*! + * Abstract base class for gates. + */ + template + class DFTGate : public DFTChildren { using DFTElementPointer = std::shared_ptr>; using DFTElementVector = std::vector; @@ -13,41 +18,35 @@ namespace storm { DFTElementVector mChildren; public: - DFTGate(size_t id, std::string const& name, DFTElementVector const& children) : - DFTElement(id, name), mChildren(children) - {} - - virtual ~DFTGate() {} - - void pushBackChild(DFTElementPointer elem) { - return mChildren.push_back(elem); + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param children Children. + */ + DFTGate(size_t id, std::string const& name, DFTElementVector const& children) : DFTChildren(id, name, children) { + // Intentionally left empty. } - size_t nrChildren() const override { - return mChildren.size(); + /*! + * Destructor + */ + virtual ~DFTGate() { + // Intentionally left empty. } - DFTElementVector const& children() const { - return mChildren; - } - virtual bool isGate() const override { return true; } - + + /*! + * Return whether the gate is a dynamic gate. + * @return True iff the gate is dynamic. + */ bool isDynamicGate() const { return !isStaticGateType(this->type()); } - - - virtual std::string typestring() const { - return storm::storage::toString(this->type()); - } - virtual void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const = 0; - - virtual void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const = 0; - virtual void extendSpareModule(std::set& elementsInSpareModule) const override { if (!this->isSpareGate()) { DFTElement::extendSpareModule(elementsInSpareModule); @@ -59,73 +58,9 @@ namespace storm { } } } - - virtual std::vector independentUnit() const override { - std::set unit = {this->mId}; - for(auto const& child : mChildren) { - child->extendUnit(unit); - } - return std::vector(unit.begin(), unit.end()); - } - - virtual void extendUnit(std::set& unit) const override { - DFTElement::extendUnit(unit); - for(auto const& child : mChildren) { - child->extendUnit(unit); - } - } - - virtual std::vector independentSubDft(bool blockParents, bool sparesAsLeaves = false) const override { - auto prelRes = DFTElement::independentSubDft(blockParents); - if(prelRes.empty()) { - // No elements (especially not this->id) in the prelimanry result, so we know already that it is not a subdft. - return prelRes; - } - std::set unit(prelRes.begin(), prelRes.end()); - std::vector pids = this->parentIds(); - for(auto const& child : mChildren) { - child->extendSubDft(unit, pids, blockParents, sparesAsLeaves); - if(unit.empty()) { - // Parent in the subdft, ie it is *not* a subdft - break; - } - } - return std::vector(unit.begin(), unit.end()); - } - - virtual void extendSubDft(std::set& elemsInSubtree, std::vector const& parentsOfSubRoot, bool blockParents, bool sparesAsLeaves) const override { - if(elemsInSubtree.count(this->id()) > 0) return; - DFTElement::extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); - if(elemsInSubtree.empty()) { - // Parent in the subdft, ie it is *not* a subdft - return; - } - for(auto const& child : mChildren) { - child->extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); - if(elemsInSubtree.empty()) { - // Parent in the subdft, ie it is *not* a subdft - return; - } - } - } - - - virtual std::string toString() const override { - std::stringstream stream; - stream << "{" << this->name() << "} " << typestring() << "( "; - typename DFTElementVector::const_iterator it = mChildren.begin(); - stream << (*it)->name(); - ++it; - while(it != mChildren.end()) { - stream << ", " << (*it)->name(); - ++it; - } - stream << ")"; - return stream.str(); - } virtual bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { - if(DFTElement::checkDontCareAnymore(state, queues)) { + if (DFTElement::checkDontCareAnymore(state, queues)) { childrenDontCare(state, queues); return true; } @@ -136,12 +71,12 @@ namespace storm { protected: void fail(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { - for(std::shared_ptr parent : this->mParents) { - if(state.isOperational(parent->id())) { + for (std::shared_ptr parent : this->mParents) { + if (state.isOperational(parent->id())) { queues.propagateFailure(parent); } } - for(std::shared_ptr> restr : this->mRestrictions) { + for (std::shared_ptr> restr : this->mRestrictions) { queues.checkRestrictionLater(restr); } state.setFailed(this->mId); @@ -149,38 +84,19 @@ namespace storm { } void failsafe(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { - for(std::shared_ptr parent : this->mParents) { - if(state.isOperational(parent->id())) { + for (std::shared_ptr parent : this->mParents) { + if (state.isOperational(parent->id())) { queues.propagateFailsafe(parent); } } state.setFailsafe(this->mId); this->childrenDontCare(state, queues); } - + void childrenDontCare(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { queues.propagateDontCare(mChildren); } - - bool hasFailsafeChild(DFTState& state) const { - for(auto const& child : mChildren) { - if(state.isFailsafe(child->id())) - { - return true; - } - } - return false; - } - - bool hasFailedChild(DFTState& state) const { - for(auto const& child : mChildren) { - if(state.hasFailed(child->id())) { - return true; - } - } - return false; - } - }; + } } diff --git a/src/storm-dft/storage/dft/elements/DFTPand.h b/src/storm-dft/storage/dft/elements/DFTPand.h index 33ad6c399..70352332f 100644 --- a/src/storm-dft/storage/dft/elements/DFTPand.h +++ b/src/storm-dft/storage/dft/elements/DFTPand.h @@ -24,7 +24,7 @@ namespace storm { * parame children Children. */ DFTPand(size_t id, std::string const& name, bool inclusive, std::vector>> const& children = {}) : DFTGate(id, name, children), inclusive(inclusive) { - // Intentionally left empty. + // Intentionally left empty. } DFTElementType type() const override { @@ -32,7 +32,7 @@ namespace storm { } std::string typestring() const override { - return isInclusive() ? "PAND (incl)" : "PAND (excl)"; + return this->isInclusive() ? "PAND (incl)" : "PAND (excl)"; } /*! diff --git a/src/storm-dft/storage/dft/elements/DFTPor.h b/src/storm-dft/storage/dft/elements/DFTPor.h index 885cc7300..617290bca 100644 --- a/src/storm-dft/storage/dft/elements/DFTPor.h +++ b/src/storm-dft/storage/dft/elements/DFTPor.h @@ -31,7 +31,7 @@ namespace storm { } std::string typestring() const override { - return isInclusive() ? "POR (incl)" : "POR (excl)"; + return this->isInclusive() ? "POR (incl)" : "POR (excl)"; } /*! @@ -42,7 +42,7 @@ namespace storm { return inclusive; } - void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { + void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { STORM_LOG_ASSERT(isInclusive(), "Exclusive POR not supported."); if (state.isOperational(this->mId)) { auto childIter = this->mChildren.begin(); diff --git a/src/storm-dft/storage/dft/elements/DFTRestriction.h b/src/storm-dft/storage/dft/elements/DFTRestriction.h index 10392e05c..d1a69c98b 100644 --- a/src/storm-dft/storage/dft/elements/DFTRestriction.h +++ b/src/storm-dft/storage/dft/elements/DFTRestriction.h @@ -1,44 +1,55 @@ #pragma once -#include "DFTElement.h" +#include "DFTChildren.h" + namespace storm { namespace storage { + + /*! + * Abstract base class for restrictions. + * Restrictions prevent the failure of DFT events. + */ template - class DFTRestriction : public DFTElement { + class DFTRestriction : public DFTChildren { using DFTElementPointer = std::shared_ptr>; using DFTElementVector = std::vector; - protected: - DFTElementVector mChildren; public: - DFTRestriction(size_t id, std::string const& name, DFTElementVector const& children) : - DFTElement(id, name), mChildren(children) - {} - - virtual ~DFTRestriction() {} - - void pushBackChild(DFTElementPointer elem) { - return mChildren.push_back(elem); - } - - size_t nrChildren() const override { - return mChildren.size(); - } - - DFTElementVector const& children() const { - return mChildren; - } - - virtual bool isRestriction() const override { + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param children Children. + */ + DFTRestriction(size_t id, std::string const& name, DFTElementVector const& children) : DFTChildren(id, name, children) { + // Intentionally left empty. + } + + /*! + * Destructor + */ + virtual ~DFTRestriction() { + // Intentionally left empty. + }; + + bool isRestriction() const override { return true; } - + + /*! + * Return whether the restriction is a sequence enforcer. + * @return True iff the restriction is a SEQ. + */ virtual bool isSeqEnforcer() const { return false; } - + + /*! + * Returns whether all children are BEs. + * @return True iff all children are BEs. + */ bool allChildrenBEs() const { - for(auto const& elem : mChildren) { + for (auto const& elem : mChildren) { if (!elem->isBasicElement()) { return false; } @@ -46,165 +57,75 @@ namespace storm { return true; } - - virtual std::string typestring() const = 0; - - virtual void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const = 0; - - virtual void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const = 0; - virtual void extendSpareModule(std::set& elementsInSpareModule) const override { // Do nothing } - virtual std::vector independentUnit() const override { - std::set unit = {this->mId}; - for(auto const& child : mChildren) { - child->extendUnit(unit); - } - return std::vector(unit.begin(), unit.end()); - } - - virtual void extendUnit(std::set& unit) const override { - DFTElement::extendUnit(unit); - for(auto const& child : mChildren) { - child->extendUnit(unit); - } - } - - virtual std::vector independentSubDft(bool blockParents, bool sparesAsLeaves) const override { - auto prelRes = DFTElement::independentSubDft(blockParents); - if(prelRes.empty()) { - // No elements (especially not this->id) in the prelimanry result, so we know already that it is not a subdft. - return prelRes; - } - std::set unit(prelRes.begin(), prelRes.end()); - std::vector pids = this->parentIds(); - for(auto const& child : mChildren) { - child->extendSubDft(unit, pids, blockParents, sparesAsLeaves); - if(unit.empty()) { - // Parent in the subdft, ie it is *not* a subdft - break; - } - } - return std::vector(unit.begin(), unit.end()); - } - - virtual void extendSubDft(std::set& elemsInSubtree, std::vector const& parentsOfSubRoot, bool blockParents, bool sparesAsLeaves) const override { - if(elemsInSubtree.count(this->id()) > 0) return; - DFTElement::extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); - if(elemsInSubtree.empty()) { - // Parent in the subdft, ie it is *not* a subdft - return; - } - for(auto const& child : mChildren) { - child->extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); - if(elemsInSubtree.empty()) { - // Parent in the subdft, ie it is *not* a subdft - return; - } - } - } - - virtual bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { + virtual bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { return false; } protected: - - void fail(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { + void fail(DFTState & state, DFTStateSpaceGenerationQueues & queues) const { state.markAsInvalid(); } - void failsafe(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { + void failsafe(DFTState & state, DFTStateSpaceGenerationQueues & queues) const { } - bool hasFailsafeChild(DFTState& state) const { - for(auto const& child : mChildren) { - if(state.isFailsafe(child->id())) - { - return true; - } - } - return false; - } - - bool hasFailedChild(DFTState& state) const { - for(auto const& child : mChildren) { - if(state.hasFailed(child->id())) { - return true; - } - } - return false; - } - - virtual std::string toString() const override { - std::stringstream stream; - stream << "{" << this->name() << "} " << this->typestring() << "( "; - auto it = this->children().begin(); - stream << (*it)->name(); - ++it; - while(it != this->children().end()) { - stream << ", " << (*it)->name(); - ++it; - } - stream << ")"; - return stream.str(); - } - - + DFTElementVector mChildren; }; + /*! + * Sequence enforcer (SEQ). + * All children can only fail in order from first to last child. + * A child which has not failed yet prevents the failure of all children to the right of it. + */ template class DFTSeq : public DFTRestriction { - public: - DFTSeq(size_t id, std::string const& name, std::vector>> const& children = {}) : - DFTRestriction(id, name, children) - {} + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param children Children. + */ + DFTSeq(size_t id, std::string const& name, std::vector>> const&children = {}) : DFTRestriction(id, name, children) { + // Intentionally left empty. + } + + virtual DFTElementType type() const override { + return DFTElementType::SEQ; + } virtual bool isSeqEnforcer() const override { return true; } - - - void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { + void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { STORM_LOG_ASSERT(queues.failurePropagationDone(), "Failure propagation not finished."); bool childOperationalBefore = false; - for(auto const& child : this->mChildren) - { - if(!state.hasFailed(child->id())) { + for (auto const& child : this->mChildren) { + if (!state.hasFailed(child->id())) { childOperationalBefore = true; - } else if(childOperationalBefore && state.hasFailed(child->id())){ + } else if (childOperationalBefore && state.hasFailed(child->id())) { this->fail(state, queues); return; } } - } - void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { - - + void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { } - - virtual bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { + + virtual bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { // Actually, it doesnt matter what we return here.. return false; } - - virtual DFTElementType type() const override { - return DFTElementType::SEQ; - } - - std::string typestring() const override { - return "SEQ"; - } }; } From 722ff138e213ec65d5acbdb7b5aad81aa7f1c5d6 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 4 Apr 2019 00:31:43 +0200 Subject: [PATCH 22/40] Added missing break statement --- src/storm-dft/storage/dft/DFT.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/storm-dft/storage/dft/DFT.h b/src/storm-dft/storage/dft/DFT.h index b902d6218..940e8adcf 100644 --- a/src/storm-dft/storage/dft/DFT.h +++ b/src/storm-dft/storage/dft/DFT.h @@ -149,6 +149,7 @@ namespace storm { } case storm::storage::DFTElementType::BE_CONST: result.push_back(be->id()); + break; default: STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "BE type '" << be->type() << "' is not supported."); } From 20b123ceca5e1c7f26ffa48483f039e18dd04415 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 4 Apr 2019 11:04:40 +0200 Subject: [PATCH 23/40] Removed mChildren in DFTGate --- src/storm-dft/storage/dft/elements/DFTAnd.h | 2 +- src/storm-dft/storage/dft/elements/DFTGate.h | 11 ++- src/storm-dft/storage/dft/elements/DFTOr.h | 2 +- src/storm-dft/storage/dft/elements/DFTPand.h | 2 +- src/storm-dft/storage/dft/elements/DFTPor.h | 6 +- src/storm-dft/storage/dft/elements/DFTSpare.h | 72 ++++++++++--------- src/storm-dft/storage/dft/elements/DFTVot.h | 4 +- 7 files changed, 49 insertions(+), 50 deletions(-) diff --git a/src/storm-dft/storage/dft/elements/DFTAnd.h b/src/storm-dft/storage/dft/elements/DFTAnd.h index aab72d436..6c1108c66 100644 --- a/src/storm-dft/storage/dft/elements/DFTAnd.h +++ b/src/storm-dft/storage/dft/elements/DFTAnd.h @@ -29,7 +29,7 @@ namespace storm { void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { if (state.isOperational(this->mId)) { - for (auto const& child : this->mChildren) { + for (auto const& child : this->children()) { if (!state.hasFailed(child->id())) { return; } diff --git a/src/storm-dft/storage/dft/elements/DFTGate.h b/src/storm-dft/storage/dft/elements/DFTGate.h index a41a14ae8..1c3000c85 100644 --- a/src/storm-dft/storage/dft/elements/DFTGate.h +++ b/src/storm-dft/storage/dft/elements/DFTGate.h @@ -14,9 +14,6 @@ namespace storm { using DFTElementPointer = std::shared_ptr>; using DFTElementVector = std::vector; - protected: - DFTElementVector mChildren; - public: /*! * Constructor. @@ -50,7 +47,7 @@ namespace storm { virtual void extendSpareModule(std::set& elementsInSpareModule) const override { if (!this->isSpareGate()) { DFTElement::extendSpareModule(elementsInSpareModule); - for (auto const& child : mChildren) { + for (auto const& child : this->children()) { if (elementsInSpareModule.count(child->id()) == 0) { elementsInSpareModule.insert(child->id()); child->extendSpareModule(elementsInSpareModule); @@ -70,7 +67,7 @@ namespace storm { protected: - void fail(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { + virtual void fail(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { for (std::shared_ptr parent : this->mParents) { if (state.isOperational(parent->id())) { queues.propagateFailure(parent); @@ -83,7 +80,7 @@ namespace storm { this->childrenDontCare(state, queues); } - void failsafe(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { + virtual void failsafe(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { for (std::shared_ptr parent : this->mParents) { if (state.isOperational(parent->id())) { queues.propagateFailsafe(parent); @@ -94,7 +91,7 @@ namespace storm { } void childrenDontCare(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { - queues.propagateDontCare(mChildren); + queues.propagateDontCare(this->children()); } }; diff --git a/src/storm-dft/storage/dft/elements/DFTOr.h b/src/storm-dft/storage/dft/elements/DFTOr.h index 4f5c8b2e0..de0225cea 100644 --- a/src/storm-dft/storage/dft/elements/DFTOr.h +++ b/src/storm-dft/storage/dft/elements/DFTOr.h @@ -35,7 +35,7 @@ namespace storm { } void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { - for (auto const& child : this->mChildren) { + for (auto const& child : this->children()) { if (!state.isFailsafe(child->id())) { return; } diff --git a/src/storm-dft/storage/dft/elements/DFTPand.h b/src/storm-dft/storage/dft/elements/DFTPand.h index 70352332f..1eaa0a9e7 100644 --- a/src/storm-dft/storage/dft/elements/DFTPand.h +++ b/src/storm-dft/storage/dft/elements/DFTPand.h @@ -47,7 +47,7 @@ namespace storm { STORM_LOG_ASSERT(isInclusive(), "Exclusive PAND not supported."); if (state.isOperational(this->mId)) { bool childOperationalBefore = false; - for (auto const& child : this->mChildren) { + for (auto const& child : this->children()) { if (!state.hasFailed(child->id())) { childOperationalBefore = true; } else if (childOperationalBefore && state.hasFailed(child->id())) { diff --git a/src/storm-dft/storage/dft/elements/DFTPor.h b/src/storm-dft/storage/dft/elements/DFTPor.h index 617290bca..11a8a25a6 100644 --- a/src/storm-dft/storage/dft/elements/DFTPor.h +++ b/src/storm-dft/storage/dft/elements/DFTPor.h @@ -45,14 +45,14 @@ namespace storm { void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { STORM_LOG_ASSERT(isInclusive(), "Exclusive POR not supported."); if (state.isOperational(this->mId)) { - auto childIter = this->mChildren.begin(); + auto childIter = this->children().begin(); if (state.hasFailed((*childIter)->id())) { // First child has failed before others this->fail(state, queues); return; } // Iterate over other children - for (; childIter != this->mChildren.end(); ++childIter) { + for (; childIter != this->children().end(); ++childIter) { if (state.hasFailed((*childIter)->id())) { // Child has failed before first child this->failsafe(state, queues); @@ -65,7 +65,7 @@ namespace storm { void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { STORM_LOG_ASSERT(isInclusive(), "Exclusive POR not supported."); // If first child is not failsafe, it could still fail. - if (state.isFailsafe(this->mChildren.front()->id())) { + if (state.isFailsafe(this->children().front()->id())) { this->failsafe(state, queues); this->childrenDontCare(state, queues); } diff --git a/src/storm-dft/storage/dft/elements/DFTSpare.h b/src/storm-dft/storage/dft/elements/DFTSpare.h index 7584a1f94..52097f701 100644 --- a/src/storm-dft/storage/dft/elements/DFTSpare.h +++ b/src/storm-dft/storage/dft/elements/DFTSpare.h @@ -1,41 +1,45 @@ -#pragma once - +#pragma once #include "DFTGate.h" + namespace storm { namespace storage { - + /*! + * SPARE gate. + */ template class DFTSpare : public DFTGate { public: - DFTSpare(size_t id, std::string const& name, std::vector>> const& children = {}) : - DFTGate(id, name, children) - {} - - std::string typestring() const override { - return "SPARE"; + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param children Children. + */ + DFTSpare(size_t id, std::string const& name, std::vector>> const& children = {}) : DFTGate(id, name, children) { + // Intentionally left empty. } - virtual DFTElementType type() const override { + DFTElementType type() const override { return DFTElementType::SPARE; } bool isSpareGate() const override { return true; } - - void fail(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { + + void fail(DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { DFTGate::fail(state, queues); state.finalizeUses(this->mId); } - - void failsafe(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { + + void failsafe(DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { DFTGate::failsafe(state, queues); state.finalizeUses(this->mId); } - + bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { if (DFTGate::checkDontCareAnymore(state, queues)) { state.finalizeUses(this->mId); @@ -43,40 +47,40 @@ namespace storm { } return false; } - + void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { - if(state.isOperational(this->mId)) { + if (state.isOperational(this->mId)) { size_t uses = state.uses(this->mId); - if(!state.isOperational(uses)) { - bool claimingSuccessful = state.claimNew(this->mId, uses, this->mChildren); - if(!claimingSuccessful) { + if (!state.isOperational(uses)) { + bool claimingSuccessful = state.claimNew(this->mId, uses, this->children()); + if (!claimingSuccessful) { this->fail(state, queues); } - } - } + } + } } void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { - if(state.isOperational(this->mId)) { - if(state.isFailsafe(state.uses(this->mId))) { + if (state.isOperational(this->mId)) { + if (state.isFailsafe(state.uses(this->mId))) { this->failsafe(state, queues); this->childrenDontCare(state, queues); } } } - + std::vector independentSubDft(bool blockParents, bool sparesAsLeaves = false) const override { auto prelRes = DFTElement::independentSubDft(blockParents); - if(prelRes.empty()) { + if (prelRes.empty()) { // No elements (especially not this->id) in the prelimanry result, so we know already that it is not a subdft. return prelRes; } std::set unit(prelRes.begin(), prelRes.end()); std::vector pids = this->parentIds(); if (!sparesAsLeaves) { - for(auto const& child : this->mChildren) { + for (auto const& child : this->children()) { child->extendSubDft(unit, pids, blockParents, sparesAsLeaves); - if(unit.empty()) { + if (unit.empty()) { // Parent in the subdft, ie it is *not* a subdft break; } @@ -84,26 +88,24 @@ namespace storm { } return std::vector(unit.begin(), unit.end()); } - + void extendSubDft(std::set& elemsInSubtree, std::vector const& parentsOfSubRoot, bool blockParents, bool sparesAsLeaves) const override { - if(elemsInSubtree.count(this->id()) > 0) return; + if (elemsInSubtree.count(this->id()) > 0) return; DFTElement::extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); - if(elemsInSubtree.empty()) { + if (elemsInSubtree.empty()) { // Parent in the subdft, ie it is *not* a subdft return; } if (!sparesAsLeaves) { - for(auto const& child : this->mChildren) { + for (auto const& child : this->children()) { child->extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); - if(elemsInSubtree.empty()) { + if (elemsInSubtree.empty()) { // Parent in the subdft, ie it is *not* a subdft return; } } } } - - }; } diff --git a/src/storm-dft/storage/dft/elements/DFTVot.h b/src/storm-dft/storage/dft/elements/DFTVot.h index bb40998ac..920efb3e7 100644 --- a/src/storm-dft/storage/dft/elements/DFTVot.h +++ b/src/storm-dft/storage/dft/elements/DFTVot.h @@ -44,7 +44,7 @@ namespace storm { void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { if (state.isOperational(this->mId)) { unsigned nrFailedChildren = 0; - for (auto const& child : this->mChildren) { + for (auto const& child : this->children()) { if (state.hasFailed(child->id())) { ++nrFailedChildren; if (nrFailedChildren >= mThreshold) { @@ -61,7 +61,7 @@ namespace storm { STORM_LOG_ASSERT(this->hasFailsafeChild(state), "No failsafe child."); if (state.isOperational(this->mId)) { unsigned nrFailsafeChildren = 0; - for (auto const& child : this->mChildren) { + for (auto const& child : this->children()) { if (state.isFailsafe(child->id())) { ++nrFailsafeChildren; if (nrFailsafeChildren > this->nrChildren() - mThreshold) { From 5ba2c6357e698d2634e14d9a18b713051c6daef9 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 4 Apr 2019 11:21:24 +0200 Subject: [PATCH 24/40] Removed mChildren in DFTRestriction --- .../storage/dft/elements/DFTChildren.h | 5 +++++ src/storm-dft/storage/dft/elements/DFTGate.h | 4 ++-- .../storage/dft/elements/DFTRestriction.h | 20 +++++++++---------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/storm-dft/storage/dft/elements/DFTChildren.h b/src/storm-dft/storage/dft/elements/DFTChildren.h index 5a0e53776..a9d0c7290 100644 --- a/src/storm-dft/storage/dft/elements/DFTChildren.h +++ b/src/storm-dft/storage/dft/elements/DFTChildren.h @@ -158,6 +158,11 @@ namespace storm { return false; } + virtual void fail(DFTState& state, DFTStateSpaceGenerationQueues& queues) const = 0; + + virtual void failsafe(DFTState& state, DFTStateSpaceGenerationQueues& queues) const = 0; + + private: DFTElementVector mChildren; diff --git a/src/storm-dft/storage/dft/elements/DFTGate.h b/src/storm-dft/storage/dft/elements/DFTGate.h index 1c3000c85..9f95ed751 100644 --- a/src/storm-dft/storage/dft/elements/DFTGate.h +++ b/src/storm-dft/storage/dft/elements/DFTGate.h @@ -67,7 +67,7 @@ namespace storm { protected: - virtual void fail(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { + void fail(DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { for (std::shared_ptr parent : this->mParents) { if (state.isOperational(parent->id())) { queues.propagateFailure(parent); @@ -80,7 +80,7 @@ namespace storm { this->childrenDontCare(state, queues); } - virtual void failsafe(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { + void failsafe(DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { for (std::shared_ptr parent : this->mParents) { if (state.isOperational(parent->id())) { queues.propagateFailsafe(parent); diff --git a/src/storm-dft/storage/dft/elements/DFTRestriction.h b/src/storm-dft/storage/dft/elements/DFTRestriction.h index d1a69c98b..9b93ae63a 100644 --- a/src/storm-dft/storage/dft/elements/DFTRestriction.h +++ b/src/storm-dft/storage/dft/elements/DFTRestriction.h @@ -49,7 +49,7 @@ namespace storm { * @return True iff all children are BEs. */ bool allChildrenBEs() const { - for (auto const& elem : mChildren) { + for (auto const& elem : this->children()) { if (!elem->isBasicElement()) { return false; } @@ -57,25 +57,23 @@ namespace storm { return true; } - virtual void extendSpareModule(std::set& elementsInSpareModule) const override { + void extendSpareModule(std::set& elementsInSpareModule) const override { // Do nothing } - virtual bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { + bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { return false; } protected: - void fail(DFTState & state, DFTStateSpaceGenerationQueues & queues) const { + void fail(DFTState & state, DFTStateSpaceGenerationQueues & queues) const override { state.markAsInvalid(); } - void failsafe(DFTState & state, DFTStateSpaceGenerationQueues & queues) const { + void failsafe(DFTState & state, DFTStateSpaceGenerationQueues & queues) const override { } - - DFTElementVector mChildren; }; @@ -98,18 +96,18 @@ namespace storm { // Intentionally left empty. } - virtual DFTElementType type() const override { + DFTElementType type() const override { return DFTElementType::SEQ; } - virtual bool isSeqEnforcer() const override { + bool isSeqEnforcer() const override { return true; } void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { STORM_LOG_ASSERT(queues.failurePropagationDone(), "Failure propagation not finished."); bool childOperationalBefore = false; - for (auto const& child : this->mChildren) { + for (auto const& child : this->children()) { if (!state.hasFailed(child->id())) { childOperationalBefore = true; } else if (childOperationalBefore && state.hasFailed(child->id())) { @@ -122,7 +120,7 @@ namespace storm { void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { } - virtual bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { + bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { // Actually, it doesnt matter what we return here.. return false; } From 694c87c2b1790719da61bbcecc1c94f03c796267 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 4 Apr 2019 17:23:09 +0200 Subject: [PATCH 25/40] Fixed JSON import after changes in BEs --- src/storm-dft/parser/DFTJsonParser.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/storm-dft/parser/DFTJsonParser.cpp b/src/storm-dft/parser/DFTJsonParser.cpp index 1272e033e..7975a0d5b 100644 --- a/src/storm-dft/parser/DFTJsonParser.cpp +++ b/src/storm-dft/parser/DFTJsonParser.cpp @@ -3,8 +3,9 @@ #include #include #include -#include #include +#include + #include "storm/exceptions/NotImplementedException.h" #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/NotSupportedException.h" @@ -87,16 +88,17 @@ namespace storm { success = builder.addSpareElement(name, childNames); } else if (type == "seq") { success = builder.addSequenceEnforcer(name, childNames); - } else if (type== "fdep") { + } else if (type == "fdep") { success = builder.addDepElement(name, childNames, storm::utility::one()); - } else if (type== "pdep") { + } else if (type == "pdep") { ValueType probability = parseRationalExpression(parseJsonNumber(data.at("probability"))); success = builder.addDepElement(name, childNames, probability); - } else if (type == "be") { + } else if (boost::starts_with(type, "be")) { std::string distribution = "exp"; // Set default of exponential distribution if (data.count("distribution") > 0) { distribution = data.at("distribution"); } + STORM_LOG_THROW(type == "be" || "be_" + distribution == type, storm::exceptions::WrongFormatException, "BE type '" << type << "' and distribution '" << distribution << " do not agree."); if (distribution == "exp") { ValueType failureRate = parseRationalExpression(parseJsonNumber(data.at("rate"))); ValueType dormancyFactor = parseRationalExpression(parseJsonNumber(data.at("dorm"))); From 26366e43cf40895f4078d0af19c1d768480e4d4f Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 5 Apr 2019 16:13:24 +0200 Subject: [PATCH 26/40] Some more refactoring --- .../storage/dft/elements/DFTDependency.h | 24 +- .../storage/dft/elements/DFTElement.cpp | 48 ++-- .../storage/dft/elements/DFTElement.h | 249 +++++++++++------- src/storm-dft/storage/dft/elements/DFTGate.h | 5 + .../storage/dft/elements/DFTRestriction.h | 2 +- 5 files changed, 192 insertions(+), 136 deletions(-) diff --git a/src/storm-dft/storage/dft/elements/DFTDependency.h b/src/storm-dft/storage/dft/elements/DFTDependency.h index c055c119f..a7cca4f36 100644 --- a/src/storm-dft/storage/dft/elements/DFTDependency.h +++ b/src/storm-dft/storage/dft/elements/DFTDependency.h @@ -55,6 +55,18 @@ namespace storm { return mProbability; } + bool isDependency() const override { + return true; + } + + /*! + * Check whether the dependency is an FDEP, i.e., p=1. + * @return True iff p=1. + */ + bool isFDEP() const { + return storm::utility::isOne(this->probability()); + } + /*! * Get trigger event, i.e., the first child. * @return Trigger event. @@ -106,18 +118,6 @@ namespace storm { return 1; } - bool isDependency() const override { - return true; - } - - /*! - * Check whether the dependency is an FDEP, i.e., p=1. - * @return True iff p=1. - */ - bool isFDEP() const { - return storm::utility::isOne(this->probability()); - } - bool isTypeEqualTo(DFTElement const& other) const override { if (!DFTElement::isTypeEqualTo(other)) { return false; diff --git a/src/storm-dft/storage/dft/elements/DFTElement.cpp b/src/storm-dft/storage/dft/elements/DFTElement.cpp index 287af8e98..5f04b9d65 100644 --- a/src/storm-dft/storage/dft/elements/DFTElement.cpp +++ b/src/storm-dft/storage/dft/elements/DFTElement.cpp @@ -6,13 +6,13 @@ namespace storm { namespace storage { - + template bool DFTElement::checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const { if (state.dontCare(mId)) { return false; } - + // Check that no outgoing dependencies can be triggered anymore // Notice that n-ary dependencies are supported via rewriting them during build-time for (DFTDependencyPointer dependency : mOutgoingDependencies) { @@ -21,23 +21,23 @@ namespace storm { return false; } } - + bool hasParentSpare = false; // Check that no parent can fail anymore - for(DFTGatePointer const& parent : mParents) { - if(state.isOperational(parent->id())) { + for (DFTGatePointer const& parent : mParents) { + if (state.isOperational(parent->id())) { return false; } if (parent->isSpareGate()) { hasParentSpare = true; } } - - if(!mRestrictions.empty() && state.hasOperationalPostSeqElements(mId)) { + + if (!mRestrictions.empty() && state.hasOperationalPostSeqElements(mId)) { return false; } - + state.setDontCare(mId); if (hasParentSpare) { // Activate child for consistency in failed spares @@ -48,8 +48,8 @@ namespace storm { template void DFTElement::extendSpareModule(std::set& elementsInModule) const { - for(auto const& parent : mParents) { - if(elementsInModule.count(parent->id()) == 0 && !parent->isSpareGate()) { + for (auto const& parent : mParents) { + if (elementsInModule.count(parent->id()) == 0 && !parent->isSpareGate()) { elementsInModule.insert(parent->id()); parent->extendSpareModule(elementsInModule); } @@ -78,48 +78,42 @@ namespace storm { template void DFTElement::extendSubDft(std::set& elemsInSubtree, std::vector const& parentsOfSubRoot, bool blockParents, bool sparesAsLeaves) const { - if(elemsInSubtree.count(this->id()) > 0) return; - if(std::find(parentsOfSubRoot.begin(), parentsOfSubRoot.end(), mId) != parentsOfSubRoot.end()) { + if (elemsInSubtree.count(this->id()) > 0) return; + if (std::find(parentsOfSubRoot.begin(), parentsOfSubRoot.end(), mId) != parentsOfSubRoot.end()) { // This is a parent of the suspected root, thus it is not a subdft. elemsInSubtree.clear(); return; } elemsInSubtree.insert(mId); - for(auto const& parent : mParents) { - if(blockParents && std::find(parentsOfSubRoot.begin(), parentsOfSubRoot.end(), parent->id()) != parentsOfSubRoot.end()) { + for (auto const& parent : mParents) { + if (blockParents && std::find(parentsOfSubRoot.begin(), parentsOfSubRoot.end(), parent->id()) != parentsOfSubRoot.end()) { continue; } parent->extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); - if(elemsInSubtree.empty()) { + if (elemsInSubtree.empty()) { return; } } - for(auto const& dep : mOutgoingDependencies) { + for (auto const& dep : mOutgoingDependencies) { dep->extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); - if(elemsInSubtree.empty()) { + if (elemsInSubtree.empty()) { return; } } - - for(auto const& restr : mRestrictions) { + + for (auto const& restr : mRestrictions) { restr->extendSubDft(elemsInSubtree, parentsOfSubRoot, blockParents, sparesAsLeaves); - if(elemsInSubtree.empty()) { + if (elemsInSubtree.empty()) { return; } } - + } - - // Explicitly instantiate the class. template class DFTElement; - -#ifdef STORM_HAVE_CARL template class DFTElement; -#endif - } } diff --git a/src/storm-dft/storage/dft/elements/DFTElement.h b/src/storm-dft/storage/dft/elements/DFTElement.h index 5690f5f0c..b287ae863 100644 --- a/src/storm-dft/storage/dft/elements/DFTElement.h +++ b/src/storm-dft/storage/dft/elements/DFTElement.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -16,23 +16,25 @@ #include "storm/adapters/RationalFunctionAdapter.h" - - namespace storm { namespace storage { - + using std::size_t; // Forward declarations template class DFTGate; - + template class DFTDependency; + template class DFTRestriction; - + /*! + * Abstract base class for DFT elements. + * It is the most general class. + */ template class DFTElement { @@ -43,16 +45,6 @@ namespace storm { using DFTRestrictionPointer = std::shared_ptr>; using DFTRestrictionVector = std::vector; - - protected: - std::size_t mId; - std::string mName; - std::size_t mRank = -1; - DFTGateVector mParents; - DFTDependencyVector mOutgoingDependencies; - DFTRestrictionVector mRestrictions; - - public: /*! * Constructor. @@ -60,12 +52,14 @@ namespace storm { * @param name Name. */ DFTElement(size_t id, std::string const& name) : mId(id), mName(name) { + // Intentionally left empty. } /*! * Destructor. */ virtual ~DFTElement() { + // Intentionally left empty. } /*! @@ -99,6 +93,10 @@ namespace storm { */ virtual DFTElementType type() const = 0; + /*! + * Get type as string. + * @return String with type information. + */ virtual std::string typestring() const { return storm::storage::toString(this->type()); } @@ -119,10 +117,6 @@ namespace storm { this->mRank = rank; } - virtual bool isConstant() const { - return false; - } - /*! * Checks whether the element is a basic element. * @return True iff element is a BE. @@ -132,111 +126,168 @@ namespace storm { } /*! - * Check wether the element is a gate. + * Check whether the element is a gate. * @return True iff element is a gate. */ virtual bool isGate() const { return false; } - - /** - * Returns true if the element is a spare gate + + /*! + * Check whether the element is a SPARE gate. + * @return True iff element is a SPARE gate. */ virtual bool isSpareGate() const { return false; } + /*! + * Check whether the element is a dependency. + * @return True iff element is a dependency. + */ virtual bool isDependency() const { return false; } - + + /*! + * Check whether the element is a restriction. + * @return True iff element is a restriction. + */ virtual bool isRestriction() const { return false; } + /*! + * Return whether the element has parents. + * @return True iff at least one parent exists. + */ + bool hasParents() const { + return !mParents.empty(); + } - bool addParent(DFTGatePointer const& e) { - if(std::find(mParents.begin(), mParents.end(), e) != mParents.end()) { - return false; - } - else - { - mParents.push_back(e); - return true; - } + /*! + * Return the number of parents. + * @return Number of parents. + */ + size_t nrParents() const { + return mParents.size(); + } + + /*! + * Get parents. + * @return Parents. + */ + DFTGateVector const& parents() const { + return mParents; } - bool addRestriction(DFTRestrictionPointer const& e) { - if (std::find(mRestrictions.begin(), mRestrictions.end(), e) != mRestrictions.end()) { - return false; - } else { - mRestrictions.push_back(e); - return true; + /*! + * Add parent. + * @param parent Parent. + */ + void addParent(DFTGatePointer const& parent) { + if (std::find(this->parents().begin(), this->parents().end(), parent) == this->parents().end()) { + // Parent does not exist yet + mParents.push_back(parent); + }; + } + + /*! + * Return Ids of parents. + * @return Parent ids. + */ + std::vector parentIds() const { + std::vector ids; + for (auto parent : this->parents()) { + ids.push_back(parent->id()); } + return ids; } - bool hasOnlyStaticParents() const { - for(auto const& parent : mParents) { - if(!isStaticGateType(parent->type())) { + /*! + * Check whether the element has only static gates as parents. + * @return True iff all parents are static gates. + */ + bool hasOnlyStaticParents() const { + for (auto const& parent : this->parents()) { + if (!isStaticGateType(parent->type())) { return false; } } return true; } - - bool hasParents() const { - return !mParents.empty(); - } - - size_t nrParents() const { - return mParents.size(); - } - - DFTGateVector const& parents() const { - return mParents; - } - + /*! + * Return whether the element has restrictions. + * @return True iff at least one restriction exists. + */ bool hasRestrictions() const { return !mRestrictions.empty(); } - + + /*! + * Return the number of restrictions. + * @return Number of restrictions. + */ size_t nrRestrictions() const { return mRestrictions.size(); } - + + /*! + * Get restrictions. + * @return Restrictions. + */ DFTRestrictionVector const& restrictions() const { return mRestrictions; } - std::vector parentIds() const { - std::vector res; - for(auto parent : parents()) { - res.push_back(parent->id()); - } - return res; - } - - bool addOutgoingDependency(DFTDependencyPointer const& e) { - STORM_LOG_ASSERT(e->triggerEvent()->id() == this->id(), "Ids do not match."); - if(std::find(mOutgoingDependencies.begin(), mOutgoingDependencies.end(), e) != mOutgoingDependencies.end()) { - return false; - } - else - { - mOutgoingDependencies.push_back(e); - return true; + /*! + * Add restriction. + * @param restrictions Restriction. + */ + void addRestriction(DFTRestrictionPointer const& restriction) { + if (std::find(this->restrictions().begin(), this->restrictions().end(), restriction) == this->restrictions().end()) { + // Restriction does not exist yet + mRestrictions.push_back(restriction); } } - + + /*! + * Return whether the element has outgoing dependencies. + * @return True iff at least one restriction exists. + */ bool hasOutgoingDependencies() const { return !mOutgoingDependencies.empty(); } - + + /*! + * Return the number of outgoing dependencies. + * @return Number of outgoing dependencies. + */ size_t nrOutgoingDependencies() const { return mOutgoingDependencies.size(); } - + + /*! + * Get outgoing dependencies. + * @return Outgoing dependencies. + */ + DFTDependencyVector const& outgoingDependencies() const { + return mOutgoingDependencies; + } + + /*! + * Add outgoing dependency. + * @param outgoingDependency Outgoing dependency. + */ + void addOutgoingDependency(DFTDependencyPointer const& outgoingDependency) { + STORM_LOG_ASSERT(outgoingDependency->triggerEvent()->id() == this->id(), "Ids do not match."); + if (std::find(this->outgoingDependencies().begin(), this->outgoingDependencies().end(), outgoingDependency) == this->outgoingDependencies().end()) { + // Outgoing dependency does not exist yet + mOutgoingDependencies.push_back(outgoingDependency); + }; + } + /** * Obtains ids of elements which are the direct successor in the list of children of a restriction * @return A vector of ids @@ -244,24 +295,24 @@ namespace storm { std::vector seqRestrictionPosts() const { std::vector res; for (auto const& restr : mRestrictions) { - if(!restr->isSeqEnforcer()) { + if (!restr->isSeqEnforcer()) { continue; } auto it = restr->children().cbegin(); - for(; it != restr->children().cend(); ++it) { - if((*it)->id() == mId) { + for (; it != restr->children().cend(); ++it) { + if ((*it)->id() == mId) { break; } } STORM_LOG_ASSERT(it != restr->children().cend(), "Child not found."); ++it; - if(it != restr->children().cend()) { + if (it != restr->children().cend()) { res.push_back((*it)->id()); } } return res; } - + /** * Obtains ids of elements which are the direct predecessor in the list of children of a restriction * @return A vector of ids @@ -269,31 +320,27 @@ namespace storm { std::vector seqRestrictionPres() const { std::vector res; for (auto const& restr : mRestrictions) { - if(!restr->isSeqEnforcer()) { + if (!restr->isSeqEnforcer()) { continue; } auto it = restr->children().cbegin(); - for(; it != restr->children().cend(); ++it) { - if((*it)->id() == mId) { + for (; it != restr->children().cend(); ++it) { + if ((*it)->id() == mId) { break; } } STORM_LOG_ASSERT(it != restr->children().cend(), "Child not found."); - if(it != restr->children().cbegin()) { + if (it != restr->children().cbegin()) { --it; res.push_back((*it)->id()); } } return res; } - - DFTDependencyVector const& outgoingDependencies() const { - return mOutgoingDependencies; - } - + virtual void extendSpareModule(std::set& elementsInModule) const; - // virtual void extendImmediateFailureCausePathEvents(std::set& ) const; + // virtual void extendImmediateFailureCausePathEvents(std::set& ) const; /*! * Get number of children. * @return Nr of children. @@ -320,12 +367,18 @@ namespace storm { * such that there exists a path from x to a child of this does not go through this. */ virtual std::vector independentSubDft(bool blockParents, bool sparesAsLeaves = false) const; + /** * Helper to the independent subtree computation * @see independentSubDft */ virtual void extendSubDft(std::set& elemsInSubtree, std::vector const& parentsOfSubRoot, bool blockParents, bool sparesAsLeaves) const; + /*! + * Check whether two elements have the same type. + * @param other Other element. + * @return True iff this and other have the same type. + */ virtual bool isTypeEqualTo(DFTElement const& other) const { return type() == other.type(); } @@ -338,8 +391,12 @@ namespace storm { protected: - // virtual bool checkIsomorphicSubDftHelper(DFTElement const& otherElem, std::vector>& mapping, std::vector const& order ) const = 0; - + std::size_t mId; + std::string mName; + std::size_t mRank = -1; + DFTGateVector mParents; + DFTDependencyVector mOutgoingDependencies; + DFTRestrictionVector mRestrictions; }; @@ -347,7 +404,7 @@ namespace storm { inline std::ostream& operator<<(std::ostream& os, DFTElement const& element) { return os << element.toString(); } - + template bool equalType(DFTElement const& e1, DFTElement const& e2) { return e1.isTypeEqualTo(e2); diff --git a/src/storm-dft/storage/dft/elements/DFTGate.h b/src/storm-dft/storage/dft/elements/DFTGate.h index 9f95ed751..e997c1a4a 100644 --- a/src/storm-dft/storage/dft/elements/DFTGate.h +++ b/src/storm-dft/storage/dft/elements/DFTGate.h @@ -90,6 +90,11 @@ namespace storm { this->childrenDontCare(state, queues); } + /*! + * Propagate Don't Care to children. + * @param state Current DFT state. + * @param queues Propagation queues. + */ void childrenDontCare(DFTState& state, DFTStateSpaceGenerationQueues& queues) const { queues.propagateDontCare(this->children()); } diff --git a/src/storm-dft/storage/dft/elements/DFTRestriction.h b/src/storm-dft/storage/dft/elements/DFTRestriction.h index 9b93ae63a..b83ba44f7 100644 --- a/src/storm-dft/storage/dft/elements/DFTRestriction.h +++ b/src/storm-dft/storage/dft/elements/DFTRestriction.h @@ -72,7 +72,7 @@ namespace storm { } void failsafe(DFTState & state, DFTStateSpaceGenerationQueues & queues) const override { - + // Do nothing } }; From 99651bdc71401b76a0b30eaeb99b916ab13f9b16 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 5 Apr 2019 19:07:48 +0200 Subject: [PATCH 27/40] Started on the notion of 'relevant events' for DFT analysis --- src/storm-dft-cli/storm-dft.cpp | 34 +++++++++--- src/storm-dft/api/storm-dft.h | 49 ++++++----------- .../builder/ExplicitDFTModelBuilder.cpp | 6 +-- .../builder/ExplicitDFTModelBuilder.h | 8 +-- .../generator/DftNextStateGenerator.cpp | 4 +- .../generator/DftNextStateGenerator.h | 6 +-- .../modelchecker/dft/DFTModelChecker.cpp | 24 ++++----- .../modelchecker/dft/DFTModelChecker.h | 25 ++++----- .../settings/modules/FaultTreeSettings.cpp | 25 +++++++-- .../settings/modules/FaultTreeSettings.h | 28 ++++++++-- src/storm-dft/storage/dft/DFT.cpp | 16 ++++++ src/storm-dft/storage/dft/DFT.h | 13 +++++ .../storm-dft/api/DftApproximationTest.cpp | 19 ++++--- .../storm-dft/api/DftModelCheckerTest.cpp | 52 ++++++++++++------- 14 files changed, 198 insertions(+), 111 deletions(-) diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index eb4b1b837..0514e63d0 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -120,16 +120,38 @@ void processOptions() { propString += ";" + properties[i]; } std::vector> props = storm::api::extractFormulasFromProperties(storm::api::parseProperties(propString)); - STORM_LOG_ASSERT(props.size() > 0, "No properties found."); + + // Set relevant elements + // TODO: also incorporate events from properties + std::set relevantEvents; // Per default only the toplevel event is relevant + // Possible clash of relevantEvents and disableDC was already considered in FaultTreeSettings::check(). + if (faultTreeSettings.areRelevantEventsSet()) { + for (std::string const& relevantName : faultTreeSettings.getRelevantEvents()) { + if (relevantName == "none") { + // Only toplevel event is relevant + relevantEvents = {}; + break; + } else if (relevantName == "all") { + // All events are relevant + relevantEvents = dft->getAllIds(); + break; + } else { + // Find corresponding id + relevantEvents.insert(dft->getIndex(relevantName)); + } + } + } else if (faultTreeSettings.isDisableDC()) { + // All events are relevant + relevantEvents = dft->getAllIds(); + } // Carry out the actual analysis + double approximationError = 0.0; if (faultTreeSettings.isApproximationErrorSet()) { - // Approximate analysis - storm::api::analyzeDFTApprox(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), - faultTreeSettings.getApproximationError(), faultTreeSettings.getApproximationHeuristic(), true); - } else { - storm::api::analyzeDFT(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), true); + approximationError = faultTreeSettings.getApproximationError(); } + storm::api::analyzeDFT(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), relevantEvents, approximationError, + faultTreeSettings.getApproximationHeuristic(), true); } /*! diff --git a/src/storm-dft/api/storm-dft.h b/src/storm-dft/api/storm-dft.h index 6cd701e83..f36bfc3ca 100644 --- a/src/storm-dft/api/storm-dft.h +++ b/src/storm-dft/api/storm-dft.h @@ -53,57 +53,40 @@ namespace storm { return std::make_shared>(parser.parseJsonFromFile(file)); } - template - bool isWellFormed(storm::storage::DFT const& dft) { - std::stringstream stream; - return dft.checkWellFormedness(stream); - } - - /*! - * Analyse the given DFT according to the given properties. - * First the Markov model is built from the DFT and then this model is checked against the given properties. + * Check whether the DFT is well-formed. * * @param dft DFT. - * @param properties PCTL formulas capturing the properties to check. - * @param symred Flag whether symmetry reduction should be used. - * @param allowModularisation Flag whether modularisation should be applied if possible. - * @param enableDC Flag whether Don't Care propagation should be used. - * - * @return Result. + * @return True iff the DFT is well-formed. */ template - typename storm::modelchecker::DFTModelChecker::dft_results - analyzeDFT(storm::storage::DFT const& dft, std::vector> const& properties, bool symred, bool allowModularisation, - bool enableDC, bool printOutput) { - storm::modelchecker::DFTModelChecker modelChecker(printOutput); - typename storm::modelchecker::DFTModelChecker::dft_results results = modelChecker.check(dft, properties, symred, allowModularisation, enableDC, 0.0); - if (printOutput) { - modelChecker.printTimings(); - modelChecker.printResults(results); - } - return results; + bool isWellFormed(storm::storage::DFT const& dft) { + std::stringstream stream; + return dft.checkWellFormedness(stream); } /*! - * Approximate the analysis result of the given DFT according to the given properties. + * Compute the exact or approximate analysis result of the given DFT according to the given properties. * First the Markov model is built from the DFT and then this model is checked against the given properties. * * @param dft DFT. * @param properties PCTL formulas capturing the properties to check. * @param symred Flag whether symmetry reduction should be used. * @param allowModularisation Flag whether modularisation should be applied if possible. - * @param enableDC Flag whether Don't Care propagation should be used. - * @param approximationError Allowed approximation error. - * - * @return Result. + * @param relevantEvents List of relevant events which should be observed. + * @param approximationError Allowed approximation error. Value 0 indicates no approximation. + * @param approximationHeuristic Heuristic used for state space exploration. + * @param printOutput If true, model information, timings, results, etc. are printed. + * @return Results. */ template typename storm::modelchecker::DFTModelChecker::dft_results - analyzeDFTApprox(storm::storage::DFT const& dft, std::vector> const& properties, bool symred, - bool allowModularisation, bool enableDC, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic, bool printOutput) { + analyzeDFT(storm::storage::DFT const& dft, std::vector> const& properties, bool symred = true, + bool allowModularisation = true, std::set const& relevantEvents = {}, double approximationError = 0.0, + storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH, bool printOutput = false) { storm::modelchecker::DFTModelChecker modelChecker(printOutput); - typename storm::modelchecker::DFTModelChecker::dft_results results = modelChecker.check(dft, properties, symred, allowModularisation, enableDC, approximationError, approximationHeuristic); + typename storm::modelchecker::DFTModelChecker::dft_results results = modelChecker.check(dft, properties, symred, allowModularisation, relevantEvents, + approximationError, approximationHeuristic); if (printOutput) { modelChecker.printTimings(); modelChecker.printResults(results); diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index 8c23c6d6a..aba061935 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -54,11 +54,11 @@ namespace storm { } template - ExplicitDFTModelBuilder::ExplicitDFTModelBuilder(storm::storage::DFT const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC) : + ExplicitDFTModelBuilder::ExplicitDFTModelBuilder(storm::storage::DFT const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, std::set const& relevantEvents) : dft(dft), stateGenerationInfo(std::make_shared(dft.buildStateGenerationInfo(symmetries))), - enableDC(enableDC), - generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates), + relevantEvents(relevantEvents), + generator(dft, *stateGenerationInfo, relevantEvents, mergeFailedStates), matrixBuilder(!generator.isDeterministicModel()), stateStorage(dft.stateBitVectorSize()), explorationQueue(1, 0, 0.9, false) diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.h b/src/storm-dft/builder/ExplicitDFTModelBuilder.h index 379918f9b..ce00eb144 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.h +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.h @@ -174,9 +174,9 @@ namespace storm { * * @param dft DFT. * @param symmetries Symmetries in the dft. - * @param enableDC Flag indicating if dont care propagation should be used. + * @param relevantEvents List with ids of relevant events which should be observed. */ - ExplicitDFTModelBuilder(storm::storage::DFT const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC); + ExplicitDFTModelBuilder(storm::storage::DFT const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, std::set const& relevantEvents); /*! * Build model from DFT. @@ -312,8 +312,8 @@ namespace storm { // TODO Matthias: use const reference std::shared_ptr stateGenerationInfo; - // Flag indication if dont care propagation should be used. - bool enableDC = true; + // List with ids of relevant events which should be observed. + std::set const& relevantEvents; //TODO Matthias: make changeable const bool mergeFailedStates = true; diff --git a/src/storm-dft/generator/DftNextStateGenerator.cpp b/src/storm-dft/generator/DftNextStateGenerator.cpp index b59e91d52..f0646a0c5 100644 --- a/src/storm-dft/generator/DftNextStateGenerator.cpp +++ b/src/storm-dft/generator/DftNextStateGenerator.cpp @@ -10,7 +10,7 @@ namespace storm { namespace generator { template - DftNextStateGenerator::DftNextStateGenerator(storm::storage::DFT const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, bool enableDC, bool mergeFailedStates) : mDft(dft), mStateGenerationInfo(stateGenerationInfo), state(nullptr), enableDC(enableDC), mergeFailedStates(mergeFailedStates) { + DftNextStateGenerator::DftNextStateGenerator(storm::storage::DFT const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, std::set const& relevantEvents, bool mergeFailedStates) : mDft(dft), mStateGenerationInfo(stateGenerationInfo), state(nullptr), relevantEvents(relevantEvents), mergeFailedStates(mergeFailedStates) { deterministicModel = !mDft.canHaveNondeterminism(); } @@ -144,7 +144,7 @@ namespace storm { } // Propagate dont cares - while (enableDC && !queues.dontCarePropagationDone()) { + while (relevantEvents.empty() && !queues.dontCarePropagationDone()) { DFTElementPointer next = queues.nextDontCarePropagation(); next->checkDontCareAnymore(*newState, queues); } diff --git a/src/storm-dft/generator/DftNextStateGenerator.h b/src/storm-dft/generator/DftNextStateGenerator.h index 08aa3739e..0574d0266 100644 --- a/src/storm-dft/generator/DftNextStateGenerator.h +++ b/src/storm-dft/generator/DftNextStateGenerator.h @@ -24,7 +24,7 @@ namespace storm { public: typedef std::function StateToIdCallback; - DftNextStateGenerator(storm::storage::DFT const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, bool enableDC, bool mergeFailedStates); + DftNextStateGenerator(storm::storage::DFT const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, std::set const& relevantEvents, bool mergeFailedStates); bool isDeterministicModel() const; std::vector getInitialStates(StateToIdCallback const& stateToIdCallback); @@ -55,8 +55,8 @@ namespace storm { // Current state DFTStatePointer state; - // Flag indicating if dont care propagation is enabled. - bool enableDC; + // List with ids of relevant events which should be observed. + std::set const& relevantEvents; // Flag indication if all failed states should be merged into one. bool mergeFailedStates = true; diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp index c76495177..385d0efe4 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp @@ -17,7 +17,7 @@ namespace storm { namespace modelchecker { template - typename DFTModelChecker::dft_results DFTModelChecker::check(storm::storage::DFT const& origDft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { + typename DFTModelChecker::dft_results DFTModelChecker::check(storm::storage::DFT const& origDft, std::vector> const& properties, bool symred, bool allowModularisation, std::set const& relevantEvents, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { totalTimer.start(); dft_results results; @@ -29,21 +29,21 @@ namespace storm { // Checking DFT if (properties[0]->isTimeOperatorFormula() && allowModularisation) { // Use parallel composition as modularisation approach for expected time - std::shared_ptr> model = buildModelViaComposition(dft, properties, symred, true, enableDC); + std::shared_ptr> model = buildModelViaComposition(dft, properties, symred, true, relevantEvents); // Model checking std::vector resultsValue = checkModel(model, properties); for (ValueType result : resultsValue) { results.push_back(result); } } else { - results = checkHelper(dft, properties, symred, allowModularisation, enableDC, approximationError, approximationHeuristic); + results = checkHelper(dft, properties, symred, allowModularisation, relevantEvents, approximationError, approximationHeuristic); } totalTimer.stop(); return results; } template - typename DFTModelChecker::dft_results DFTModelChecker::checkHelper(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { + typename DFTModelChecker::dft_results DFTModelChecker::checkHelper(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, std::set const& relevantEvents, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { STORM_LOG_TRACE("Check helper called"); std::vector> dfts; bool invResults = false; @@ -98,7 +98,7 @@ namespace storm { std::vector res; for(auto const ft : dfts) { // TODO Matthias: allow approximation in modularisation - dft_results ftResults = checkHelper(ft, {property}, symred, true, enableDC, 0.0); + dft_results ftResults = checkHelper(ft, {property}, symred, true, relevantEvents, 0.0); STORM_LOG_ASSERT(ftResults.size() == 1, "Wrong number of results"); res.push_back(boost::get(ftResults[0])); } @@ -137,12 +137,12 @@ namespace storm { return results; } else { // No modularisation was possible - return checkDFT(dft, properties, symred, enableDC, approximationError, approximationHeuristic); + return checkDFT(dft, properties, symred, relevantEvents, approximationError, approximationHeuristic); } } template - std::shared_ptr> DFTModelChecker::buildModelViaComposition(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, bool enableDC) { + std::shared_ptr> DFTModelChecker::buildModelViaComposition(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, std::set const& relevantEvents) { // TODO Matthias: use approximation? STORM_LOG_TRACE("Build model via composition"); std::vector> dfts; @@ -193,7 +193,7 @@ namespace storm { // Build a single CTMC STORM_LOG_DEBUG("Building Model..."); - storm::builder::ExplicitDFTModelBuilder builder(ft, symmetries, enableDC); + storm::builder::ExplicitDFTModelBuilder builder(ft, symmetries, relevantEvents); typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties); builder.buildModel(labeloptions, 0, 0.0); std::shared_ptr> model = builder.getModel(); @@ -245,7 +245,7 @@ namespace storm { // Build a single CTMC STORM_LOG_DEBUG("Building Model..."); - storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, enableDC); + storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, relevantEvents); typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties); builder.buildModel(labeloptions, 0, 0.0); std::shared_ptr> model = builder.getModel(); @@ -257,7 +257,7 @@ namespace storm { } template - typename DFTModelChecker::dft_results DFTModelChecker::checkDFT(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool enableDC, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { + typename DFTModelChecker::dft_results DFTModelChecker::checkDFT(storm::storage::DFT const& dft, property_vector const& properties, bool symred, std::set const& relevantEvents, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { explorationTimer.start(); // Find symmetries @@ -277,7 +277,7 @@ namespace storm { approximation_result approxResult = std::make_pair(storm::utility::zero(), storm::utility::zero()); std::shared_ptr> model; std::vector newResult; - storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, enableDC); + storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, relevantEvents); typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties); // TODO Matthias: compute approximation for all properties simultaneously? @@ -343,7 +343,7 @@ namespace storm { // Build a single Markov Automaton auto ioSettings = storm::settings::getModule(); STORM_LOG_DEBUG("Building Model..."); - storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, enableDC); + storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, relevantEvents); typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties, ioSettings.isExportExplicitSet() || ioSettings.isExportDotSet()); builder.buildModel(labeloptions, 0, 0.0); std::shared_ptr> model = builder.getModel(); diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.h b/src/storm-dft/modelchecker/dft/DFTModelChecker.h index 7bc07e30e..34568d2f4 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.h +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.h @@ -49,15 +49,14 @@ namespace storm { * * @param origDft Original DFT. * @param properties Properties to check for. - * @param symred Flag indicating if symmetry reduction should be used. + * @param symred Flag whether symmetry reduction should be used. * @param allowModularisation Flag indicating if modularisation is allowed. - * @param enableDC Flag indicating if Don't Care propagation should be used. + * @param relevantEvents List with ids of relevant events which should be observed. * @param approximationError Error allowed for approximation. Value 0 indicates no approximation. - * @param approximationHeuristic Heuristic used for approximation. - * - * @return Model checking results for the given properties. + * @param approximationHeuristic Heuristic used for state space exploration. + * @return Model checking results for the given properties.. */ - dft_results check(storm::storage::DFT const& origDft, property_vector const& properties, bool symred = true, bool allowModularisation = true, bool enableDC = true, double approximationError = 0.0, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); + dft_results check(storm::storage::DFT const& origDft, property_vector const& properties, bool symred = true, bool allowModularisation = true, std::set const& relevantEvents = {}, double approximationError = 0.0, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); /*! * Print timings of all operations to stream. @@ -92,13 +91,12 @@ namespace storm { * @param properties Properties to check for. * @param symred Flag indicating if symmetry reduction should be used. * @param allowModularisation Flag indicating if modularisation is allowed. - * @param enableDC Flag indicating if Don't Caree propagation should be used. + * @param relevantEvents List with ids of relevant events which should be observed. * @param approximationError Error allowed for approximation. Value 0 indicates no approximation. * @param approximationHeuristic Heuristic used for approximation. - * * @return Model checking results (or in case of approximation two results for lower and upper bound) */ - dft_results checkHelper(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); + dft_results checkHelper(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, std::set const& relevantEvents, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); /*! * Internal helper for building a CTMC from a DFT via parallel composition. @@ -107,11 +105,10 @@ namespace storm { * @param properties Properties to check for. * @param symred Flag indicating if symmetry reduction should be used. * @param allowModularisation Flag indicating if modularisation is allowed. - * @param enableDC Flag indicating if Don't Care propagation should be used. - * + * @param relevantEvents List with ids of relevant events which should be observed. * @return CTMC representing the DFT */ - std::shared_ptr> buildModelViaComposition(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, bool enableDC); + std::shared_ptr> buildModelViaComposition(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, std::set const& relevantEvents); /*! * Check model generated from DFT. @@ -119,13 +116,13 @@ namespace storm { * @param dft The DFT. * @param properties Properties to check for. * @param symred Flag indicating if symmetry reduction should be used. - * @param enableDC Flag indicating if Don't Care propagation should be used. + * @param relevantEvents List with ids of relevant events which should be observed. * @param approximationError Error allowed for approximation. Value 0 indicates no approximation. * @param approximationHeuristic Heuristic used for approximation. * * @return Model checking result */ - dft_results checkDFT(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool enableDC, double approximationError = 0.0, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); + dft_results checkDFT(storm::storage::DFT const& dft, property_vector const& properties, bool symred, std::set const& relevantEvents = {}, double approximationError = 0.0, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); /*! * Check the given markov model for the given properties. diff --git a/src/storm-dft/settings/modules/FaultTreeSettings.cpp b/src/storm-dft/settings/modules/FaultTreeSettings.cpp index 740c6aa54..fd365a1ea 100644 --- a/src/storm-dft/settings/modules/FaultTreeSettings.cpp +++ b/src/storm-dft/settings/modules/FaultTreeSettings.cpp @@ -7,16 +7,19 @@ #include "storm/settings/ArgumentBuilder.h" #include "storm/settings/Argument.h" #include "storm/exceptions/IllegalArgumentValueException.h" +#include "storm/exceptions/InvalidSettingsException.h" +#include "storm/parser/CSVParser.h" namespace storm { namespace settings { namespace modules { - + const std::string FaultTreeSettings::moduleName = "dft"; const std::string FaultTreeSettings::symmetryReductionOptionName = "symmetryreduction"; const std::string FaultTreeSettings::symmetryReductionOptionShortName = "symred"; const std::string FaultTreeSettings::modularisationOptionName = "modularisation"; const std::string FaultTreeSettings::disableDCOptionName = "disabledc"; + const std::string FaultTreeSettings::relevantEventsOptionName = "relevantevents"; const std::string FaultTreeSettings::approximationErrorOptionName = "approximation"; const std::string FaultTreeSettings::approximationErrorOptionShortName = "approx"; const std::string FaultTreeSettings::approximationHeuristicOptionName = "approximationheuristic"; @@ -30,6 +33,8 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, modularisationOptionName, false, "Use modularisation (not applicable for expected time).").build()); this->addOption(storm::settings::OptionBuilder(moduleName, disableDCOptionName, false, "Disable Dont Care propagation.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, firstDependencyOptionName, false, "Avoid non-determinism by always taking the first possible dependency.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, relevantEventsOptionName, false, "Specifies the relevant events from the DFT.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of relevant events. 'all' marks all events as relevant, The default '' or 'none' mark only the top level event as relevant.").setDefaultValueString("").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, approximationErrorOptionName, false, "Approximation error allowed.").setShortName(approximationErrorOptionShortName).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("error", "The relative approximation error to use.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterEqualValidator(0.0)).build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, approximationHeuristicOptionName, false, "Set the heuristic used for approximation.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("heuristic", "The name of the heuristic used for approximation.") @@ -43,15 +48,23 @@ namespace storm { bool FaultTreeSettings::useSymmetryReduction() const { return this->getOption(symmetryReductionOptionName).getHasOptionBeenSet(); } - + bool FaultTreeSettings::useModularisation() const { return this->getOption(modularisationOptionName).getHasOptionBeenSet(); } - + bool FaultTreeSettings::isDisableDC() const { return this->getOption(disableDCOptionName).getHasOptionBeenSet(); } + bool FaultTreeSettings::areRelevantEventsSet() const { + return this->getOption(relevantEventsOptionName).getHasOptionBeenSet() && (this->getOption(relevantEventsOptionName).getArgumentByName("values").getValueAsString() != ""); + } + + std::vector FaultTreeSettings::getRelevantEvents() const { + return storm::parser::parseCommaSeperatedValues(this->getOption(relevantEventsOptionName).getArgumentByName("values").getValueAsString()); + } + bool FaultTreeSettings::isApproximationErrorSet() const { return this->getOption(approximationErrorOptionName).getHasOptionBeenSet(); } @@ -81,14 +94,16 @@ namespace storm { return this->getOption(solveWithSmtOptionName).getHasOptionBeenSet(); } #endif - + void FaultTreeSettings::finalize() { } bool FaultTreeSettings::check() const { + // Ensure that disableDC and relevantEvents are not set at the same time + STORM_LOG_THROW(!isDisableDC() || !areRelevantEventsSet(), storm::exceptions::InvalidSettingsException, "DisableDC and relevantSets can not both be set."); return true; } - + } // namespace modules } // namespace settings } // namespace storm diff --git a/src/storm-dft/settings/modules/FaultTreeSettings.h b/src/storm-dft/settings/modules/FaultTreeSettings.h index 171d5c38e..1e88b48e4 100644 --- a/src/storm-dft/settings/modules/FaultTreeSettings.h +++ b/src/storm-dft/settings/modules/FaultTreeSettings.h @@ -25,14 +25,14 @@ namespace storm { * @return True iff the option was set. */ bool useSymmetryReduction() const; - + /*! * Retrieves whether the option to use modularisation is set. * * @return True iff the option was set. */ bool useModularisation() const; - + /*! * Retrieves whether the option to disable Dont Care propagation is set. * @@ -40,6 +40,20 @@ namespace storm { */ bool isDisableDC() const; + /*! + * Retrieves whether the option to give relevant events is set. + * + * @return True iff the option was set. + */ + bool areRelevantEventsSet() const; + + /*! + * Retrieves the relevant events which should be present throughout the analysis. + * + * @return The list of relevant events. + */ + std::vector getRelevantEvents() const; + /*! * Retrieves whether the option to compute an approximation is set. * @@ -67,28 +81,32 @@ namespace storm { * @return True iff the option was set. */ bool isTakeFirstDependency() const; - + #ifdef STORM_HAVE_Z3 + /*! * Retrieves whether the DFT should be checked via SMT. * * @return True iff the option was set. */ bool solveWithSMT() const; + #endif - + bool check() const override; + void finalize() override; // The name of the module. static const std::string moduleName; private: - // Define the string names of the options as constants. + // Define the string names of the options as constants. static const std::string symmetryReductionOptionName; static const std::string symmetryReductionOptionShortName; static const std::string modularisationOptionName; static const std::string disableDCOptionName; + static const std::string relevantEventsOptionName; static const std::string approximationErrorOptionName; static const std::string approximationErrorOptionShortName; static const std::string approximationHeuristicOptionName; diff --git a/src/storm-dft/storage/dft/DFT.cpp b/src/storm-dft/storage/dft/DFT.cpp index a9ecb8a5a..6a926e3a3 100644 --- a/src/storm-dft/storage/dft/DFT.cpp +++ b/src/storm-dft/storage/dft/DFT.cpp @@ -845,6 +845,22 @@ namespace storm { return std::make_tuple(parents, ingoingDeps, outgoingDeps); } + template + std::set DFT::getAllIds() const { + std::set ids; + for (auto const& elem : mElements) { + ids.insert(elem->id()); + } + return ids; + } + + template + size_t DFT::getIndex(std::string const& name) const { + auto iter = std::find_if(mElements.begin(), mElements.end(), [&name](DFTElementPointer const& e) { return e->name() == name; }); + STORM_LOG_THROW(iter != mElements.end(), storm::exceptions::InvalidArgumentException, "Event name '" << name << "' not known."); + return (*iter)->id(); + } + template void DFT::writeStatsToStream(std::ostream& stream) const { // Count individual types of elements diff --git a/src/storm-dft/storage/dft/DFT.h b/src/storm-dft/storage/dft/DFT.h index 940e8adcf..dfb7c583d 100644 --- a/src/storm-dft/storage/dft/DFT.h +++ b/src/storm-dft/storage/dft/DFT.h @@ -305,6 +305,19 @@ namespace storm { void writeStatsToStream(std::ostream& stream) const; + /*! + * Get Ids of all elements. + * @return All element ids. + */ + std::set getAllIds() const; + + /*! + * Get id for the given element name. + * @param name Name of element. + * @return Index of element. + */ + size_t getIndex(std::string const& name) const; + private: std::tuple, std::vector, std::vector> getSortedParentAndDependencyIds(size_t index) const; diff --git a/src/test/storm-dft/api/DftApproximationTest.cpp b/src/test/storm-dft/api/DftApproximationTest.cpp index d00973da1..7718d9218 100644 --- a/src/test/storm-dft/api/DftApproximationTest.cpp +++ b/src/test/storm-dft/api/DftApproximationTest.cpp @@ -15,22 +15,27 @@ namespace { class ApproxDepthConfig { public: typedef double ValueType; + static DftAnalysisConfig createConfig() { - return DftAnalysisConfig {storm::builder::ApproximationHeuristic::DEPTH, false}; + return DftAnalysisConfig{storm::builder::ApproximationHeuristic::DEPTH, false}; } }; + class ApproxProbabilityConfig { public: typedef double ValueType; + static DftAnalysisConfig createConfig() { - return DftAnalysisConfig {storm::builder::ApproximationHeuristic::PROBABILITY, false}; + return DftAnalysisConfig{storm::builder::ApproximationHeuristic::PROBABILITY, false}; } }; + class ApproxBoundDifferenceConfig { public: typedef double ValueType; + static DftAnalysisConfig createConfig() { - return DftAnalysisConfig {storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE, false}; + return DftAnalysisConfig{storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE, false}; } }; @@ -52,7 +57,8 @@ namespace { EXPECT_TRUE(storm::api::isWellFormed(*dft)); std::string property = "T=? [F \"failed\"]"; std::vector> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(property)); - typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFTApprox(*dft, properties, config.useSR, false, true, errorBound, config.heuristic, false); + typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, config.useSR, false, {}, errorBound, + config.heuristic, false); return boost::get::approximation_result>(results[0]); } @@ -62,7 +68,8 @@ namespace { std::stringstream propertyStream; propertyStream << "P=? [F<=" << timeBound << " \"failed\"]"; std::vector> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(propertyStream.str())); - typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFTApprox(*dft, properties, config.useSR, false, true, errorBound, config.heuristic, false); + typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, config.useSR, false, {}, errorBound, + config.heuristic, false); return boost::get::approximation_result>(results[0]); } @@ -83,7 +90,7 @@ namespace { std::pair approxResult = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/hecs_3_2_2_np.dft", errorBound); EXPECT_LE(approxResult.first, 417.9436693); EXPECT_GE(approxResult.second, 417.9436693); - EXPECT_LE(2*(approxResult.second - approxResult.first) / (approxResult.first + approxResult.second), errorBound); + EXPECT_LE(2 * (approxResult.second - approxResult.first) / (approxResult.first + approxResult.second), errorBound); // Ensure results are not equal -> not exact values were computed EXPECT_GE(approxResult.second - approxResult.first, errorBound * approxResult.first / 10); } diff --git a/src/test/storm-dft/api/DftModelCheckerTest.cpp b/src/test/storm-dft/api/DftModelCheckerTest.cpp index 6da316081..790c29509 100644 --- a/src/test/storm-dft/api/DftModelCheckerTest.cpp +++ b/src/test/storm-dft/api/DftModelCheckerTest.cpp @@ -16,36 +16,45 @@ namespace { class NoOptimizationsConfig { public: typedef double ValueType; + static DftAnalysisConfig createConfig() { - return DftAnalysisConfig {false, false, false}; + return DftAnalysisConfig{false, false, false}; } }; + class DontCareConfig { public: typedef double ValueType; + static DftAnalysisConfig createConfig() { - return DftAnalysisConfig {false, false, true}; + return DftAnalysisConfig{false, false, true}; } }; + class ModularisationConfig { public: typedef double ValueType; + static DftAnalysisConfig createConfig() { - return DftAnalysisConfig {false, true, false}; + return DftAnalysisConfig{false, true, false}; } }; + class SymmetryReductionConfig { public: typedef double ValueType; + static DftAnalysisConfig createConfig() { - return DftAnalysisConfig {true, false, false}; + return DftAnalysisConfig{true, false, false}; } }; + class AllOptimizationsConfig { public: typedef double ValueType; + static DftAnalysisConfig createConfig() { - return DftAnalysisConfig {true, true, true}; + return DftAnalysisConfig{true, true, true}; } }; @@ -67,7 +76,12 @@ namespace { EXPECT_TRUE(storm::api::isWellFormed(*dft)); std::string property = "Tmin=? [F \"failed\"]"; std::vector> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(property)); - typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, config.useSR, config.useMod, config.useDC, false); + std::set relevantEvents; + if (config.useDC) { + relevantEvents = dft->getAllIds(); + } + typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, config.useSR, config.useMod, + relevantEvents); return boost::get(results[0]); } @@ -97,13 +111,13 @@ namespace { TYPED_TEST(DftModelCheckerTest, VotingMTTF) { double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/voting.dft"); - EXPECT_FLOAT_EQ(result, 5/3.0); + EXPECT_FLOAT_EQ(result, 5 / 3.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/voting2.dft"); - EXPECT_FLOAT_EQ(result, 10/17.0); + EXPECT_FLOAT_EQ(result, 10 / 17.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/voting3.dft"); EXPECT_FLOAT_EQ(result, 1.7356173); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/voting4.dft"); - EXPECT_FLOAT_EQ(result, 5/6.0); + EXPECT_FLOAT_EQ(result, 5 / 6.0); } TYPED_TEST(DftModelCheckerTest, PandMTTF) { @@ -127,7 +141,7 @@ namespace { EXPECT_THROW(this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep5.dft"), storm::exceptions::NotSupportedException); } else { result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep.dft"); - EXPECT_FLOAT_EQ(result, 2/3.0); + EXPECT_FLOAT_EQ(result, 2 / 3.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep4.dft"); EXPECT_FLOAT_EQ(result, 1); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep5.dft"); @@ -137,15 +151,15 @@ namespace { TYPED_TEST(DftModelCheckerTest, PdepMTTF) { double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep.dft"); - EXPECT_FLOAT_EQ(result, 8/3.0); + EXPECT_FLOAT_EQ(result, 8 / 3.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep3.dft"); - EXPECT_FLOAT_EQ(result, 67/24.0); + EXPECT_FLOAT_EQ(result, 67 / 24.0); if (this->getConfig().useMod) { - if (!this->getConfig().useDC) { + if (this->getConfig().useDC) { EXPECT_THROW(this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep2.dft"), storm::exceptions::NotSupportedException); } else { result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep2.dft"); - EXPECT_FLOAT_EQ(result, 38/15.0); + EXPECT_FLOAT_EQ(result, 38 / 15.0); } EXPECT_THROW(this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep4.dft"), storm::exceptions::NotSupportedException); } else { @@ -153,17 +167,18 @@ namespace { EXPECT_EQ(result, storm::utility::infinity()); } } + TYPED_TEST(DftModelCheckerTest, SpareMTTF) { double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare.dft"); - EXPECT_FLOAT_EQ(result, 46/13.0); + EXPECT_FLOAT_EQ(result, 46 / 13.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare2.dft"); - EXPECT_FLOAT_EQ(result, 43/23.0); + EXPECT_FLOAT_EQ(result, 43 / 23.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare3.dft"); - EXPECT_FLOAT_EQ(result, 14/11.0); + EXPECT_FLOAT_EQ(result, 14 / 11.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare4.dft"); EXPECT_FLOAT_EQ(result, 4.8458967); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare5.dft"); - EXPECT_FLOAT_EQ(result, 8/3.0); + EXPECT_FLOAT_EQ(result, 8 / 3.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare6.dft"); EXPECT_FLOAT_EQ(result, 1.4); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare7.dft"); @@ -171,6 +186,7 @@ namespace { result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare8.dft"); EXPECT_FLOAT_EQ(result, 4.78846); // DFTCalc has result of 4.33779 due to different semantics of nested spares } + TYPED_TEST(DftModelCheckerTest, SeqMTTF) { double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/seq.dft"); EXPECT_FLOAT_EQ(result, 4); From 5f7bf64d44c0970dfa0cc0b70332f273089d57f5 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 5 Apr 2019 19:10:14 +0200 Subject: [PATCH 28/40] Some refactoring --- src/storm-dft-cli/storm-dft.cpp | 34 ++++++++++++++++++--------------- src/storm-dft/api/storm-dft.h | 19 +++++++----------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index 0514e63d0..a804a798d 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -1,17 +1,17 @@ +#include #include "storm-dft/api/storm-dft.h" #include "storm-dft/settings/DftSettings.h" +#include "storm-dft/settings/modules/DftGspnSettings.h" #include "storm-dft/settings/modules/DftIOSettings.h" #include "storm-dft/settings/modules/FaultTreeSettings.h" -#include "storm-dft/settings/modules/DftGspnSettings.h" +#include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/IOSettings.h" #include "storm/settings/modules/ResourceSettings.h" -#include "storm/settings/modules/GeneralSettings.h" - - -#include "storm-parsers/api/storm-parsers.h" #include "storm/utility/initialize.h" #include "storm-cli-utilities/cli.h" +#include "storm-parsers/api/storm-parsers.h" + /*! * Process commandline options and start computations. @@ -28,7 +28,7 @@ void processOptions() { if (!dftIOSettings.isDftFileSet() && !dftIOSettings.isDftJsonFileSet()) { - STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "No input model."); + STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "No input model given."); } // Build DFT from given file @@ -48,13 +48,12 @@ void processOptions() { if (dftIOSettings.isExportToJson()) { // Export to json storm::api::exportDFTToJsonFile(*dft, dftIOSettings.getExportJsonFilename()); - return; } // Check well-formedness of DFT std::stringstream stream; if (!dft->checkWellFormedness(stream)) { - STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "DFT is not well-formed: " << stream.str()); + STORM_LOG_THROW(false, storm::exceptions::UnmetRequirementException, "DFT is not well-formed: " << stream.str()); } if (dftGspnSettings.isTransformToGspn()) { @@ -82,14 +81,16 @@ void processOptions() { } #endif + // From now on we analyse DFT via model checking + // Set min or max std::string optimizationDirection = "min"; if (dftIOSettings.isComputeMaximalValue()) { - STORM_LOG_THROW(!dftIOSettings.isComputeMinimalValue(), storm::exceptions::InvalidSettingsException, "Cannot compute minimal and maximal values at the same time."); optimizationDirection = "max"; } - // Construct properties to analyse + // Construct properties to analyse. + // We allow multiple properties to be checked at once. std::vector properties; if (ioSettings.isPropertySet()) { properties.push_back(ioSettings.getProperty()); @@ -114,10 +115,13 @@ void processOptions() { } // Build properties - STORM_LOG_THROW(!properties.empty(), storm::exceptions::InvalidSettingsException, "No property given."); - std::string propString = properties[0]; - for (size_t i = 1; i < properties.size(); ++i) { - propString += ";" + properties[i]; + STORM_LOG_WARN_COND(!properties.empty(), "No property given."); + std::string propString; + for (size_t i = 0; i < properties.size(); ++i) { + if (i + 1 < properties.size()) { + propString += ";"; + } + propString += properties[i]; } std::vector> props = storm::api::extractFormulasFromProperties(storm::api::parseProperties(propString)); @@ -159,7 +163,7 @@ void processOptions() { * * @param argc The argc argument of main(). * @param argv The argv argument of main(). - * @return Return code, 0 if successfull, not 0 otherwise. + * @return Return code, 0 if successful, > 0 otherwise. */ int main(const int argc, const char** argv) { try { diff --git a/src/storm-dft/api/storm-dft.h b/src/storm-dft/api/storm-dft.h index f36bfc3ca..f801b0eda 100644 --- a/src/storm-dft/api/storm-dft.h +++ b/src/storm-dft/api/storm-dft.h @@ -5,11 +5,10 @@ #include "storm-dft/parser/DFTGalileoParser.h" #include "storm-dft/parser/DFTJsonParser.h" #include "storm-dft/storage/dft/DftJsonExporter.h" - #include "storm-dft/modelchecker/dft/DFTModelChecker.h" #include "storm-dft/modelchecker/dft/DFTASFChecker.h" - #include "storm-dft/transformations/DftToGspnTransformator.h" + #include "storm-gspn/api/storm-gspn.h" namespace storm { @@ -19,38 +18,35 @@ namespace storm { * Load DFT from Galileo file. * * @param file File containing DFT description in Galileo format. - * * @return DFT. */ template std::shared_ptr> loadDFTGalileoFile(std::string const& file) { - return std::make_shared>(storm::parser::DFTGalileoParser::parseDFT(file)); + return std::make_shared>(storm::parser::DFTGalileoParser::parseDFT(file)); } /*! * Load DFT from JSON string. * * @param jsonString String containing DFT description in JSON format. - * * @return DFT. */ template std::shared_ptr> loadDFTJsonString(std::string const& jsonString) { - storm::parser::DFTJsonParser parser; - return std::make_shared>(parser.parseJsonFromString(jsonString)); + storm::parser::DFTJsonParser parser; + return std::make_shared>(parser.parseJsonFromString(jsonString)); } /*! * Load DFT from JSON file. * * @param file File containing DFT description in JSON format. - * * @return DFT. */ template std::shared_ptr> loadDFTJsonFile(std::string const& file) { - storm::parser::DFTJsonParser parser; - return std::make_shared>(parser.parseJsonFromFile(file)); + storm::parser::DFTJsonParser parser; + return std::make_shared>(parser.parseJsonFromFile(file)); } /*! @@ -107,6 +103,7 @@ namespace storm { * Export DFT to JSON string. * * @param dft DFT. + * @return DFT in JSON format. */ template std::string exportDFTToJsonString(storm::storage::DFT const& dft); @@ -124,7 +121,6 @@ namespace storm { * Transform DFT to GSPN. * * @param dft DFT. - * * @return Pair of GSPN and id of failed place corresponding to the top level element. */ template @@ -135,7 +131,6 @@ namespace storm { * * @param gspn GSPN. * @param toplevelFailedPlace Id of the failed place in the GSPN for the top level element in the DFT. - * * @return JANI model. */ std::shared_ptr transformToJani(storm::gspn::GSPN const& gspn, uint64_t toplevelFailedPlace); From 01df35236b6badd6e5075ce7ad20135d8162cbce Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 10 Apr 2019 16:23:35 +0200 Subject: [PATCH 29/40] Updated some TODOS --- src/storm-dft/builder/DFTBuilder.h | 4 +-- .../builder/ExplicitDFTModelBuilder.cpp | 34 +++++++++---------- .../builder/ExplicitDFTModelBuilder.h | 6 ++-- .../generator/DftNextStateGenerator.cpp | 3 +- .../modelchecker/dft/DFTModelChecker.cpp | 14 ++++---- src/storm-dft/storage/dft/DFTState.cpp | 2 +- 6 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/storm-dft/builder/DFTBuilder.h b/src/storm-dft/builder/DFTBuilder.h index b12013fc7..9ce85db0f 100644 --- a/src/storm-dft/builder/DFTBuilder.h +++ b/src/storm-dft/builder/DFTBuilder.h @@ -106,7 +106,7 @@ namespace storm { } std::string trigger = children[0]; - //TODO Matthias: collect constraints for SMT solving + //TODO: collect constraints for SMT solving //0 <= probability <= 1 if (binaryDependencies && !storm::utility::isOne(probability) && children.size() > 2) { // Introduce additional element for first capturing the probabilistic dependency @@ -195,7 +195,7 @@ namespace storm { } bool addBasicElementExponential(std::string const& name, ValueType failureRate, ValueType dormancyFactor, bool transient = false) { - //TODO Matthias: collect constraints for SMT solving + //TODO: collect constraints for SMT solving //0 <= dormancyFactor <= 1 if (nameInUse(name)) { STORM_LOG_ERROR("Element with name '" << name << "' already exists."); diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index aba061935..7b364204e 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -155,7 +155,7 @@ namespace storm { setMarkovian(behavior.begin()->isMarkovian()); // Now add self loop. - // TODO Matthias: maybe use general method. + // TODO: maybe use general method. STORM_LOG_ASSERT(behavior.getNumberOfChoices() == 1, "Wrong number of choices for failed state."); STORM_LOG_ASSERT(behavior.begin()->size() == 1, "Wrong number of transitions for failed state."); std::pair stateProbabilityPair = *(behavior.begin()->begin()); @@ -214,7 +214,7 @@ namespace storm { // Fix the entries in the transition matrix according to the mapping of ids to row group indices STORM_LOG_ASSERT(matrixBuilder.getRemapping(initialStateIndex) == initialStateIndex, "Initial state should not be remapped."); - // TODO Matthias: do not consider all rows? + // TODO: do not consider all rows? STORM_LOG_TRACE("Remap matrix: " << matrixBuilder.stateRemapping << ", offset: " << matrixBuilder.mappingOffset); matrixBuilder.remap(); @@ -238,16 +238,16 @@ namespace storm { void ExplicitDFTModelBuilder::initializeNextIteration() { STORM_LOG_TRACE("Refining DFT state space"); - // TODO Matthias: should be easier now as skipped states all are at the end of the matrix + // TODO: should be easier now as skipped states all are at the end of the matrix // Push skipped states to explore queue - // TODO Matthias: remove + // TODO: remove for (auto const& skippedState : skippedStates) { statesNotExplored[skippedState.second.first->getId()] = skippedState.second; explorationQueue.push(skippedState.second.second); } // Initialize matrix builder again - // TODO Matthias: avoid copy + // TODO: avoid copy std::vector copyRemapping = matrixBuilder.stateRemapping; matrixBuilder = MatrixBuilder(!generator.isDeterministicModel()); matrixBuilder.stateRemapping = copyRemapping; @@ -309,7 +309,7 @@ namespace storm { modelComponents.markovianStates = markovianStatesNew; // Build submatrix for expanded states - // TODO Matthias: only use row groups when necessary + // TODO: only use row groups when necessary for (StateType oldRowGroup = 0; oldRowGroup < modelComponents.transitionMatrix.getRowGroupCount(); ++oldRowGroup) { if (indexRemapping[oldRowGroup] < nrExpandedStates) { // State is expanded -> copy to new matrix @@ -342,7 +342,7 @@ namespace storm { size_t nrSkippedStates = 0; storm::utility::ProgressMeasurement progress("explored states"); progress.startNewMeasurement(0); - // TODO Matthias: do not empty queue every time but break before + // TODO: do not empty queue every time but break before while (!explorationQueue.empty()) { // Get the first state in the queue ExplorationHeuristicPointer currentExplorationHeuristic = explorationQueue.pop(); @@ -379,7 +379,7 @@ namespace storm { STORM_LOG_TRACE("Skip expansion of state: " << dft.getStateString(currentState)); setMarkovian(true); // Add transition to target state with temporary value 0 - // TODO Matthias: what to do when there is no unique target state? + // TODO: what to do when there is no unique target state? matrixBuilder.addTransition(failedStateId, storm::utility::zero()); // Remember skipped state skippedStates[matrixBuilder.getCurrentRowGroup() - 1] = std::make_pair(currentState, currentExplorationHeuristic); @@ -434,7 +434,7 @@ namespace storm { STORM_LOG_ASSERT(!currentState->isPseudoState(), "State is pseudo state."); // Initialize bounds - // TODO Mathias: avoid hack + // TODO: avoid hack ValueType lowerBound = getLowerBound(state); ValueType upperBound = getUpperBound(state); heuristic->setBounds(lowerBound, upperBound); @@ -522,12 +522,12 @@ namespace storm { template std::shared_ptr> ExplicitDFTModelBuilder::getModelApproximation(bool lowerBound, bool expectedTime) { if (expectedTime) { - // TODO Matthias: handle case with no skipped states + // TODO: handle case with no skipped states changeMatrixBound(modelComponents.transitionMatrix, lowerBound); return createModel(true); } else { // Change model for probabilities - // TODO Matthias: make nicer + // TODO: make nicer storm::storage::SparseMatrix matrix = modelComponents.transitionMatrix; storm::models::sparse::StateLabeling labeling = modelComponents.stateLabeling; if (lowerBound) { @@ -554,7 +554,7 @@ namespace storm { } else { // Build MA // Compute exit rates - // TODO Matthias: avoid computing multiple times + // TODO: avoid computing multiple times modelComponents.exitRates = std::vector(modelComponents.markovianStates.size()); std::vector::index_type> indices = matrix.getRowGroupIndices(); for (StateType stateIndex = 0; stateIndex < modelComponents.markovianStates.size(); ++stateIndex) { @@ -573,7 +573,7 @@ namespace storm { std::shared_ptr> ma = std::make_shared>(std::move(maComponents)); if (ma->hasOnlyTrivialNondeterminism()) { // Markov automaton can be converted into CTMC - // TODO Matthias: change components which were not moved accordingly + // TODO: change components which were not moved accordingly model = ma->convertToCtmc(); } else { model = ma; @@ -604,7 +604,7 @@ namespace storm { } else { // Build MA // Compute exit rates - // TODO Matthias: avoid computing multiple times + // TODO: avoid computing multiple times modelComponents.exitRates = std::vector(modelComponents.markovianStates.size()); std::vector::index_type> indices = modelComponents.transitionMatrix.getRowGroupIndices(); for (StateType stateIndex = 0; stateIndex < modelComponents.markovianStates.size(); ++stateIndex) { @@ -632,7 +632,7 @@ namespace storm { } if (ma->hasOnlyTrivialNondeterminism()) { // Markov automaton can be converted into CTMC - // TODO Matthias: change components which were not moved accordingly + // TODO: change components which were not moved accordingly model = ma->convertToCtmc(); } else { model = ma; @@ -770,7 +770,7 @@ namespace storm { return result; } - // TODO Matthias: works only for <64 BEs! + // TODO: works only for <64 BEs! // WARNING: this code produces wrong results for more than 32 BEs /*for (size_t i = 1; i < 4 && i <= rates.size(); ++i) { size_t permutation = smallestIntWithNBitsSet(static_cast(i)); @@ -842,7 +842,7 @@ namespace storm { STORM_LOG_ASSERT(iter->second.first->status() == state->status(), "Pseudo states do not coincide."); state->setId(stateId); // Update mapping to map to concrete state now - // TODO Matthias: just change pointer? + // TODO: just change pointer? statesNotExplored[stateId] = std::make_pair(state, iter->second.second); // We do not push the new state on the exploration queue as the pseudo state was already pushed STORM_LOG_TRACE("Created pseudo state " << dft.getStateString(state)); diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.h b/src/storm-dft/builder/ExplicitDFTModelBuilder.h index ce00eb144..5598ac6ef 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.h +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.h @@ -135,7 +135,7 @@ namespace storm { size_t mappingOffset; // A mapping from state ids to the row group indices in which they actually reside. - // TODO Matthias: avoid hack with fixed int type + // TODO: avoid hack with fixed int type std::vector stateRemapping; private: @@ -309,13 +309,13 @@ namespace storm { storm::storage::DFT const& dft; // General information for state generation - // TODO Matthias: use const reference + // TODO: use const reference std::shared_ptr stateGenerationInfo; // List with ids of relevant events which should be observed. std::set const& relevantEvents; - //TODO Matthias: make changeable + //TODO: merge depending on relevant events const bool mergeFailedStates = true; // Heuristic used for approximation diff --git a/src/storm-dft/generator/DftNextStateGenerator.cpp b/src/storm-dft/generator/DftNextStateGenerator.cpp index f0646a0c5..495631817 100644 --- a/src/storm-dft/generator/DftNextStateGenerator.cpp +++ b/src/storm-dft/generator/DftNextStateGenerator.cpp @@ -33,7 +33,7 @@ namespace storm { template void DftNextStateGenerator::load(storm::storage::BitVector const& state) { // Load the state from bitvector - size_t id = 0; //TODO Matthias: set correct id + size_t id = 0; //TODO: set correct id this->state = std::make_shared>(state, mDft, mStateGenerationInfo, id); } @@ -144,6 +144,7 @@ namespace storm { } // Propagate dont cares + // TODO: do not set DC for relevant events while (relevantEvents.empty() && !queues.dontCarePropagationDone()) { DFTElementPointer next = queues.nextDontCarePropagation(); next->checkDontCareAnymore(*newState, queues); diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp index 385d0efe4..5d6806f58 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp @@ -24,7 +24,7 @@ namespace storm { // Optimizing DFT storm::storage::DFT dft = origDft.optimize(); - // TODO Matthias: check that all paths reach the target state for approximation + // TODO: check that all paths reach the target state for approximation // Checking DFT if (properties[0]->isTimeOperatorFormula() && allowModularisation) { @@ -88,7 +88,7 @@ namespace storm { // Perform modularisation if(dfts.size() > 1) { STORM_LOG_TRACE("Recursive CHECK Call"); - // TODO Matthias: compute simultaneously + // TODO: compute simultaneously dft_results results; for (auto property : properties) { if (!property->isProbabilityOperatorFormula()) { @@ -97,7 +97,7 @@ namespace storm { // Recursively call model checking std::vector res; for(auto const ft : dfts) { - // TODO Matthias: allow approximation in modularisation + // TODO: allow approximation in modularisation dft_results ftResults = checkHelper(ft, {property}, symred, true, relevantEvents, 0.0); STORM_LOG_ASSERT(ftResults.size() == 1, "Wrong number of results"); res.push_back(boost::get(ftResults[0])); @@ -143,7 +143,7 @@ namespace storm { template std::shared_ptr> DFTModelChecker::buildModelViaComposition(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, std::set const& relevantEvents) { - // TODO Matthias: use approximation? + // TODO: use approximation? STORM_LOG_TRACE("Build model via composition"); std::vector> dfts; bool isAnd = true; @@ -280,7 +280,7 @@ namespace storm { storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, relevantEvents); typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties); - // TODO Matthias: compute approximation for all properties simultaneously? + // TODO: compute approximation for all properties simultaneously? std::shared_ptr property = properties[0]; if (properties.size() > 1) { STORM_LOG_WARN("Computing approximation only for first property: " << *property); @@ -295,12 +295,12 @@ namespace storm { explorationTimer.start(); } STORM_LOG_DEBUG("Building model..."); - // TODO Matthias refine model using existing model and MC results + // TODO refine model using existing model and MC results builder.buildModel(labeloptions, iteration, approximationError, approximationHeuristic); explorationTimer.stop(); buildingTimer.start(); - // TODO Matthias: possible to do bisimulation on approximated model and not on concrete one? + // TODO: possible to do bisimulation on approximated model and not on concrete one? // Build model for lower bound STORM_LOG_DEBUG("Getting model for lower bound..."); diff --git a/src/storm-dft/storage/dft/DFTState.cpp b/src/storm-dft/storage/dft/DFTState.cpp index 13d9c5279..804068576 100644 --- a/src/storm-dft/storage/dft/DFTState.cpp +++ b/src/storm-dft/storage/dft/DFTState.cpp @@ -7,7 +7,7 @@ namespace storm { template DFTState::DFTState(DFT const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(dft.stateBitVectorSize()), mId(id), failableElements(dft.nrElements()), mPseudoState(false), mDft(dft), mStateGenerationInfo(stateGenerationInfo) { - // TODO Matthias: use construct() + // TODO: use construct() // Initialize uses for(size_t spareId : mDft.getSpareIndices()) { From 86c183a342efe4e76b8456af5927caa801e1830d Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 10 Apr 2019 16:46:36 +0200 Subject: [PATCH 30/40] Fixed seqfault when no property was given --- src/storm-dft-cli/storm-dft.cpp | 33 +++++++++++-------- .../modelchecker/dft/DFTModelChecker.cpp | 1 + 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index a804a798d..19dec5f9d 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -115,15 +115,17 @@ void processOptions() { } // Build properties - STORM_LOG_WARN_COND(!properties.empty(), "No property given."); - std::string propString; - for (size_t i = 0; i < properties.size(); ++i) { - if (i + 1 < properties.size()) { - propString += ";"; + std::vector> props; + if (!properties.empty()) { + std::string propString; + for (size_t i = 0; i < properties.size(); ++i) { + if (i + 1 < properties.size()) { + propString += ";"; + } + propString += properties[i]; } - propString += properties[i]; + props = storm::api::extractFormulasFromProperties(storm::api::parseProperties(propString)); } - std::vector> props = storm::api::extractFormulasFromProperties(storm::api::parseProperties(propString)); // Set relevant elements // TODO: also incorporate events from properties @@ -149,13 +151,18 @@ void processOptions() { relevantEvents = dft->getAllIds(); } - // Carry out the actual analysis - double approximationError = 0.0; - if (faultTreeSettings.isApproximationErrorSet()) { - approximationError = faultTreeSettings.getApproximationError(); + // Analyze DFT + // TODO allow building of state space even without properties + if (props.empty()) { + STORM_LOG_WARN("No property given. No analysis will be performed."); + } else { + double approximationError = 0.0; + if (faultTreeSettings.isApproximationErrorSet()) { + approximationError = faultTreeSettings.getApproximationError(); + } + storm::api::analyzeDFT(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), relevantEvents, approximationError, + faultTreeSettings.getApproximationHeuristic(), true); } - storm::api::analyzeDFT(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), relevantEvents, approximationError, - faultTreeSettings.getApproximationHeuristic(), true); } /*! diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp index 5d6806f58..19a091a50 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp @@ -27,6 +27,7 @@ namespace storm { // TODO: check that all paths reach the target state for approximation // Checking DFT + // TODO: distinguish for all properties, not only for first one if (properties[0]->isTimeOperatorFormula() && allowModularisation) { // Use parallel composition as modularisation approach for expected time std::shared_ptr> model = buildModelViaComposition(dft, properties, symred, true, relevantEvents); From ee023576126f80b2705ae5ff94b6c69eef34b64d Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 10 Apr 2019 17:51:56 +0200 Subject: [PATCH 31/40] Allow empty choices due to restrictions in state exploration --- src/storm-dft/generator/DftNextStateGenerator.cpp | 9 ++++++++- src/storm-dft/storage/dft/DFT.cpp | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/storm-dft/generator/DftNextStateGenerator.cpp b/src/storm-dft/generator/DftNextStateGenerator.cpp index 495631817..1e9a53045 100644 --- a/src/storm-dft/generator/DftNextStateGenerator.cpp +++ b/src/storm-dft/generator/DftNextStateGenerator.cpp @@ -204,7 +204,14 @@ namespace storm { return exploreState(stateToIdCallback, false); } } else { - STORM_LOG_ASSERT(choice.size() > 0, "No transitions were generated"); + if (choice.size() == 0) { + // No transition was generated + STORM_LOG_TRACE("No transitions were generated."); + // Add self loop + choice.addProbability(state->getId(), storm::utility::one()); + STORM_LOG_TRACE("Added self loop for " << state->getId()); + } + STORM_LOG_ASSERT(choice.size() > 0, "At least one choice should have been generated."); // Add all rates as one choice result.addChoice(std::move(choice)); } diff --git a/src/storm-dft/storage/dft/DFT.cpp b/src/storm-dft/storage/dft/DFT.cpp index 6a926e3a3..8ae059104 100644 --- a/src/storm-dft/storage/dft/DFT.cpp +++ b/src/storm-dft/storage/dft/DFT.cpp @@ -18,9 +18,10 @@ namespace storm { template DFT::DFT(DFTElementVector const& elements, DFTElementPointer const& tle) : mElements(elements), mNrOfBEs(0), mNrOfSpares(0), mTopLevelIndex(tle->id()), mMaxSpareChildCount(0) { + // Check that ids correspond to indices in the element vector STORM_LOG_ASSERT(elementIndicesCorrect(), "Ids incorrect."); size_t nrRepresentatives = 0; - + for (auto& elem : mElements) { if (isRepresentative(elem->id())) { ++nrRepresentatives; From d4f56ac724c42d82307953a193316aaca67689b9 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 11 Apr 2019 11:02:45 +0200 Subject: [PATCH 32/40] Added support for MUTEX (but without DC support) --- src/storm-dft/builder/DFTBuilder.cpp | 5 +- src/storm-dft/parser/DFTGalileoParser.cpp | 2 + src/storm-dft/parser/DFTJsonParser.cpp | 2 + src/storm-dft/storage/dft/DFTElements.h | 3 +- src/storm-dft/storage/dft/DftJsonExporter.cpp | 5 +- src/storm-dft/storage/dft/elements/DFTMutex.h | 61 +++++++++++++++++++ .../storage/dft/elements/DFTRestriction.h | 56 +---------------- src/storm-dft/storage/dft/elements/DFTSeq.h | 59 ++++++++++++++++++ 8 files changed, 134 insertions(+), 59 deletions(-) create mode 100644 src/storm-dft/storage/dft/elements/DFTMutex.h create mode 100644 src/storm-dft/storage/dft/elements/DFTSeq.h diff --git a/src/storm-dft/builder/DFTBuilder.cpp b/src/storm-dft/builder/DFTBuilder.cpp index 3c856407b..fce5d7962 100644 --- a/src/storm-dft/builder/DFTBuilder.cpp +++ b/src/storm-dft/builder/DFTBuilder.cpp @@ -137,7 +137,7 @@ namespace storm { template bool DFTBuilder::addRestriction(std::string const& name, std::vector const& children, storm::storage::DFTElementType tp) { if (children.size() <= 1) { - STORM_LOG_ERROR("Sequence enforcers require at least two children"); + STORM_LOG_ERROR("Restrictions require at least two children"); } if (nameInUse(name)) { STORM_LOG_ERROR("Element with name '" << name << "' already exists."); @@ -149,8 +149,7 @@ namespace storm { restr = std::make_shared>(mNextId++, name); break; case storm::storage::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."); + restr = std::make_shared>(mNextId++, name); break; default: STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type not known."); diff --git a/src/storm-dft/parser/DFTGalileoParser.cpp b/src/storm-dft/parser/DFTGalileoParser.cpp index bf1dced78..8d44637f9 100644 --- a/src/storm-dft/parser/DFTGalileoParser.cpp +++ b/src/storm-dft/parser/DFTGalileoParser.cpp @@ -137,6 +137,8 @@ namespace storm { success = builder.addSpareElement(name, childNames); } else if (type == "seq") { success = builder.addSequenceEnforcer(name, childNames); + } else if (type == "mutex") { + success = builder.addMutex(name, childNames); } else if (type == "fdep") { STORM_LOG_THROW(childNames.size() >= 2, storm::exceptions::WrongFormatException, "FDEP gate needs at least two children in line " << lineNo << "."); success = builder.addDepElement(name, childNames, storm::utility::one()); diff --git a/src/storm-dft/parser/DFTJsonParser.cpp b/src/storm-dft/parser/DFTJsonParser.cpp index 7975a0d5b..96eeeb762 100644 --- a/src/storm-dft/parser/DFTJsonParser.cpp +++ b/src/storm-dft/parser/DFTJsonParser.cpp @@ -88,6 +88,8 @@ namespace storm { success = builder.addSpareElement(name, childNames); } else if (type == "seq") { success = builder.addSequenceEnforcer(name, childNames); + } else if (type == "mutex") { + success = builder.addMutex(name, childNames); } else if (type == "fdep") { success = builder.addDepElement(name, childNames, storm::utility::one()); } else if (type == "pdep") { diff --git a/src/storm-dft/storage/dft/DFTElements.h b/src/storm-dft/storage/dft/DFTElements.h index 3173446fb..36d671703 100644 --- a/src/storm-dft/storage/dft/DFTElements.h +++ b/src/storm-dft/storage/dft/DFTElements.h @@ -4,9 +4,10 @@ #include "storm-dft/storage/dft/elements/BEConst.h" #include "storm-dft/storage/dft/elements/DFTAnd.h" #include "storm-dft/storage/dft/elements/DFTDependency.h" +#include "storm-dft/storage/dft/elements/DFTMutex.h" #include "storm-dft/storage/dft/elements/DFTOr.h" #include "storm-dft/storage/dft/elements/DFTPand.h" #include "storm-dft/storage/dft/elements/DFTPor.h" -#include "storm-dft/storage/dft/elements/DFTRestriction.h" +#include "storm-dft/storage/dft/elements/DFTSeq.h" #include "storm-dft/storage/dft/elements/DFTSpare.h" #include "storm-dft/storage/dft/elements/DFTVot.h" diff --git a/src/storm-dft/storage/dft/DftJsonExporter.cpp b/src/storm-dft/storage/dft/DftJsonExporter.cpp index 2eb811095..9ff66615e 100644 --- a/src/storm-dft/storage/dft/DftJsonExporter.cpp +++ b/src/storm-dft/storage/dft/DftJsonExporter.cpp @@ -61,10 +61,11 @@ namespace storm { nodeData["voting"] = std::static_pointer_cast const>(element)->threshold(); } } else if (element->isRestriction()) { + // TODO use same method for gates and restrictions // Set children for restriction - auto seq = std::static_pointer_cast const>(element); + auto restriction = std::static_pointer_cast const>(element); std::vector children; - for (DFTElementPointer const& child : seq->children()) { + for (DFTElementPointer const& child : restriction->children()) { children.push_back(std::to_string(child->id())); } nodeData["children"] = children; diff --git a/src/storm-dft/storage/dft/elements/DFTMutex.h b/src/storm-dft/storage/dft/elements/DFTMutex.h new file mode 100644 index 000000000..cbc18a69b --- /dev/null +++ b/src/storm-dft/storage/dft/elements/DFTMutex.h @@ -0,0 +1,61 @@ +#pragma once + +#include "DFTRestriction.h" + +namespace storm { + namespace storage { + + /*! + * Mutex restriction (MUTEX). + * Only one of the children can fail. + * A child which has failed prevents the failure of all other children. + */ + template + class DFTMutex : public DFTRestriction { + + public: + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param children Children. + */ + DFTMutex(size_t id, std::string const& name, std::vector>> const& children = {}) : DFTRestriction(id, name, children) { + // Intentionally left empty. + } + + DFTElementType type() const override { + return DFTElementType::MUTEX; + } + + bool isSeqEnforcer() const override { + return true; + } + + void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { + STORM_LOG_ASSERT(queues.failurePropagationDone(), "Failure propagation not finished."); + bool childFailed = false; + for (auto const& child : this->children()) { + if (state.hasFailed(child->id())) { + if (childFailed) { + // Two children have failed + this->fail(state, queues); + return; + } else { + childFailed = true; + } + } + } + } + + void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { + } + + bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { + // Actually, it doesnt matter what we return here.. + return false; + } + }; + + } +} diff --git a/src/storm-dft/storage/dft/elements/DFTRestriction.h b/src/storm-dft/storage/dft/elements/DFTRestriction.h index b83ba44f7..92c9a69ec 100644 --- a/src/storm-dft/storage/dft/elements/DFTRestriction.h +++ b/src/storm-dft/storage/dft/elements/DFTRestriction.h @@ -61,70 +61,20 @@ namespace storm { // Do nothing } - bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { + bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { return false; } protected: - void fail(DFTState & state, DFTStateSpaceGenerationQueues & queues) const override { + void fail(DFTState & state, DFTStateSpaceGenerationQueues& queues) const override { state.markAsInvalid(); } - void failsafe(DFTState & state, DFTStateSpaceGenerationQueues & queues) const override { + void failsafe(DFTState & state, DFTStateSpaceGenerationQueues& queues) const override { // Do nothing } }; - - /*! - * Sequence enforcer (SEQ). - * All children can only fail in order from first to last child. - * A child which has not failed yet prevents the failure of all children to the right of it. - */ - template - class DFTSeq : public DFTRestriction { - - public: - /*! - * Constructor. - * @param id Id. - * @param name Name. - * @param children Children. - */ - DFTSeq(size_t id, std::string const& name, std::vector>> const&children = {}) : DFTRestriction(id, name, children) { - // Intentionally left empty. - } - - DFTElementType type() const override { - return DFTElementType::SEQ; - } - - bool isSeqEnforcer() const override { - return true; - } - - void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { - STORM_LOG_ASSERT(queues.failurePropagationDone(), "Failure propagation not finished."); - bool childOperationalBefore = false; - for (auto const& child : this->children()) { - if (!state.hasFailed(child->id())) { - childOperationalBefore = true; - } else if (childOperationalBefore && state.hasFailed(child->id())) { - this->fail(state, queues); - return; - } - } - } - - void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { - } - - bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues & queues) const override { - // Actually, it doesnt matter what we return here.. - return false; - } - }; - } } diff --git a/src/storm-dft/storage/dft/elements/DFTSeq.h b/src/storm-dft/storage/dft/elements/DFTSeq.h new file mode 100644 index 000000000..8cef64e21 --- /dev/null +++ b/src/storm-dft/storage/dft/elements/DFTSeq.h @@ -0,0 +1,59 @@ +#pragma once + +#include "DFTRestriction.h" + +namespace storm { + namespace storage { + + /*! + * Sequence enforcer (SEQ). + * All children can only fail in order from first to last child. + * A child which has not failed yet prevents the failure of all children to the right of it. + */ + template + class DFTSeq : public DFTRestriction { + + public: + /*! + * Constructor. + * @param id Id. + * @param name Name. + * @param children Children. + */ + DFTSeq(size_t id, std::string const& name, std::vector>> const& children = {}) : DFTRestriction(id, name, children) { + // Intentionally left empty. + } + + DFTElementType type() const override { + return DFTElementType::SEQ; + } + + bool isSeqEnforcer() const override { + return true; + } + + void checkFails(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { + STORM_LOG_ASSERT(queues.failurePropagationDone(), "Failure propagation not finished."); + bool childOperationalBefore = false; + for (auto const& child : this->children()) { + if (!state.hasFailed(child->id())) { + childOperationalBefore = true; + } else if (childOperationalBefore && state.hasFailed(child->id())) { + // Child has failed before left sibling. + this->fail(state, queues); + return; + } + } + } + + void checkFailsafe(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { + } + + bool checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const override { + // Actually, it doesnt matter what we return here.. + return false; + } + }; + + } +} From 2ccd6d22dcf09ab54aed6c84cec8a37c80d182ff Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 11 Apr 2019 11:03:13 +0200 Subject: [PATCH 33/40] Added tests for mutex --- resources/examples/testfiles/dft/mutex.dft | 8 ++++++++ resources/examples/testfiles/dft/mutex2.dft | 7 +++++++ resources/examples/testfiles/dft/mutex3.dft | 6 ++++++ src/test/storm-dft/api/DftModelCheckerTest.cpp | 7 +++++++ 4 files changed, 28 insertions(+) create mode 100644 resources/examples/testfiles/dft/mutex.dft create mode 100644 resources/examples/testfiles/dft/mutex2.dft create mode 100644 resources/examples/testfiles/dft/mutex3.dft diff --git a/resources/examples/testfiles/dft/mutex.dft b/resources/examples/testfiles/dft/mutex.dft new file mode 100644 index 000000000..e3c081c4d --- /dev/null +++ b/resources/examples/testfiles/dft/mutex.dft @@ -0,0 +1,8 @@ +toplevel "T"; +"T" or "A" "B"; +"B" and "B1" "B2"; +"M" seq "C" "B"; +"A" lambda=2 dorm=1; +"B1" lambda=4 dorm=1; +"B2" lambda=5 dorm=1; +"C" lambda=0 dorm=1; diff --git a/resources/examples/testfiles/dft/mutex2.dft b/resources/examples/testfiles/dft/mutex2.dft new file mode 100644 index 000000000..951e2e039 --- /dev/null +++ b/resources/examples/testfiles/dft/mutex2.dft @@ -0,0 +1,7 @@ +toplevel "T"; +"T" or "B"; +"B" and "B1" "B2"; +"M" seq "C" "B"; +"B1" lambda=4 dorm=1; +"B2" lambda=5 dorm=1; +"C" lambda=0 dorm=1; diff --git a/resources/examples/testfiles/dft/mutex3.dft b/resources/examples/testfiles/dft/mutex3.dft new file mode 100644 index 000000000..686469755 --- /dev/null +++ b/resources/examples/testfiles/dft/mutex3.dft @@ -0,0 +1,6 @@ +toplevel "T"; +"T" and "A" "B" "C"; +"M" mutex "B" "C"; +"A" lambda=2 dorm=1; +"B" lambda=4 dorm=1; +"C" lambda=5 dorm=1; diff --git a/src/test/storm-dft/api/DftModelCheckerTest.cpp b/src/test/storm-dft/api/DftModelCheckerTest.cpp index 790c29509..baf30dc02 100644 --- a/src/test/storm-dft/api/DftModelCheckerTest.cpp +++ b/src/test/storm-dft/api/DftModelCheckerTest.cpp @@ -198,6 +198,13 @@ namespace { EXPECT_FLOAT_EQ(result, 6); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/seq5.dft"); EXPECT_EQ(result, storm::utility::infinity()); + + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/mutex.dft"); + EXPECT_FLOAT_EQ(result, 0.5); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/mutex2.dft"); + EXPECT_FLOAT_EQ(result, storm::utility::infinity()); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/mutex3.dft"); + EXPECT_FLOAT_EQ(result, storm::utility::infinity()); } } From cbbd812b42f4ab73e643c2a1b50c106b6a349aaf Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 11 Apr 2019 17:49:13 +0200 Subject: [PATCH 34/40] Proper handling of disabling/enabling events for SEQ and MUTEX --- .../generator/DftNextStateGenerator.cpp | 3 + src/storm-dft/storage/dft/DFT.cpp | 3 +- src/storm-dft/storage/dft/DFTState.cpp | 95 +++++++++++++++++-- src/storm-dft/storage/dft/DFTState.h | 14 +++ .../storage/dft/DFTStateGenerationInfo.h | 20 +++- .../storage/dft/elements/DFTChildren.h | 12 +++ .../storage/dft/elements/DFTDependency.h | 1 - .../storage/dft/elements/DFTElement.h | 23 +++++ src/storm-dft/storage/dft/elements/DFTMutex.h | 2 +- .../storage/dft/elements/DFTRestriction.h | 8 ++ 10 files changed, 168 insertions(+), 13 deletions(-) diff --git a/src/storm-dft/generator/DftNextStateGenerator.cpp b/src/storm-dft/generator/DftNextStateGenerator.cpp index 1e9a53045..253e0e0a2 100644 --- a/src/storm-dft/generator/DftNextStateGenerator.cpp +++ b/src/storm-dft/generator/DftNextStateGenerator.cpp @@ -105,6 +105,7 @@ namespace storm { DFTGatePointer next = queues.nextFailurePropagation(); next->checkFails(*newState, queues); newState->updateFailableDependencies(next->id()); + newState->updateFailableInRestrictions(next->id()); } // Check restrictions @@ -116,6 +117,7 @@ namespace storm { DFTRestrictionPointer next = queues.nextRestrictionCheck(); next->checkFails(*newState, queues); newState->updateFailableDependencies(next->id()); + newState->updateFailableInRestrictions(next->id()); } bool transient = false; @@ -153,6 +155,7 @@ namespace storm { // Update failable dependencies newState->updateFailableDependencies(nextBE->id()); newState->updateDontCareDependencies(nextBE->id()); + newState->updateFailableInRestrictions(nextBE->id()); // Add new state newStateId = stateToIdCallback(newState); diff --git a/src/storm-dft/storage/dft/DFT.cpp b/src/storm-dft/storage/dft/DFT.cpp index 8ae059104..1aa04eaa6 100644 --- a/src/storm-dft/storage/dft/DFT.cpp +++ b/src/storm-dft/storage/dft/DFT.cpp @@ -89,11 +89,12 @@ namespace storm { DFTStateGenerationInfo DFT::buildStateGenerationInfo(storm::storage::DFTIndependentSymmetries const& symmetries) const { DFTStateGenerationInfo generationInfo(nrElements(), mMaxSpareChildCount); - // Generate Pre and Post info for restrictions + // Generate Pre and Post info for restrictions, and mutexes for(auto const& elem : mElements) { if(!elem->isDependency() && !elem->isRestriction()) { generationInfo.setRestrictionPreElements(elem->id(), elem->seqRestrictionPres()); generationInfo.setRestrictionPostElements(elem->id(), elem->seqRestrictionPosts()); + generationInfo.setMutexElements(elem->id(), elem->mutexRestrictionElements()); } } diff --git a/src/storm-dft/storage/dft/DFTState.cpp b/src/storm-dft/storage/dft/DFTState.cpp index 804068576..778c571b8 100644 --- a/src/storm-dft/storage/dft/DFTState.cpp +++ b/src/storm-dft/storage/dft/DFTState.cpp @@ -1,6 +1,7 @@ #include "DFTState.h" #include "storm-dft/storage/dft/DFTElements.h" #include "storm-dft/storage/dft/DFT.h" +#include "storm/exceptions/InvalidArgumentException.h" namespace storm { namespace storage { @@ -22,7 +23,12 @@ namespace storm { // Initialize currently failable BEs for (size_t id : mDft.nonColdBEs()) { - failableElements.addBE(id); + // Check if restriction might prevent failure + if (!isEventDisabledViaRestriction(id)) { + failableElements.addBE(id); + } else { + STORM_LOG_TRACE("BE " << id << " is disabled due to a restriction."); + } } } @@ -40,7 +46,7 @@ namespace storm { STORM_LOG_ASSERT(mPseudoState, "Only pseudo states can be constructed."); for(size_t index = 0; index < mDft.nrElements(); ++index) { // Initialize currently failable BE - if (mDft.isBasicElement(index) && isOperational(index)) { + if (mDft.isBasicElement(index) && isOperational(index) && !isEventDisabledViaRestriction(index)) { std::shared_ptr> be = mDft.getBasicElement(index); if (be->canFail()) { switch (be->type()) { @@ -215,16 +221,69 @@ namespace storm { bool addedFailableDependency = false; for (auto dependency : mDft.getElement(id)->outgoingDependencies()) { STORM_LOG_ASSERT(dependency->triggerEvent()->id() == id, "Ids do not match."); - assert(dependency->dependentEvents().size() == 1); + STORM_LOG_ASSERT(dependency->dependentEvents().size() == 1, "Only one dependent event is allowed."); if (getElementState(dependency->dependentEvents()[0]->id()) == DFTElementState::Operational) { STORM_LOG_ASSERT(!isFailsafe(dependency->dependentEvents()[0]->id()), "Dependent event is failsafe."); - failableElements.addDependency(dependency->id()); - STORM_LOG_TRACE("New dependency failure: " << *dependency); - addedFailableDependency = true; + // By assertion we have only one dependent event + // Check if restriction prevents failure of dependent event + if (!isEventDisabledViaRestriction(dependency->dependentEvents()[0]->id())) { + // Add dependency as possible failure + failableElements.addDependency(dependency->id()); + STORM_LOG_TRACE("New dependency failure: " << *dependency); + addedFailableDependency = true; + } } } return addedFailableDependency; } + + template + bool DFTState::updateFailableInRestrictions(size_t id) { + if (!hasFailed(id)) { + // Non-failure does not change anything in a restriction + return false; + } + + bool addedFailableEvent = false; + for (auto restriction : mDft.getElement(id)->restrictions()) { + STORM_LOG_ASSERT(restriction->containsChild(id), "Ids do not match."); + if (restriction->isSeqEnforcer()) { + for (auto it = restriction->children().cbegin(); it != restriction->children().cend(); ++it) { + if ((*it)->isBasicElement()) { + if ((*it)->id() != id) { + if (!hasFailed((*it)->id())) { + // Failure should be prevented later on + STORM_LOG_TRACE("Child " << (*it)->id() << " should have failed."); + } + } else { + // Current event has failed + ++it; + if (it != restriction->children().cend()) { + // Enable next event + failableElements.addBE((*it)->id()); + STORM_LOG_TRACE("Added possible BE failure: " << *(*it)); + addedFailableEvent = true; + } + break; + } + } + } + } else if (restriction->isMutex()) { + // Current element has failed and disables all other children + for (auto const& child : restriction->children()) { + if (child->isBasicElement() && child->id() != id && getElementState(child->id()) == DFTElementState::Operational) { + // Disable child + failableElements.removeBE(child->id()); + STORM_LOG_TRACE("Disabled child: " << *child); + addedFailableEvent = true; + } + } + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Restriction must be SEQ or MUTEX"); + } + } + return addedFailableEvent; + } template void DFTState::updateDontCareDependencies(size_t id) { @@ -304,7 +363,7 @@ namespace storm { activate(representativeId); } for(size_t elem : mDft.module(representativeId)) { - if(mDft.isBasicElement(elem) && isOperational(elem)) { + if(mDft.isBasicElement(elem) && isOperational(elem) && !isEventDisabledViaRestriction(elem)) { std::shared_ptr> be = mDft.getBasicElement(elem); if (be->canFail()) { switch (be->type()) { @@ -361,6 +420,28 @@ namespace storm { STORM_LOG_ASSERT(hasFailed(spareId), "Spare has not failed."); mStatus.setFromInt(mStateGenerationInfo.getSpareUsageIndex(spareId), mStateGenerationInfo.usageInfoBits(), mDft.getMaxSpareChildCount()); } + + template + bool DFTState::isEventDisabledViaRestriction(size_t id) const { + STORM_LOG_ASSERT(!mDft.isDependency(id), "Event " << id << " is dependency."); + STORM_LOG_ASSERT(!mDft.isRestriction(id), "Event " << id << " is restriction."); + // First check sequence enforcer + auto const& preIds = mStateGenerationInfo.seqRestrictionPreElements(id); + for (size_t id : preIds) { + if (isOperational(id)) { + return true; + } + } + + // Second check mutexes + auto const& mutexIds = mStateGenerationInfo.mutexRestrictionElements(id); + for (size_t id : mutexIds) { + if (!isOperational(id)) { + return true; + } + } + return false; + } template bool DFTState::hasOperationalPostSeqElements(size_t id) const { diff --git a/src/storm-dft/storage/dft/DFTState.h b/src/storm-dft/storage/dft/DFTState.h index e569e8d49..97048fd2d 100644 --- a/src/storm-dft/storage/dft/DFTState.h +++ b/src/storm-dft/storage/dft/DFTState.h @@ -289,6 +289,13 @@ namespace storm { * @return true if failable dependent events exist */ bool updateFailableDependencies(size_t id); + + /** + * Sets all failable BEs due to restrictions from newly failed element. + * @param id Id of the newly failed element + * @return true if newly failable events exist + */ + bool updateFailableInRestrictions(size_t id); /** * Sets all dependencies dont care whose dependent event is the newly failed BE. @@ -315,6 +322,13 @@ namespace storm { * @return True, if elements were swapped, false if nothing changed. */ bool orderBySymmetry(); + + /*! + * Check whether the event cannot fail at the moment due to a restriction. + * @param id Event id. + * @return True iff a restriction prevents the failure of the event. + */ + bool isEventDisabledViaRestriction(size_t id) const; /** * Checks whether operational post seq elements are present diff --git a/src/storm-dft/storage/dft/DFTStateGenerationInfo.h b/src/storm-dft/storage/dft/DFTStateGenerationInfo.h index bc7e56140..ec2ed993a 100644 --- a/src/storm-dft/storage/dft/DFTStateGenerationInfo.h +++ b/src/storm-dft/storage/dft/DFTStateGenerationInfo.h @@ -8,8 +8,9 @@ namespace storm { std::map mSpareUsageIndex; // id spare -> index first bit in state std::map mSpareActivationIndex; // id spare representative -> index in state std::vector mIdToStateIndex; // id -> index first bit in state - std::map> mSeqRestrictionPreElements; // id -> list of restriction pre elements; - std::map> mSeqRestrictionPostElements; // id -> list of restriction post elements; + std::map> mSeqRestrictionPreElements; // id -> list of restriction pre elements + std::map> mSeqRestrictionPostElements; // id -> list of restriction post elements + std::map> mMutexRestrictionElements; // id -> list of elments in the same mutexes std::vector>> mSymmetries; // pair (length of symmetry group, vector indicating the starting points of the symmetry groups) public: @@ -37,12 +38,25 @@ namespace storm { void setRestrictionPostElements(size_t id, std::vector const& elems) { mSeqRestrictionPostElements[id] = elems; } + + void setMutexElements(size_t id, std::vector const& elems) { + mMutexRestrictionElements[id] = elems; + } + + std::vector const& seqRestrictionPreElements(size_t index) const { + STORM_LOG_ASSERT(mSeqRestrictionPreElements.count(index) > 0, "Index invalid."); + return mSeqRestrictionPreElements.at(index); + } std::vector const& seqRestrictionPostElements(size_t index) const { STORM_LOG_ASSERT(mSeqRestrictionPostElements.count(index) > 0, "Index invalid."); return mSeqRestrictionPostElements.at(index); } - + + std::vector const& mutexRestrictionElements(size_t index) const { + STORM_LOG_ASSERT(mMutexRestrictionElements.count(index) > 0, "Index invalid."); + return mMutexRestrictionElements.at(index); + } void addSpareActivationIndex(size_t id, size_t index) { mSpareActivationIndex[id] = index; diff --git a/src/storm-dft/storage/dft/elements/DFTChildren.h b/src/storm-dft/storage/dft/elements/DFTChildren.h index a9d0c7290..8aeb1381f 100644 --- a/src/storm-dft/storage/dft/elements/DFTChildren.h +++ b/src/storm-dft/storage/dft/elements/DFTChildren.h @@ -52,6 +52,18 @@ namespace storm { return mChildren.size(); } + /*! + * Check whether the given element is contained in the list of children. + * @param id Id of element to search for. + * @return True iff element was found in list of children. + */ + bool containsChild(size_t id) { + auto it = std::find_if(this->mChildren.begin(), this->mChildren.end(), [&id](DFTElementPointer element) -> bool { + return element->id() == id; + }); + return it != this->mChildren.end(); + } + virtual std::vector independentUnit() const override { std::set unit = {this->mId}; for (auto const& child : mChildren) { diff --git a/src/storm-dft/storage/dft/elements/DFTDependency.h b/src/storm-dft/storage/dft/elements/DFTDependency.h index a7cca4f36..955d3b9be 100644 --- a/src/storm-dft/storage/dft/elements/DFTDependency.h +++ b/src/storm-dft/storage/dft/elements/DFTDependency.h @@ -113,7 +113,6 @@ namespace storm { return it != this->mDependentEvents.end(); } - virtual size_t nrChildren() const override { return 1; } diff --git a/src/storm-dft/storage/dft/elements/DFTElement.h b/src/storm-dft/storage/dft/elements/DFTElement.h index b287ae863..80fff512c 100644 --- a/src/storm-dft/storage/dft/elements/DFTElement.h +++ b/src/storm-dft/storage/dft/elements/DFTElement.h @@ -338,6 +338,29 @@ namespace storm { return res; } + /** + * Obtains ids of elements which are under the same mutex. + * @return A vector of ids + */ + std::vector mutexRestrictionElements() const { + std::vector res; + for (auto const& restr : mRestrictions) { + if (!restr->isMutex()) { + continue; + } + bool found = false; + for (auto it = restr->children().cbegin(); it != restr->children().cend(); ++it) { + if ((*it)->id() != mId) { + res.push_back((*it)->id()); + } else { + found = true; + } + } + STORM_LOG_ASSERT(found, "Child " << mId << " is not included in restriction " << *restr); + } + return res; + } + virtual void extendSpareModule(std::set& elementsInModule) const; // virtual void extendImmediateFailureCausePathEvents(std::set& ) const; diff --git a/src/storm-dft/storage/dft/elements/DFTMutex.h b/src/storm-dft/storage/dft/elements/DFTMutex.h index cbc18a69b..ff50d0f9f 100644 --- a/src/storm-dft/storage/dft/elements/DFTMutex.h +++ b/src/storm-dft/storage/dft/elements/DFTMutex.h @@ -28,7 +28,7 @@ namespace storm { return DFTElementType::MUTEX; } - bool isSeqEnforcer() const override { + bool isMutex() const override { return true; } diff --git a/src/storm-dft/storage/dft/elements/DFTRestriction.h b/src/storm-dft/storage/dft/elements/DFTRestriction.h index 92c9a69ec..54421d556 100644 --- a/src/storm-dft/storage/dft/elements/DFTRestriction.h +++ b/src/storm-dft/storage/dft/elements/DFTRestriction.h @@ -44,6 +44,14 @@ namespace storm { return false; } + /*! + * Return whether the restriction is a mutex. + * @return True iff the restriction is a MUTEX. + */ + virtual bool isMutex() const { + return false; + } + /*! * Returns whether all children are BEs. * @return True iff all children are BEs. From b4f34b13bf67fd082aa50b5e41200d0fe0df8d28 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 17 Apr 2019 14:56:19 +0200 Subject: [PATCH 35/40] Ignore relevant events for Don't care propagation --- .../builder/ExplicitDFTModelBuilder.cpp | 8 ++++++- .../generator/DftNextStateGenerator.cpp | 14 ++++++------ .../generator/DftNextStateGenerator.h | 5 +---- src/storm-dft/storage/dft/DFT.cpp | 11 ++++++++++ src/storm-dft/storage/dft/DFT.h | 6 +++++ .../storage/dft/elements/DFTElement.cpp | 5 +++++ .../storage/dft/elements/DFTElement.h | 22 +++++++++++++++++-- 7 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index 7b364204e..da2100537 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -58,11 +58,17 @@ namespace storm { dft(dft), stateGenerationInfo(std::make_shared(dft.buildStateGenerationInfo(symmetries))), relevantEvents(relevantEvents), - generator(dft, *stateGenerationInfo, relevantEvents, mergeFailedStates), + generator(dft, *stateGenerationInfo, mergeFailedStates), matrixBuilder(!generator.isDeterministicModel()), stateStorage(dft.stateBitVectorSize()), explorationQueue(1, 0, 0.9, false) { + // Set relevant events + this->dft.setRelevantEvents(this->relevantEvents); + // Mark top level element as relevant + this->dft.getElement(this->dft.getTopLevelIndex())->setRelevance(true); + + // Compute independent subtrees if (dft.topLevelType() == storm::storage::DFTElementType::OR) { // We only support this for approximation with top level element OR diff --git a/src/storm-dft/generator/DftNextStateGenerator.cpp b/src/storm-dft/generator/DftNextStateGenerator.cpp index 253e0e0a2..eb1795448 100644 --- a/src/storm-dft/generator/DftNextStateGenerator.cpp +++ b/src/storm-dft/generator/DftNextStateGenerator.cpp @@ -8,17 +8,17 @@ namespace storm { namespace generator { - + template - DftNextStateGenerator::DftNextStateGenerator(storm::storage::DFT const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, std::set const& relevantEvents, bool mergeFailedStates) : mDft(dft), mStateGenerationInfo(stateGenerationInfo), state(nullptr), relevantEvents(relevantEvents), mergeFailedStates(mergeFailedStates) { + DftNextStateGenerator::DftNextStateGenerator(storm::storage::DFT const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, bool mergeFailedStates) : mDft(dft), mStateGenerationInfo(stateGenerationInfo), state(nullptr), mergeFailedStates(mergeFailedStates) { deterministicModel = !mDft.canHaveNondeterminism(); } - + template bool DftNextStateGenerator::isDeterministicModel() const { return deterministicModel; } - + template std::vector DftNextStateGenerator::getInitialStates(StateToIdCallback const& stateToIdCallback) { DFTStatePointer initialState = std::make_shared>(mDft, mStateGenerationInfo, 0); @@ -42,7 +42,7 @@ namespace storm { // Store a pointer to the state itself, because we need to be able to access it when expanding it. this->state = state; } - + template StateBehavior DftNextStateGenerator::expand(StateToIdCallback const& stateToIdCallback) { STORM_LOG_DEBUG("Explore state: " << mDft.getStateString(state)); @@ -146,8 +146,8 @@ namespace storm { } // Propagate dont cares - // TODO: do not set DC for relevant events - while (relevantEvents.empty() && !queues.dontCarePropagationDone()) { + // Relevance is considered for each element independently + while (!queues.dontCarePropagationDone()) { DFTElementPointer next = queues.nextDontCarePropagation(); next->checkDontCareAnymore(*newState, queues); } diff --git a/src/storm-dft/generator/DftNextStateGenerator.h b/src/storm-dft/generator/DftNextStateGenerator.h index 0574d0266..b77751521 100644 --- a/src/storm-dft/generator/DftNextStateGenerator.h +++ b/src/storm-dft/generator/DftNextStateGenerator.h @@ -24,7 +24,7 @@ namespace storm { public: typedef std::function StateToIdCallback; - DftNextStateGenerator(storm::storage::DFT const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, std::set const& relevantEvents, bool mergeFailedStates); + DftNextStateGenerator(storm::storage::DFT const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, bool mergeFailedStates); bool isDeterministicModel() const; std::vector getInitialStates(StateToIdCallback const& stateToIdCallback); @@ -55,9 +55,6 @@ namespace storm { // Current state DFTStatePointer state; - // List with ids of relevant events which should be observed. - std::set const& relevantEvents; - // Flag indication if all failed states should be merged into one. bool mergeFailedStates = true; diff --git a/src/storm-dft/storage/dft/DFT.cpp b/src/storm-dft/storage/dft/DFT.cpp index 1aa04eaa6..4a3a5eb30 100644 --- a/src/storm-dft/storage/dft/DFT.cpp +++ b/src/storm-dft/storage/dft/DFT.cpp @@ -863,6 +863,17 @@ namespace storm { return (*iter)->id(); } + template + void DFT::setRelevantEvents(std::set const& relevantEvents) const { + for (auto const& elem : mElements) { + if (relevantEvents.find(elem->id()) != relevantEvents.end()) { + elem->setRelevance(true); + } else { + elem->setRelevance(false); + } + } + } + template void DFT::writeStatsToStream(std::ostream& stream) const { // Count individual types of elements diff --git a/src/storm-dft/storage/dft/DFT.h b/src/storm-dft/storage/dft/DFT.h index dfb7c583d..2b8795a82 100644 --- a/src/storm-dft/storage/dft/DFT.h +++ b/src/storm-dft/storage/dft/DFT.h @@ -318,6 +318,12 @@ namespace storm { */ size_t getIndex(std::string const& name) const; + /*! + * Set the relevance flag for all elements according to the given relevant events. + * @param relevantEvents All elements which should be to relevant. All elements not occuring are set to irrelevant. + */ + void setRelevantEvents(std::set const& relevantEvents) const; + private: std::tuple, std::vector, std::vector> getSortedParentAndDependencyIds(size_t index) const; diff --git a/src/storm-dft/storage/dft/elements/DFTElement.cpp b/src/storm-dft/storage/dft/elements/DFTElement.cpp index 5f04b9d65..d9bba261a 100644 --- a/src/storm-dft/storage/dft/elements/DFTElement.cpp +++ b/src/storm-dft/storage/dft/elements/DFTElement.cpp @@ -9,6 +9,11 @@ namespace storm { template bool DFTElement::checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const { + if (this->isRelevant()) { + // Relevant events are ignored for Don't Care propagation + return false; + } + if (state.dontCare(mId)) { return false; } diff --git a/src/storm-dft/storage/dft/elements/DFTElement.h b/src/storm-dft/storage/dft/elements/DFTElement.h index 80fff512c..f89f69c7a 100644 --- a/src/storm-dft/storage/dft/elements/DFTElement.h +++ b/src/storm-dft/storage/dft/elements/DFTElement.h @@ -51,7 +51,7 @@ namespace storm { * @param id Id. * @param name Name. */ - DFTElement(size_t id, std::string const& name) : mId(id), mName(name) { + DFTElement(size_t id, std::string const& name) : mId(id), mName(name), mRank(-1), mRelevant(false) { // Intentionally left empty. } @@ -117,6 +117,23 @@ namespace storm { this->mRank = rank; } + /*! + * Get whether the element is relevant. + * Relevant elements are for example not set to Don't Care and their status is stored as a label in the generated Markov Chain. + * @return True iff the element is relevant. + */ + virtual bool isRelevant() const { + return mRelevant; + } + + /*! + * Set the relevancy of the element. + * @param relevant If true, the element is relevant. + */ + virtual void setRelevance(bool relevant) const { + this->mRelevant = relevant; + } + /*! * Checks whether the element is a basic element. * @return True iff element is a BE. @@ -416,10 +433,11 @@ namespace storm { protected: std::size_t mId; std::string mName; - std::size_t mRank = -1; + std::size_t mRank; DFTGateVector mParents; DFTDependencyVector mOutgoingDependencies; DFTRestrictionVector mRestrictions; + mutable bool mRelevant; // Must be mutable to allow changes later on. TODO: avoid mutable }; From 58a4491f72ab801d1bd9f87daa988197485132af Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 17 Apr 2019 15:01:50 +0200 Subject: [PATCH 36/40] Test cases for DFT model building with relevant events --- .../examples/testfiles/dft/dont_care.dft | 17 +++++ .../storm-dft/api/DftModelBuildingTest.cpp | 64 +++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 resources/examples/testfiles/dft/dont_care.dft create mode 100644 src/test/storm-dft/api/DftModelBuildingTest.cpp diff --git a/resources/examples/testfiles/dft/dont_care.dft b/resources/examples/testfiles/dft/dont_care.dft new file mode 100644 index 000000000..1ddf82757 --- /dev/null +++ b/resources/examples/testfiles/dft/dont_care.dft @@ -0,0 +1,17 @@ +toplevel "T"; +"T" and "A" "B" "C"; +"A" or "D" "E"; +"B" or "F" "G"; +"C" or "H" "I"; +"D" or "K" "M"; +"F" or "N" "O"; +"H" or "P" "Q"; +"E" lambda=9 dorm=1; +"G" lambda=1 dorm=1; +"I" lambda=7 dorm=1; +"K" lambda=4 dorm=1; +"M" lambda=5 dorm=1; +"N" lambda=3 dorm=1; +"O" lambda=8 dorm=1; +"P" lambda=6 dorm=1; +"Q" lambda=2 dorm=1; diff --git a/src/test/storm-dft/api/DftModelBuildingTest.cpp b/src/test/storm-dft/api/DftModelBuildingTest.cpp new file mode 100644 index 000000000..cbaa53e82 --- /dev/null +++ b/src/test/storm-dft/api/DftModelBuildingTest.cpp @@ -0,0 +1,64 @@ +#include "gtest/gtest.h" +#include "storm-config.h" + +#include "storm-dft/api/storm-dft.h" +#include "storm-dft/builder/ExplicitDFTModelBuilder.h" +#include "storm-parsers/api/storm-parsers.h" + +namespace { + + TEST(DftModelBuildingTest, RelevantEvents) { + // Initialize + std::string file = STORM_TEST_RESOURCES_DIR "/dft/dont_care.dft"; + std::shared_ptr> dft = storm::api::loadDFTGalileoFile(file); + EXPECT_TRUE(storm::api::isWellFormed(*dft)); + std::string property = "Tmin=? [F \"failed\"]"; + std::vector> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(property)); + std::map>> emptySymmetry; + storm::storage::DFTIndependentSymmetries symmetries(emptySymmetry); + typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties, false); + + + // Set relevant events (none) + std::set relevantEvents; + // Build model + storm::builder::ExplicitDFTModelBuilder builder(*dft, symmetries, relevantEvents); + builder.buildModel(labeloptions, 0, 0.0); + std::shared_ptr> model = builder.getModel(); + EXPECT_EQ(8ul, model->getNumberOfStates()); + EXPECT_EQ(13ul, model->getNumberOfTransitions()); + + // Set relevant events (all) + relevantEvents = dft->getAllIds(); + // Build model + storm::builder::ExplicitDFTModelBuilder builder2(*dft, symmetries, relevantEvents); + builder2.buildModel(labeloptions, 0, 0.0); + model = builder2.getModel(); + EXPECT_EQ(170ul, model->getNumberOfStates()); + EXPECT_EQ(688ul, model->getNumberOfTransitions()); + + + // Set relevant events (H) + relevantEvents.clear(); + relevantEvents.insert(dft->getIndex("H")); + // Build model + storm::builder::ExplicitDFTModelBuilder builder3(*dft, symmetries, relevantEvents); + builder3.buildModel(labeloptions, 0, 0.0); + model = builder3.getModel(); + EXPECT_EQ(11ul, model->getNumberOfStates()); + EXPECT_EQ(23ul, model->getNumberOfTransitions()); + + + // Set relevant events (H, I) + relevantEvents.clear(); + relevantEvents.insert(dft->getIndex("H")); + relevantEvents.insert(dft->getIndex("I")); + // Build model + storm::builder::ExplicitDFTModelBuilder builder4(*dft, symmetries, relevantEvents); + builder4.buildModel(labeloptions, 0, 0.0); + model = builder4.getModel(); + EXPECT_EQ(14ul, model->getNumberOfStates()); + EXPECT_EQ(30ul, model->getNumberOfTransitions()); + } + +} From d140da92cce10619e6bd6c501f630782af9fc032 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 17 Apr 2019 17:29:33 +0200 Subject: [PATCH 37/40] Small refactoring for ElementState --- src/storm-dft/storage/dft/DFT.cpp | 6 ++---- src/storm-dft/storage/dft/DFTState.cpp | 14 ++++++++++++-- src/storm-dft/storage/dft/DFTState.h | 12 ++++++++---- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/storm-dft/storage/dft/DFT.cpp b/src/storm-dft/storage/dft/DFT.cpp index 4a3a5eb30..7538c4abc 100644 --- a/src/storm-dft/storage/dft/DFT.cpp +++ b/src/storm-dft/storage/dft/DFT.cpp @@ -540,12 +540,10 @@ namespace storm { std::stringstream stream; stream << "(" << id << ") "; for (auto const& elem : mElements) { - size_t elemIndex = stateGenerationInfo.getStateIndex(elem->id()); - int elementState = DFTState::getElementStateInt(status, elemIndex); if (elem->isDependency()) { - stream << storm::storage::toChar(static_cast(elementState)) << "[dep]"; + stream << storm::storage::toChar(DFTState::getDependencyState(status, stateGenerationInfo, elem->id())) << "[dep]"; } else { - stream << storm::storage::toChar(static_cast(elementState)); + stream << storm::storage::toChar(DFTState::getElementState(status, stateGenerationInfo, elem->id())); if(elem->isSpareGate()) { stream << "["; size_t nrUsedChild = status.getAsInt(stateGenerationInfo.getSpareUsageIndex(elem->id()), stateGenerationInfo.usageInfoBits()); diff --git a/src/storm-dft/storage/dft/DFTState.cpp b/src/storm-dft/storage/dft/DFTState.cpp index 778c571b8..689787b70 100644 --- a/src/storm-dft/storage/dft/DFTState.cpp +++ b/src/storm-dft/storage/dft/DFTState.cpp @@ -98,20 +98,30 @@ namespace storm { DFTElementState DFTState::getElementState(size_t id) const { return static_cast(getElementStateInt(id)); } + + template + DFTElementState DFTState::getElementState(storm::storage::BitVector const& state, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) { + return static_cast(DFTState::getElementStateInt(state, stateGenerationInfo, id)); + } template DFTDependencyState DFTState::getDependencyState(size_t id) const { return static_cast(getElementStateInt(id)); } + template + DFTDependencyState DFTState::getDependencyState(storm::storage::BitVector const& state, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) { + return static_cast(DFTState::getElementStateInt(state, stateGenerationInfo, id)); + } + template int DFTState::getElementStateInt(size_t id) const { return mStatus.getAsInt(mStateGenerationInfo.getStateIndex(id), 2); } template - int DFTState::getElementStateInt(storm::storage::BitVector const& state, size_t indexId) { - return state.getAsInt(indexId, 2); + int DFTState::getElementStateInt(storm::storage::BitVector const& state, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) { + return state.getAsInt(stateGenerationInfo.getStateIndex(id), 2); } template diff --git a/src/storm-dft/storage/dft/DFTState.h b/src/storm-dft/storage/dft/DFTState.h index 97048fd2d..3718e7627 100644 --- a/src/storm-dft/storage/dft/DFTState.h +++ b/src/storm-dft/storage/dft/DFTState.h @@ -152,13 +152,13 @@ namespace storm { std::shared_ptr> copy() const; DFTElementState getElementState(size_t id) const; - + + static DFTElementState getElementState(storm::storage::BitVector const& state, DFTStateGenerationInfo const& stateGenerationInfo, size_t id); + DFTDependencyState getDependencyState(size_t id) const; - int getElementStateInt(size_t id) const; + static DFTDependencyState getDependencyState(storm::storage::BitVector const& state, DFTStateGenerationInfo const& stateGenerationInfo, size_t id); - static int getElementStateInt(storm::storage::BitVector const& state, size_t indexId); - size_t getId() const; void setId(size_t id); @@ -372,6 +372,10 @@ namespace storm { private: void propagateActivation(size_t representativeId); + int getElementStateInt(size_t id) const; + + static int getElementStateInt(storm::storage::BitVector const& state, DFTStateGenerationInfo const& stateGenerationInfo, size_t id); + }; } From 4b1af3c51e17e9f0ee8c86f97c7e44e36831b56a Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 17 Apr 2019 18:28:23 +0200 Subject: [PATCH 38/40] Set labels in property as relevant events as well --- src/storm-dft-cli/storm-dft.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index 19dec5f9d..1c036a33d 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -127,8 +127,26 @@ void processOptions() { props = storm::api::extractFormulasFromProperties(storm::api::parseProperties(propString)); } + // Get necessary labels from properties + std::vector> atomicLabels; + for (auto property : props) { + property->gatherAtomicLabelFormulas(atomicLabels); + } + + // Set relevant event names + std::vector relevantEventNames = faultTreeSettings.getRelevantEvents(); + // Events from properties are relevant as well + for (auto atomic : atomicLabels) { + std::string label = atomic->getLabel(); + std::size_t foundIndex = label.find("_fail"); + if (foundIndex != std::string::npos) { + relevantEventNames.push_back(label.substr(0, foundIndex)); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Label '" << label << "' not known."); + } + } + // Set relevant elements - // TODO: also incorporate events from properties std::set relevantEvents; // Per default only the toplevel event is relevant // Possible clash of relevantEvents and disableDC was already considered in FaultTreeSettings::check(). if (faultTreeSettings.areRelevantEventsSet()) { From 5952aa8a6fd1d5023c4975e3d8a8f2541e39e736 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 17 Apr 2019 19:11:34 +0200 Subject: [PATCH 39/40] Set labels, dont care propagation and unique failed state according to relevant events --- src/storm-dft-cli/storm-dft.cpp | 16 ++- src/storm-dft/api/storm-dft.h | 8 +- .../builder/ExplicitDFTModelBuilder.cpp | 109 +++++++++--------- .../builder/ExplicitDFTModelBuilder.h | 36 ++---- .../generator/DftNextStateGenerator.cpp | 17 +-- .../generator/DftNextStateGenerator.h | 9 +- .../modelchecker/dft/DFTModelChecker.cpp | 34 +++--- .../modelchecker/dft/DFTModelChecker.h | 20 +++- .../settings/modules/FaultTreeSettings.cpp | 10 +- .../settings/modules/FaultTreeSettings.h | 8 ++ src/storm-dft/storage/dft/DFT.cpp | 4 +- src/storm-dft/storage/dft/DFT.h | 3 +- .../storage/dft/elements/DFTElement.cpp | 3 +- .../storage/dft/elements/DFTElement.h | 11 +- .../storm-dft/api/DftApproximationTest.cpp | 6 +- .../storm-dft/api/DftModelBuildingTest.cpp | 18 ++- .../storm-dft/api/DftModelCheckerTest.cpp | 2 +- 17 files changed, 162 insertions(+), 152 deletions(-) diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index 1c036a33d..0db58195b 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -138,11 +138,15 @@ void processOptions() { // Events from properties are relevant as well for (auto atomic : atomicLabels) { std::string label = atomic->getLabel(); - std::size_t foundIndex = label.find("_fail"); - if (foundIndex != std::string::npos) { - relevantEventNames.push_back(label.substr(0, foundIndex)); + if (label == "failed") { + // Ignore as this label will always be added } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Label '" << label << "' not known."); + std::size_t foundIndex = label.find("_fail"); + if (foundIndex != std::string::npos) { + relevantEventNames.push_back(label.substr(0, foundIndex)); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Label '" << label << "' not known."); + } } } @@ -178,8 +182,8 @@ void processOptions() { if (faultTreeSettings.isApproximationErrorSet()) { approximationError = faultTreeSettings.getApproximationError(); } - storm::api::analyzeDFT(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), relevantEvents, approximationError, - faultTreeSettings.getApproximationHeuristic(), true); + storm::api::analyzeDFT(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), relevantEvents, + faultTreeSettings.isAllowDCForRelevantEvents(), approximationError, faultTreeSettings.getApproximationHeuristic(), true); } } diff --git a/src/storm-dft/api/storm-dft.h b/src/storm-dft/api/storm-dft.h index f801b0eda..754bdfc91 100644 --- a/src/storm-dft/api/storm-dft.h +++ b/src/storm-dft/api/storm-dft.h @@ -70,6 +70,7 @@ namespace storm { * @param symred Flag whether symmetry reduction should be used. * @param allowModularisation Flag whether modularisation should be applied if possible. * @param relevantEvents List of relevant events which should be observed. + * @param allowDCForRelevantEvents If true, Don't Care propagation is allowed even for relevant events. * @param approximationError Allowed approximation error. Value 0 indicates no approximation. * @param approximationHeuristic Heuristic used for state space exploration. * @param printOutput If true, model information, timings, results, etc. are printed. @@ -78,11 +79,12 @@ namespace storm { template typename storm::modelchecker::DFTModelChecker::dft_results analyzeDFT(storm::storage::DFT const& dft, std::vector> const& properties, bool symred = true, - bool allowModularisation = true, std::set const& relevantEvents = {}, double approximationError = 0.0, - storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH, bool printOutput = false) { + bool allowModularisation = true, std::set const& relevantEvents = {}, bool allowDCForRelevantEvents = true, double approximationError = 0.0, + storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH, bool printOutput = false) { storm::modelchecker::DFTModelChecker modelChecker(printOutput); typename storm::modelchecker::DFTModelChecker::dft_results results = modelChecker.check(dft, properties, symred, allowModularisation, relevantEvents, - approximationError, approximationHeuristic); + allowDCForRelevantEvents, approximationError, + approximationHeuristic); if (printOutput) { modelChecker.printTimings(); modelChecker.printResults(results); diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index da2100537..9fc882e27 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -31,43 +31,24 @@ namespace storm { } template - ExplicitDFTModelBuilder::LabelOptions::LabelOptions(std::vector> properties, bool buildAllLabels) : buildFailLabel(true), buildFailSafeLabel(false), buildAllLabels(buildAllLabels) { - // Get necessary labels from properties - std::vector> atomicLabels; - for (auto property : properties) { - property->gatherAtomicLabelFormulas(atomicLabels); - } - // Set usage of necessary labels - for (auto atomic : atomicLabels) { - std::string label = atomic->getLabel(); - std::size_t foundIndex = label.find("_fail"); - if (foundIndex != std::string::npos) { - elementLabels.insert(label.substr(0, foundIndex)); - } else if (label.compare("failed") == 0) { - buildFailLabel = true; - } else if (label.compare("failsafe") == 0) { - buildFailSafeLabel = true; - } else { - STORM_LOG_WARN("Label '" << label << "' not known."); - } - } - } - - template - ExplicitDFTModelBuilder::ExplicitDFTModelBuilder(storm::storage::DFT const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, std::set const& relevantEvents) : + ExplicitDFTModelBuilder::ExplicitDFTModelBuilder(storm::storage::DFT const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, std::set const& relevantEvents, bool allowDCForRelevantEvents) : dft(dft), stateGenerationInfo(std::make_shared(dft.buildStateGenerationInfo(symmetries))), relevantEvents(relevantEvents), - generator(dft, *stateGenerationInfo, mergeFailedStates), + generator(dft, *stateGenerationInfo), matrixBuilder(!generator.isDeterministicModel()), stateStorage(dft.stateBitVectorSize()), explorationQueue(1, 0, 0.9, false) { // Set relevant events - this->dft.setRelevantEvents(this->relevantEvents); + this->dft.setRelevantEvents(this->relevantEvents, allowDCForRelevantEvents); // Mark top level element as relevant this->dft.getElement(this->dft.getTopLevelIndex())->setRelevance(true); - + if (this->relevantEvents.empty()) { + // Only interested in top level event -> introduce unique failed state + this->uniqueFailedState = true; + STORM_LOG_DEBUG("Using unique failed state with id 0."); + } // Compute independent subtrees if (dft.topLevelType() == storm::storage::DFTElementType::OR) { @@ -126,10 +107,17 @@ namespace storm { } template - void ExplicitDFTModelBuilder::buildModel(LabelOptions const& labelOpts, size_t iteration, double approximationThreshold, storm::builder::ApproximationHeuristic approximationHeuristic) { + void ExplicitDFTModelBuilder::buildModel(size_t iteration, double approximationThreshold, storm::builder::ApproximationHeuristic approximationHeuristic) { STORM_LOG_TRACE("Generating DFT state space"); usedHeuristic = approximationHeuristic; + if (approximationThreshold > 0 && !this->uniqueFailedState) { + // Approximation requires unique failed states + // TODO lift this restriction + STORM_LOG_WARN("Approximation requires unique failed state. Forcing use of unique failed state."); + this->uniqueFailedState = true; + } + if (iteration < 1) { // Initialize switch (usedHeuristic) { @@ -147,15 +135,16 @@ namespace storm { } modelComponents.markovianStates = storm::storage::BitVector(INITIAL_BITVECTOR_SIZE); - if(mergeFailedStates) { + if (this->uniqueFailedState) { // Introduce explicit fail state storm::generator::StateBehavior behavior = generator.createMergeFailedState([this] (DFTStatePointer const& state) { - this->failedStateId = newIndex++; + size_t failedStateId = newIndex++; + STORM_LOG_ASSERT(failedStateId == 0, "Unique failed id is not 0."); matrixBuilder.stateRemapping.push_back(0); - return this->failedStateId; + return failedStateId; } ); - matrixBuilder.setRemapping(failedStateId); + matrixBuilder.setRemapping(0); STORM_LOG_ASSERT(!behavior.empty(), "Behavior is empty."); matrixBuilder.newRowGroup(); setMarkovian(behavior.begin()->isMarkovian()); @@ -165,7 +154,7 @@ namespace storm { STORM_LOG_ASSERT(behavior.getNumberOfChoices() == 1, "Wrong number of choices for failed state."); STORM_LOG_ASSERT(behavior.begin()->size() == 1, "Wrong number of transitions for failed state."); std::pair stateProbabilityPair = *(behavior.begin()->begin()); - STORM_LOG_ASSERT(stateProbabilityPair.first == failedStateId, "No self loop for failed state."); + STORM_LOG_ASSERT(stateProbabilityPair.first == 0, "No self loop for failed state."); STORM_LOG_ASSERT(storm::utility::isOne(stateProbabilityPair.second), "Probability for failed state != 1."); matrixBuilder.addTransition(stateProbabilityPair.first, stateProbabilityPair.second); matrixBuilder.finishRow(); @@ -214,7 +203,7 @@ namespace storm { } exploreStateSpace(approximationThreshold); - size_t stateSize = stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0); + size_t stateSize = stateStorage.getNumberOfStates() + (this->uniqueFailedState ? 1 : 0); modelComponents.markovianStates.resize(stateSize); modelComponents.deterministicModel = generator.isDeterministicModel(); @@ -237,7 +226,7 @@ namespace storm { STORM_LOG_TRACE("Transition matrix: too big to print"); } - buildLabeling(labelOpts); + buildLabeling(); } template @@ -386,7 +375,8 @@ namespace storm { setMarkovian(true); // Add transition to target state with temporary value 0 // TODO: what to do when there is no unique target state? - matrixBuilder.addTransition(failedStateId, storm::utility::zero()); + STORM_LOG_ASSERT(this->uniqueFailedState, "Approximation only works with unique failed state"); + matrixBuilder.addTransition(0, storm::utility::zero()); // Remember skipped state skippedStates[matrixBuilder.getCurrentRowGroup() - 1] = std::make_pair(currentState, currentExplorationHeuristic); matrixBuilder.finishRow(); @@ -471,47 +461,54 @@ namespace storm { } template - void ExplicitDFTModelBuilder::buildLabeling(LabelOptions const& labelOpts) { + void ExplicitDFTModelBuilder::buildLabeling() { // Build state labeling modelComponents.stateLabeling = storm::models::sparse::StateLabeling(modelComponents.transitionMatrix.getRowGroupCount()); // Initial state modelComponents.stateLabeling.addLabel("init"); STORM_LOG_ASSERT(matrixBuilder.getRemapping(initialStateIndex) == initialStateIndex, "Initial state should not be remapped."); modelComponents.stateLabeling.addLabelToState("init", initialStateIndex); - // Label all states corresponding to their status (failed, failsafe, failed BE) - if(labelOpts.buildFailLabel) { - modelComponents.stateLabeling.addLabel("failed"); - } - if(labelOpts.buildFailSafeLabel) { - modelComponents.stateLabeling.addLabel("failsafe"); - } + // Label all states corresponding to their status (failed, failed/dont care BE) + modelComponents.stateLabeling.addLabel("failed"); // Collect labels for all necessary elements for (size_t id = 0; id < dft.nrElements(); ++id) { std::shared_ptr const> element = dft.getElement(id); - if (labelOpts.buildAllLabels || labelOpts.elementLabels.count(element->name()) > 0) { + if (element->isRelevant()) { modelComponents.stateLabeling.addLabel(element->name() + "_fail"); + modelComponents.stateLabeling.addLabel(element->name() + "_dc"); } } // Set labels to states - if (mergeFailedStates) { - modelComponents.stateLabeling.addLabelToState("failed", failedStateId); + if (this->uniqueFailedState) { + modelComponents.stateLabeling.addLabelToState("failed", 0); } for (auto const& stateIdPair : stateStorage.stateToId) { storm::storage::BitVector state = stateIdPair.first; size_t stateId = matrixBuilder.getRemapping(stateIdPair.second); - if (!mergeFailedStates && labelOpts.buildFailLabel && dft.hasFailed(state, *stateGenerationInfo)) { + if (dft.hasFailed(state, *stateGenerationInfo)) { modelComponents.stateLabeling.addLabelToState("failed", stateId); } - if (labelOpts.buildFailSafeLabel && dft.isFailsafe(state, *stateGenerationInfo)) { - modelComponents.stateLabeling.addLabelToState("failsafe", stateId); - } - // Set fail status for each necessary element + // Set fail/dont care status for each necessary element for (size_t id = 0; id < dft.nrElements(); ++id) { std::shared_ptr const> element = dft.getElement(id); - if ((labelOpts.buildAllLabels || labelOpts.elementLabels.count(element->name()) > 0) && storm::storage::DFTState::hasFailed(state, stateGenerationInfo->getStateIndex(element->id()))) { - modelComponents.stateLabeling.addLabelToState(element->name() + "_fail", stateId); + if (element->isRelevant()){ + storm::storage::DFTElementState elementState = storm::storage::DFTState::getElementState(state, *stateGenerationInfo, element->id()); + switch (elementState) { + case storm::storage::DFTElementState::Failed: + modelComponents.stateLabeling.addLabelToState(element->name() + "_fail", stateId); + break; + case storm::storage::DFTElementState::DontCare: + modelComponents.stateLabeling.addLabelToState(element->name() + "_dc", stateId); + break; + case storm::storage::DFTElementState::Operational: + case storm::storage::DFTElementState::Failsafe: + // do nothing + break; + default: + STORM_LOG_ASSERT(false, "Unknown element state " << elementState); + } } } } @@ -540,7 +537,7 @@ namespace storm { // Set self loop for lower bound for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) { auto matrixEntry = matrix.getRow(it->first, 0).begin(); - STORM_LOG_ASSERT(matrixEntry->getColumn() == failedStateId, "Transition has wrong target state."); + STORM_LOG_ASSERT(matrixEntry->getColumn() == 0, "Transition has wrong target state."); STORM_LOG_ASSERT(!it->second.first->isPseudoState(), "State is still pseudo state."); matrixEntry->setValue(storm::utility::one()); matrixEntry->setColumn(it->first); @@ -658,7 +655,7 @@ namespace storm { // Set lower bound for skipped states for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) { auto matrixEntry = matrix.getRow(it->first, 0).begin(); - STORM_LOG_ASSERT(matrixEntry->getColumn() == failedStateId, "Transition has wrong target state."); + STORM_LOG_ASSERT(matrixEntry->getColumn() == 0, "Transition has wrong target state."); STORM_LOG_ASSERT(!it->second.first->isPseudoState(), "State is still pseudo state."); ExplorationHeuristicPointer heuristic = it->second.second; diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.h b/src/storm-dft/builder/ExplicitDFTModelBuilder.h index 5598ac6ef..46ac973b8 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.h +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.h @@ -151,42 +151,24 @@ namespace storm { }; public: - // A structure holding the labeling options. - struct LabelOptions { - // Constructor - LabelOptions(std::vector> properties, bool buildAllLabels = false); - - // Flag indicating if the general fail label should be included. - bool buildFailLabel; - - // Flag indicating if the general failsafe label should be included. - bool buildFailSafeLabel; - - // Flag indicating if all possible labels should be included. - bool buildAllLabels; - - // Set of element names whose fail label to include. - std::set elementLabels; - }; - /*! * Constructor. * * @param dft DFT. * @param symmetries Symmetries in the dft. * @param relevantEvents List with ids of relevant events which should be observed. + * @param allowDCForRelevantEvents If true, Don't Care propagation is allowed even for relevant events. */ - ExplicitDFTModelBuilder(storm::storage::DFT const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, std::set const& relevantEvents); + ExplicitDFTModelBuilder(storm::storage::DFT const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, std::set const& relevantEvents, bool allowDCForRelevantEvents); /*! * Build model from DFT. * - * @param labelOpts Options for labeling. * @param iteration Current number of iteration. * @param approximationThreshold Threshold determining when to skip exploring states. * @param approximationHeuristic Heuristic used for exploring states. */ - void buildModel(LabelOptions const& labelOpts, size_t iteration, double approximationThreshold = 0.0, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); + void buildModel(size_t iteration, double approximationThreshold = 0.0, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); /*! * Get the built model. @@ -221,10 +203,8 @@ namespace storm { /*! * Build the labeling. - * - * @param labelOpts Options for labeling. */ - void buildLabeling(LabelOptions const& labelOpts); + void buildLabeling(); /*! * Add a state to the explored states (if not already there). It also handles pseudo states. @@ -315,17 +295,15 @@ namespace storm { // List with ids of relevant events which should be observed. std::set const& relevantEvents; - //TODO: merge depending on relevant events - const bool mergeFailedStates = true; - // Heuristic used for approximation storm::builder::ApproximationHeuristic usedHeuristic; // Current id for new state size_t newIndex = 0; - // Id of failed state - size_t failedStateId = 0; + // Whether to use a unique state for all failed states + // If used, the unique failed state has the id 0 + bool uniqueFailedState = false; // Id of initial state size_t initialStateIndex = 0; diff --git a/src/storm-dft/generator/DftNextStateGenerator.cpp b/src/storm-dft/generator/DftNextStateGenerator.cpp index eb1795448..4dd2e8402 100644 --- a/src/storm-dft/generator/DftNextStateGenerator.cpp +++ b/src/storm-dft/generator/DftNextStateGenerator.cpp @@ -10,7 +10,7 @@ namespace storm { namespace generator { template - DftNextStateGenerator::DftNextStateGenerator(storm::storage::DFT const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, bool mergeFailedStates) : mDft(dft), mStateGenerationInfo(stateGenerationInfo), state(nullptr), mergeFailedStates(mergeFailedStates) { + DftNextStateGenerator::DftNextStateGenerator(storm::storage::DFT const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo) : mDft(dft), mStateGenerationInfo(stateGenerationInfo), state(nullptr), uniqueFailedState(false) { deterministicModel = !mDft.canHaveNondeterminism(); } @@ -135,9 +135,9 @@ namespace storm { // Get the id of the successor state StateType newStateId; - if (newState->hasFailed(mDft.getTopLevelIndex()) && mergeFailedStates) { + if (newState->hasFailed(mDft.getTopLevelIndex()) && uniqueFailedState) { // Use unique failed state - newStateId = mergeFailedStateId; + newStateId = 0; } else { // Propagate failsafe while (!queues.failsafePropagationDone()) { @@ -226,15 +226,16 @@ namespace storm { template StateBehavior DftNextStateGenerator::createMergeFailedState(StateToIdCallback const& stateToIdCallback) { - STORM_LOG_ASSERT(mergeFailedStates, "No unique failed state used."); - // Introduce explicit fail state + this->uniqueFailedState = true; + // Introduce explicit fail state with id 0 DFTStatePointer failedState = std::make_shared>(mDft, mStateGenerationInfo, 0); - mergeFailedStateId = stateToIdCallback(failedState); - STORM_LOG_TRACE("Introduce fail state with id: " << mergeFailedStateId); + size_t failedStateId = stateToIdCallback(failedState); + STORM_LOG_ASSERT(failedStateId == 0, "Unique failed state has not id 0."); + STORM_LOG_TRACE("Introduce fail state with id 0."); // Add self loop Choice choice(0, true); - choice.addProbability(mergeFailedStateId, storm::utility::one()); + choice.addProbability(0, storm::utility::one()); // No further exploration required StateBehavior result; diff --git a/src/storm-dft/generator/DftNextStateGenerator.h b/src/storm-dft/generator/DftNextStateGenerator.h index b77751521..9fab2ee1f 100644 --- a/src/storm-dft/generator/DftNextStateGenerator.h +++ b/src/storm-dft/generator/DftNextStateGenerator.h @@ -24,7 +24,7 @@ namespace storm { public: typedef std::function StateToIdCallback; - DftNextStateGenerator(storm::storage::DFT const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, bool mergeFailedStates); + DftNextStateGenerator(storm::storage::DFT const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo); bool isDeterministicModel() const; std::vector getInitialStates(StateToIdCallback const& stateToIdCallback); @@ -55,11 +55,8 @@ namespace storm { // Current state DFTStatePointer state; - // Flag indication if all failed states should be merged into one. - bool mergeFailedStates = true; - - // Id of the merged failed state - StateType mergeFailedStateId = 0; + // Flag indication if all failed states should be merged into one unique failed state. + bool uniqueFailedState; // Flag indicating if the model is deterministic. bool deterministicModel = false; diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp index 19a091a50..eed303311 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp @@ -17,7 +17,7 @@ namespace storm { namespace modelchecker { template - typename DFTModelChecker::dft_results DFTModelChecker::check(storm::storage::DFT const& origDft, std::vector> const& properties, bool symred, bool allowModularisation, std::set const& relevantEvents, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { + typename DFTModelChecker::dft_results DFTModelChecker::check(storm::storage::DFT const& origDft, std::vector> const& properties, bool symred, bool allowModularisation, std::set const& relevantEvents, bool allowDCForRelevantEvents, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { totalTimer.start(); dft_results results; @@ -37,14 +37,14 @@ namespace storm { results.push_back(result); } } else { - results = checkHelper(dft, properties, symred, allowModularisation, relevantEvents, approximationError, approximationHeuristic); + results = checkHelper(dft, properties, symred, allowModularisation, relevantEvents, allowDCForRelevantEvents, approximationError, approximationHeuristic); } totalTimer.stop(); return results; } template - typename DFTModelChecker::dft_results DFTModelChecker::checkHelper(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, std::set const& relevantEvents, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { + typename DFTModelChecker::dft_results DFTModelChecker::checkHelper(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, std::set const& relevantEvents, bool allowDCForRelevantEvents, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { STORM_LOG_TRACE("Check helper called"); std::vector> dfts; bool invResults = false; @@ -99,7 +99,7 @@ namespace storm { std::vector res; for(auto const ft : dfts) { // TODO: allow approximation in modularisation - dft_results ftResults = checkHelper(ft, {property}, symred, true, relevantEvents, 0.0); + dft_results ftResults = checkHelper(ft, {property}, symred, true, relevantEvents, allowDCForRelevantEvents, 0.0); STORM_LOG_ASSERT(ftResults.size() == 1, "Wrong number of results"); res.push_back(boost::get(ftResults[0])); } @@ -138,12 +138,12 @@ namespace storm { return results; } else { // No modularisation was possible - return checkDFT(dft, properties, symred, relevantEvents, approximationError, approximationHeuristic); + return checkDFT(dft, properties, symred, relevantEvents, allowDCForRelevantEvents, approximationError, approximationHeuristic); } } template - std::shared_ptr> DFTModelChecker::buildModelViaComposition(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, std::set const& relevantEvents) { + std::shared_ptr> DFTModelChecker::buildModelViaComposition(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, std::set const& relevantEvents, bool allowDCForRelevantEvents) { // TODO: use approximation? STORM_LOG_TRACE("Build model via composition"); std::vector> dfts; @@ -194,9 +194,8 @@ namespace storm { // Build a single CTMC STORM_LOG_DEBUG("Building Model..."); - storm::builder::ExplicitDFTModelBuilder builder(ft, symmetries, relevantEvents); - typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties); - builder.buildModel(labeloptions, 0, 0.0); + storm::builder::ExplicitDFTModelBuilder builder(ft, symmetries, relevantEvents, allowDCForRelevantEvents); + builder.buildModel(0, 0.0); std::shared_ptr> model = builder.getModel(); explorationTimer.stop(); @@ -246,9 +245,8 @@ namespace storm { // Build a single CTMC STORM_LOG_DEBUG("Building Model..."); - storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, relevantEvents); - typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties); - builder.buildModel(labeloptions, 0, 0.0); + storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, relevantEvents, allowDCForRelevantEvents); + builder.buildModel(0, 0.0); std::shared_ptr> model = builder.getModel(); //model->printModelInformationToStream(std::cout); explorationTimer.stop(); @@ -258,7 +256,7 @@ namespace storm { } template - typename DFTModelChecker::dft_results DFTModelChecker::checkDFT(storm::storage::DFT const& dft, property_vector const& properties, bool symred, std::set const& relevantEvents, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { + typename DFTModelChecker::dft_results DFTModelChecker::checkDFT(storm::storage::DFT const& dft, property_vector const& properties, bool symred, std::set const& relevantEvents, bool allowDCForRelevantEvents, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic) { explorationTimer.start(); // Find symmetries @@ -278,8 +276,7 @@ namespace storm { approximation_result approxResult = std::make_pair(storm::utility::zero(), storm::utility::zero()); std::shared_ptr> model; std::vector newResult; - storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, relevantEvents); - typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties); + storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, relevantEvents, allowDCForRelevantEvents); // TODO: compute approximation for all properties simultaneously? std::shared_ptr property = properties[0]; @@ -297,7 +294,7 @@ namespace storm { } STORM_LOG_DEBUG("Building model..."); // TODO refine model using existing model and MC results - builder.buildModel(labeloptions, iteration, approximationError, approximationHeuristic); + builder.buildModel(iteration, approximationError, approximationHeuristic); explorationTimer.stop(); buildingTimer.start(); @@ -344,9 +341,8 @@ namespace storm { // Build a single Markov Automaton auto ioSettings = storm::settings::getModule(); STORM_LOG_DEBUG("Building Model..."); - storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, relevantEvents); - typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties, ioSettings.isExportExplicitSet() || ioSettings.isExportDotSet()); - builder.buildModel(labeloptions, 0, 0.0); + storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, relevantEvents, allowDCForRelevantEvents); + builder.buildModel(0, 0.0); std::shared_ptr> model = builder.getModel(); explorationTimer.stop(); diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.h b/src/storm-dft/modelchecker/dft/DFTModelChecker.h index 34568d2f4..4b4cd4d3d 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.h +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.h @@ -52,11 +52,14 @@ namespace storm { * @param symred Flag whether symmetry reduction should be used. * @param allowModularisation Flag indicating if modularisation is allowed. * @param relevantEvents List with ids of relevant events which should be observed. + * @param allowDCForRelevantEvents If true, Don't Care propagation is allowed even for relevant events. * @param approximationError Error allowed for approximation. Value 0 indicates no approximation. * @param approximationHeuristic Heuristic used for state space exploration. * @return Model checking results for the given properties.. */ - dft_results check(storm::storage::DFT const& origDft, property_vector const& properties, bool symred = true, bool allowModularisation = true, std::set const& relevantEvents = {}, double approximationError = 0.0, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); + dft_results check(storm::storage::DFT const& origDft, property_vector const& properties, bool symred = true, bool allowModularisation = true, + std::set const& relevantEvents = {}, bool allowDCForRelevantEvents = true, double approximationError = 0.0, + storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); /*! * Print timings of all operations to stream. @@ -92,11 +95,14 @@ namespace storm { * @param symred Flag indicating if symmetry reduction should be used. * @param allowModularisation Flag indicating if modularisation is allowed. * @param relevantEvents List with ids of relevant events which should be observed. + * @param allowDCForRelevantEvents If true, Don't Care propagation is allowed even for relevant events. * @param approximationError Error allowed for approximation. Value 0 indicates no approximation. * @param approximationHeuristic Heuristic used for approximation. * @return Model checking results (or in case of approximation two results for lower and upper bound) */ - dft_results checkHelper(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, std::set const& relevantEvents, double approximationError, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); + dft_results checkHelper(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, + std::set const& relevantEvents, bool allowDCForRelevantEvents = true, double approximationError = 0.0, + storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); /*! * Internal helper for building a CTMC from a DFT via parallel composition. @@ -106,9 +112,12 @@ namespace storm { * @param symred Flag indicating if symmetry reduction should be used. * @param allowModularisation Flag indicating if modularisation is allowed. * @param relevantEvents List with ids of relevant events which should be observed. + * @param allowDCForRelevantEvents If true, Don't Care propagation is allowed even for relevant events. * @return CTMC representing the DFT */ - std::shared_ptr> buildModelViaComposition(storm::storage::DFT const& dft, property_vector const& properties, bool symred, bool allowModularisation, std::set const& relevantEvents); + std::shared_ptr> buildModelViaComposition(storm::storage::DFT const& dft, property_vector const& properties, + bool symred, bool allowModularisation, std::set const& relevantEvents, + bool allowDCForRelevantEvents = true); /*! * Check model generated from DFT. @@ -117,12 +126,15 @@ namespace storm { * @param properties Properties to check for. * @param symred Flag indicating if symmetry reduction should be used. * @param relevantEvents List with ids of relevant events which should be observed. + * @param allowDCForRelevantEvents If true, Don't Care propagation is allowed even for relevant events. * @param approximationError Error allowed for approximation. Value 0 indicates no approximation. * @param approximationHeuristic Heuristic used for approximation. * * @return Model checking result */ - dft_results checkDFT(storm::storage::DFT const& dft, property_vector const& properties, bool symred, std::set const& relevantEvents = {}, double approximationError = 0.0, storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); + dft_results checkDFT(storm::storage::DFT const& dft, property_vector const& properties, bool symred, std::set const& relevantEvents = {}, + bool allowDCForRelevantEvents = true, double approximationError = 0.0, + storm::builder::ApproximationHeuristic approximationHeuristic = storm::builder::ApproximationHeuristic::DEPTH); /*! * Check the given markov model for the given properties. diff --git a/src/storm-dft/settings/modules/FaultTreeSettings.cpp b/src/storm-dft/settings/modules/FaultTreeSettings.cpp index fd365a1ea..140b0f175 100644 --- a/src/storm-dft/settings/modules/FaultTreeSettings.cpp +++ b/src/storm-dft/settings/modules/FaultTreeSettings.cpp @@ -19,6 +19,7 @@ namespace storm { const std::string FaultTreeSettings::symmetryReductionOptionShortName = "symred"; const std::string FaultTreeSettings::modularisationOptionName = "modularisation"; const std::string FaultTreeSettings::disableDCOptionName = "disabledc"; + const std::string FaultTreeSettings::allowDCRelevantOptionName = "allowdcrelevant"; const std::string FaultTreeSettings::relevantEventsOptionName = "relevantevents"; const std::string FaultTreeSettings::approximationErrorOptionName = "approximation"; const std::string FaultTreeSettings::approximationErrorOptionShortName = "approx"; @@ -31,10 +32,11 @@ namespace storm { FaultTreeSettings::FaultTreeSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, symmetryReductionOptionName, false, "Exploit symmetric structure of model.").setShortName(symmetryReductionOptionShortName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, modularisationOptionName, false, "Use modularisation (not applicable for expected time).").build()); - this->addOption(storm::settings::OptionBuilder(moduleName, disableDCOptionName, false, "Disable Dont Care propagation.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, disableDCOptionName, false, "Disable Don't Care propagation.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, firstDependencyOptionName, false, "Avoid non-determinism by always taking the first possible dependency.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, relevantEventsOptionName, false, "Specifies the relevant events from the DFT.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of relevant events. 'all' marks all events as relevant, The default '' or 'none' mark only the top level event as relevant.").setDefaultValueString("").build()).build()); + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of names of relevant events. 'all' marks all events as relevant, The default '' or 'none' marks only the top level event as relevant.").setDefaultValueString("").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, allowDCRelevantOptionName, false, "Allow Don't Care propagation for relevant events.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, approximationErrorOptionName, false, "Approximation error allowed.").setShortName(approximationErrorOptionShortName).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("error", "The relative approximation error to use.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterEqualValidator(0.0)).build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, approximationHeuristicOptionName, false, "Set the heuristic used for approximation.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("heuristic", "The name of the heuristic used for approximation.") @@ -57,6 +59,10 @@ namespace storm { return this->getOption(disableDCOptionName).getHasOptionBeenSet(); } + bool FaultTreeSettings::isAllowDCForRelevantEvents() const { + return this->getOption(allowDCRelevantOptionName).getHasOptionBeenSet(); + } + bool FaultTreeSettings::areRelevantEventsSet() const { return this->getOption(relevantEventsOptionName).getHasOptionBeenSet() && (this->getOption(relevantEventsOptionName).getArgumentByName("values").getValueAsString() != ""); } diff --git a/src/storm-dft/settings/modules/FaultTreeSettings.h b/src/storm-dft/settings/modules/FaultTreeSettings.h index 1e88b48e4..16a726e04 100644 --- a/src/storm-dft/settings/modules/FaultTreeSettings.h +++ b/src/storm-dft/settings/modules/FaultTreeSettings.h @@ -40,6 +40,13 @@ namespace storm { */ bool isDisableDC() const; + /*! + * Retrieves whether the option to allow Dont Care propagation for relevant events is set. + * + * @return True iff the option was set. + */ + bool isAllowDCForRelevantEvents() const; + /*! * Retrieves whether the option to give relevant events is set. * @@ -106,6 +113,7 @@ namespace storm { static const std::string symmetryReductionOptionShortName; static const std::string modularisationOptionName; static const std::string disableDCOptionName; + static const std::string allowDCRelevantOptionName; static const std::string relevantEventsOptionName; static const std::string approximationErrorOptionName; static const std::string approximationErrorOptionShortName; diff --git a/src/storm-dft/storage/dft/DFT.cpp b/src/storm-dft/storage/dft/DFT.cpp index 7538c4abc..21251f044 100644 --- a/src/storm-dft/storage/dft/DFT.cpp +++ b/src/storm-dft/storage/dft/DFT.cpp @@ -862,12 +862,14 @@ namespace storm { } template - void DFT::setRelevantEvents(std::set const& relevantEvents) const { + void DFT::setRelevantEvents(std::set const& relevantEvents, bool allowDCForRelevantEvents) const { for (auto const& elem : mElements) { if (relevantEvents.find(elem->id()) != relevantEvents.end()) { elem->setRelevance(true); + elem->setAllowDC(allowDCForRelevantEvents); } else { elem->setRelevance(false); + elem->setAllowDC(true); } } } diff --git a/src/storm-dft/storage/dft/DFT.h b/src/storm-dft/storage/dft/DFT.h index 2b8795a82..27079a6ba 100644 --- a/src/storm-dft/storage/dft/DFT.h +++ b/src/storm-dft/storage/dft/DFT.h @@ -321,8 +321,9 @@ namespace storm { /*! * Set the relevance flag for all elements according to the given relevant events. * @param relevantEvents All elements which should be to relevant. All elements not occuring are set to irrelevant. + * @param allowDCForRelevantEvents Flag whether Don't Care propagation is allowed even for relevant events. */ - void setRelevantEvents(std::set const& relevantEvents) const; + void setRelevantEvents(std::set const& relevantEvents, bool allowDCForRelevantEvents) const; private: std::tuple, std::vector, std::vector> getSortedParentAndDependencyIds(size_t index) const; diff --git a/src/storm-dft/storage/dft/elements/DFTElement.cpp b/src/storm-dft/storage/dft/elements/DFTElement.cpp index d9bba261a..57c3b1ee0 100644 --- a/src/storm-dft/storage/dft/elements/DFTElement.cpp +++ b/src/storm-dft/storage/dft/elements/DFTElement.cpp @@ -9,8 +9,7 @@ namespace storm { template bool DFTElement::checkDontCareAnymore(storm::storage::DFTState& state, DFTStateSpaceGenerationQueues& queues) const { - if (this->isRelevant()) { - // Relevant events are ignored for Don't Care propagation + if (!this->mAllowDC) { return false; } diff --git a/src/storm-dft/storage/dft/elements/DFTElement.h b/src/storm-dft/storage/dft/elements/DFTElement.h index f89f69c7a..27784dae0 100644 --- a/src/storm-dft/storage/dft/elements/DFTElement.h +++ b/src/storm-dft/storage/dft/elements/DFTElement.h @@ -51,7 +51,7 @@ namespace storm { * @param id Id. * @param name Name. */ - DFTElement(size_t id, std::string const& name) : mId(id), mName(name), mRank(-1), mRelevant(false) { + DFTElement(size_t id, std::string const& name) : mId(id), mName(name), mRank(-1), mRelevant(false), mAllowDC(true) { // Intentionally left empty. } @@ -134,6 +134,14 @@ namespace storm { this->mRelevant = relevant; } + /*! + * Set whether Don't Care propagation is allowed for this element. + * @param allowDC If true, the element is allowed to be set to Don't Care. + */ + virtual void setAllowDC(bool allowDC) const { + this->mAllowDC = allowDC; + } + /*! * Checks whether the element is a basic element. * @return True iff element is a BE. @@ -438,6 +446,7 @@ namespace storm { DFTDependencyVector mOutgoingDependencies; DFTRestrictionVector mRestrictions; mutable bool mRelevant; // Must be mutable to allow changes later on. TODO: avoid mutable + mutable bool mAllowDC; // Must be mutable to allow changes later on. TODO: avoid mutable }; diff --git a/src/test/storm-dft/api/DftApproximationTest.cpp b/src/test/storm-dft/api/DftApproximationTest.cpp index 7718d9218..e17fa200c 100644 --- a/src/test/storm-dft/api/DftApproximationTest.cpp +++ b/src/test/storm-dft/api/DftApproximationTest.cpp @@ -57,7 +57,7 @@ namespace { EXPECT_TRUE(storm::api::isWellFormed(*dft)); std::string property = "T=? [F \"failed\"]"; std::vector> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(property)); - typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, config.useSR, false, {}, errorBound, + typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, config.useSR, false, {}, true, errorBound, config.heuristic, false); return boost::get::approximation_result>(results[0]); } @@ -67,8 +67,8 @@ namespace { EXPECT_TRUE(storm::api::isWellFormed(*dft)); std::stringstream propertyStream; propertyStream << "P=? [F<=" << timeBound << " \"failed\"]"; - std::vector> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(propertyStream.str())); - typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, config.useSR, false, {}, errorBound, + std::vector > properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(propertyStream.str())); + typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, config.useSR, false, {}, true, errorBound, config.heuristic, false); return boost::get::approximation_result>(results[0]); } diff --git a/src/test/storm-dft/api/DftModelBuildingTest.cpp b/src/test/storm-dft/api/DftModelBuildingTest.cpp index cbaa53e82..cd71be290 100644 --- a/src/test/storm-dft/api/DftModelBuildingTest.cpp +++ b/src/test/storm-dft/api/DftModelBuildingTest.cpp @@ -16,14 +16,12 @@ namespace { std::vector> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(property)); std::map>> emptySymmetry; storm::storage::DFTIndependentSymmetries symmetries(emptySymmetry); - typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties, false); - // Set relevant events (none) std::set relevantEvents; // Build model - storm::builder::ExplicitDFTModelBuilder builder(*dft, symmetries, relevantEvents); - builder.buildModel(labeloptions, 0, 0.0); + storm::builder::ExplicitDFTModelBuilder builder(*dft, symmetries, relevantEvents, false); + builder.buildModel(0, 0.0); std::shared_ptr> model = builder.getModel(); EXPECT_EQ(8ul, model->getNumberOfStates()); EXPECT_EQ(13ul, model->getNumberOfTransitions()); @@ -31,8 +29,8 @@ namespace { // Set relevant events (all) relevantEvents = dft->getAllIds(); // Build model - storm::builder::ExplicitDFTModelBuilder builder2(*dft, symmetries, relevantEvents); - builder2.buildModel(labeloptions, 0, 0.0); + storm::builder::ExplicitDFTModelBuilder builder2(*dft, symmetries, relevantEvents, false); + builder2.buildModel(0, 0.0); model = builder2.getModel(); EXPECT_EQ(170ul, model->getNumberOfStates()); EXPECT_EQ(688ul, model->getNumberOfTransitions()); @@ -42,8 +40,8 @@ namespace { relevantEvents.clear(); relevantEvents.insert(dft->getIndex("H")); // Build model - storm::builder::ExplicitDFTModelBuilder builder3(*dft, symmetries, relevantEvents); - builder3.buildModel(labeloptions, 0, 0.0); + storm::builder::ExplicitDFTModelBuilder builder3(*dft, symmetries, relevantEvents, false); + builder3.buildModel(0, 0.0); model = builder3.getModel(); EXPECT_EQ(11ul, model->getNumberOfStates()); EXPECT_EQ(23ul, model->getNumberOfTransitions()); @@ -54,8 +52,8 @@ namespace { relevantEvents.insert(dft->getIndex("H")); relevantEvents.insert(dft->getIndex("I")); // Build model - storm::builder::ExplicitDFTModelBuilder builder4(*dft, symmetries, relevantEvents); - builder4.buildModel(labeloptions, 0, 0.0); + storm::builder::ExplicitDFTModelBuilder builder4(*dft, symmetries, relevantEvents, false); + builder4.buildModel(0, 0.0); model = builder4.getModel(); EXPECT_EQ(14ul, model->getNumberOfStates()); EXPECT_EQ(30ul, model->getNumberOfTransitions()); diff --git a/src/test/storm-dft/api/DftModelCheckerTest.cpp b/src/test/storm-dft/api/DftModelCheckerTest.cpp index baf30dc02..f49639ba3 100644 --- a/src/test/storm-dft/api/DftModelCheckerTest.cpp +++ b/src/test/storm-dft/api/DftModelCheckerTest.cpp @@ -81,7 +81,7 @@ namespace { relevantEvents = dft->getAllIds(); } typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, config.useSR, config.useMod, - relevantEvents); + relevantEvents, true); return boost::get(results[0]); } From 98f3cdbfaf83d4c9b2115b200edcc0af6377f603 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 17 Apr 2019 19:19:08 +0200 Subject: [PATCH 40/40] Adapted tests to changes --- .../storm-dft/api/DftModelBuildingTest.cpp | 44 ++++++++++++++++--- .../storm-dft/api/DftModelCheckerTest.cpp | 8 +--- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/test/storm-dft/api/DftModelBuildingTest.cpp b/src/test/storm-dft/api/DftModelBuildingTest.cpp index cd71be290..46cab4f61 100644 --- a/src/test/storm-dft/api/DftModelBuildingTest.cpp +++ b/src/test/storm-dft/api/DftModelBuildingTest.cpp @@ -32,9 +32,8 @@ namespace { storm::builder::ExplicitDFTModelBuilder builder2(*dft, symmetries, relevantEvents, false); builder2.buildModel(0, 0.0); model = builder2.getModel(); - EXPECT_EQ(170ul, model->getNumberOfStates()); - EXPECT_EQ(688ul, model->getNumberOfTransitions()); - + EXPECT_EQ(448ul, model->getNumberOfStates()); + EXPECT_EQ(1260ul, model->getNumberOfTransitions()); // Set relevant events (H) relevantEvents.clear(); @@ -43,8 +42,8 @@ namespace { storm::builder::ExplicitDFTModelBuilder builder3(*dft, symmetries, relevantEvents, false); builder3.buildModel(0, 0.0); model = builder3.getModel(); - EXPECT_EQ(11ul, model->getNumberOfStates()); - EXPECT_EQ(23ul, model->getNumberOfTransitions()); + EXPECT_EQ(12ul, model->getNumberOfStates()); + EXPECT_EQ(25ul, model->getNumberOfTransitions()); // Set relevant events (H, I) @@ -55,8 +54,39 @@ namespace { storm::builder::ExplicitDFTModelBuilder builder4(*dft, symmetries, relevantEvents, false); builder4.buildModel(0, 0.0); model = builder4.getModel(); - EXPECT_EQ(14ul, model->getNumberOfStates()); - EXPECT_EQ(30ul, model->getNumberOfTransitions()); + EXPECT_EQ(16ul, model->getNumberOfStates()); + EXPECT_EQ(33ul, model->getNumberOfTransitions()); + + // Set relevant events (none) + relevantEvents.clear(); + // Build model + storm::builder::ExplicitDFTModelBuilder builder5(*dft, symmetries, relevantEvents, true); + builder5.buildModel(0, 0.0); + model = builder5.getModel(); + EXPECT_EQ(8ul, model->getNumberOfStates()); + EXPECT_EQ(13ul, model->getNumberOfTransitions()); + + // Set relevant events (all) + relevantEvents = dft->getAllIds(); + // Build model + storm::builder::ExplicitDFTModelBuilder builder6(*dft, symmetries, relevantEvents, true); + builder6.buildModel(0, 0.0); + model = builder6.getModel(); + EXPECT_EQ(8ul, model->getNumberOfStates()); + EXPECT_EQ(13ul, model->getNumberOfTransitions()); + + + // Set relevant events (H, I) + relevantEvents.clear(); + relevantEvents.insert(dft->getIndex("H")); + relevantEvents.insert(dft->getIndex("I")); + // Build model + storm::builder::ExplicitDFTModelBuilder builder7(*dft, symmetries, relevantEvents, true); + builder7.buildModel(0, 0.0); + model = builder7.getModel(); + EXPECT_EQ(8ul, model->getNumberOfStates()); + EXPECT_EQ(13ul, model->getNumberOfTransitions()); + } } diff --git a/src/test/storm-dft/api/DftModelCheckerTest.cpp b/src/test/storm-dft/api/DftModelCheckerTest.cpp index f49639ba3..73550a3af 100644 --- a/src/test/storm-dft/api/DftModelCheckerTest.cpp +++ b/src/test/storm-dft/api/DftModelCheckerTest.cpp @@ -155,12 +155,8 @@ namespace { result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep3.dft"); EXPECT_FLOAT_EQ(result, 67 / 24.0); if (this->getConfig().useMod) { - if (this->getConfig().useDC) { - EXPECT_THROW(this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep2.dft"), storm::exceptions::NotSupportedException); - } else { - result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep2.dft"); - EXPECT_FLOAT_EQ(result, 38 / 15.0); - } + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep2.dft"); + EXPECT_FLOAT_EQ(result, 38 / 15.0); EXPECT_THROW(this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep4.dft"), storm::exceptions::NotSupportedException); } else { result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep4.dft");