diff --git a/src/formula/AbstractFilter.h b/src/formula/AbstractFilter.h index fe9798fca..ba95d5524 100644 --- a/src/formula/AbstractFilter.h +++ b/src/formula/AbstractFilter.h @@ -9,6 +9,7 @@ #define STORM_FORMULA_ABSTRACTFILTER_H_ #include <vector> +#include <string> #include "src/formula/AbstractFormula.h" #include "src/formula/Actions/AbstractAction.h" diff --git a/src/formula/Actions/AbstractAction.h b/src/formula/Actions/AbstractAction.h index c58ad6be0..77d2089ea 100644 --- a/src/formula/Actions/AbstractAction.h +++ b/src/formula/Actions/AbstractAction.h @@ -9,7 +9,11 @@ #define STORM_FORMULA_ACTION_ABSTRACTACTION_H_ #include <vector> +#include <utility> #include "src/storage/BitVector.h" +#include "src/modelchecker/prctl/AbstractModelChecker.h" +#include "src/modelchecker/csl/AbstractModelChecker.h" +#include "src/modelchecker/ltl/AbstractModelChecker.h" namespace storm { namespace property { @@ -20,6 +24,42 @@ class AbstractAction { public: + struct Result { + + /*! + * + */ + Result() : selection(), stateMap(), pathResult(), stateResult(){ + // Intentionally left empty. + } + + /*! + * + */ + Result(Result const & other) : selection(other.selection), stateMap(other.stateMap), pathResult(other.pathResult), stateResult(other.stateResult) { + // Intentionally left empty. + } + + /*! + * + */ + Result(storm::storage::BitVector const & selection, std::vector<uint_fast64_t> const & stateMap, std::vector<T> const & pathResult, storm::storage::BitVector const & stateResult) : selection(selection), stateMap(stateMap), pathResult(pathResult), stateResult(stateResult) { + // Intentionally left empty. + } + + //! + storm::storage::BitVector selection; + + //! + std::vector<uint_fast64_t> stateMap; + + //! + std::vector<T> pathResult; + + //! + storm::storage::BitVector stateResult; + }; + /*! * Virtual destructor * To ensure that the right destructor is called @@ -28,29 +68,32 @@ public: //Intentionally left empty } - /*! + /* * */ - virtual std::vector<T> evaluate(std::vector<T> input) const { - return input; + virtual Result evaluate(Result const & filterResult, storm::modelchecker::prctl::AbstractModelChecker<T> const & mc) const { + return Result(); } - /*! + /* * */ - virtual storm::storage::BitVector evaluate(storm::storage::BitVector input) const { - return input; + virtual Result evaluate(Result const & filterResult, storm::modelchecker::csl::AbstractModelChecker<T> const & mc) const { + return Result(); } - /*! + /* * */ - virtual std::string toString() const = 0; + virtual Result evaluate(Result const & filterResult, storm::modelchecker::ltl::AbstractModelChecker<T> const & mc) const { + return Result(); + } /*! * */ - virtual std::string toFormulaString() const = 0; + virtual std::string toString() const = 0; + }; } //namespace action diff --git a/src/formula/Actions/BoundAction.h b/src/formula/Actions/BoundAction.h new file mode 100644 index 000000000..4b7f77cc0 --- /dev/null +++ b/src/formula/Actions/BoundAction.h @@ -0,0 +1,167 @@ +/* + * BoundAction.h + * + * Created on: Jun 22, 2014 + * Author: Manuel Sascha Weiand + */ + +#ifndef STORM_FORMULA_ACTION_BOUNDACTION_H_ +#define STORM_FORMULA_ACTION_BOUNDACTION_H_ + +#include "src/formula/Actions/AbstractAction.h" +#include "src/formula/ComparisonType.h" + +namespace storm { +namespace property { +namespace action { + +template <class T> +class BoundAction : public AbstractAction<T> { + + typedef typename AbstractAction<T>::Result Result; + +public: + + BoundAction() : comparisonOperator(storm::property::GREATER_EQUAL), bound(0) { + //Intentionally left empty. + } + + BoundAction(storm::property::ComparisonType comparisonOperator, T bound) : comparisonOperator(comparisonOperator), bound(bound) { + //Intentionally left empty. + } + + /*! + * Virtual destructor + * To ensure that the right destructor is called + */ + virtual ~BoundAction() { + //Intentionally left empty + } + + /*! + * + */ + virtual Result evaluate(Result const & result, storm::modelchecker::prctl::AbstractModelChecker<T> const & mc) const override { + return evaluate(result); + } + + /*! + * + */ + virtual Result evaluate(Result const & result, storm::modelchecker::csl::AbstractModelChecker<T> const & mc) const override { + return evaluate(result); + } + + /*! + * + */ + virtual Result evaluate(Result const & result, storm::modelchecker::ltl::AbstractModelChecker<T> const & mc) const override { + return evaluate(result); + } + + /*! + * + */ + virtual std::string toString() const override { + std::string out = "bound("; + switch (comparisonOperator) { + case LESS: + out += "<"; + break; + case LESS_EQUAL: + out += "<="; + break; + case GREATER: + out += ">"; + break; + case GREATER_EQUAL: + out += ">="; + break; + default: + LOG4CPLUS_INFO(logger, "Unknown comparison operator of value " << comparisonOperator << "."); + std::cout << "Unknown comparison operator of value " << comparisonOperator << "." << std::endl; + break; + } + out += ", "; + out += std::to_string(bound); + out += ")"; + return out; + } + +private: + + /*! + * + */ + virtual Result evaluate(Result const & result) const { + + //Initialize the new selection vector. + storm::storage::BitVector out(result.selection.size()); + + if(result.pathResult.size() != 0) { + + //Fill the selction by comapring the values for all previously selected states with theegiven bound using the comparison operator. + for(uint_fast64_t i = 0; i < result.stateMap.size(); i++) { + if(result.selection[result.stateMap[i]]) { + switch(comparisonOperator) { + case storm::property::GREATER_EQUAL: + out.set(result.pathResult[result.stateMap[i]] >= bound); + break; + case storm::property::GREATER: + out.set(result.pathResult[result.stateMap[i]] > bound); + break; + case storm::property::LESS_EQUAL: + out.set(result.pathResult[result.stateMap[i]] <= bound); + break; + case storm::property::LESS: + out.set(result.pathResult[result.stateMap[i]] < bound); + break; + default: + LOG4CPLUS_INFO(logger, "Unknown comparison operator of value " << comparisonOperator << "."); + std::cout << "Unknown comparison operator of value " << comparisonOperator << "." << std::endl; + break; + } + } + } + } else { + + //Fill the selction by comapring the values for all previously selected states with theegiven bound using the comparison operator. + for(uint_fast64_t i = 0; i < result.stateMap.size(); i++) { + if(result.selection[result.stateMap[i]]) { + switch(comparisonOperator) { + case storm::property::GREATER_EQUAL: + out.set(result.stateResult[result.stateMap[i]] >= bound); + break; + case storm::property::GREATER: + out.set(result.stateResult[result.stateMap[i]] > bound); + break; + case storm::property::LESS_EQUAL: + out.set(result.stateResult[result.stateMap[i]] <= bound); + break; + case storm::property::LESS: + out.set(result.stateResult[result.stateMap[i]] < bound); + break; + default: + LOG4CPLUS_INFO(logger, "Unknown comparison operator of value " << comparisonOperator << "."); + std::cout << "Unknown comparison operator of value " << comparisonOperator << "." << std::endl; + break; + } + } + } + } + + return Result(out, result.stateMap, result.pathResult, result.stateResult); + } + + storm::property::ComparisonType comparisonOperator; + T bound; + +}; + + +} +} +} + + +#endif /* STORM_FORMULA_ACTION_BOUNDACTION_H_ */ diff --git a/src/formula/Actions/InvertAction.h b/src/formula/Actions/InvertAction.h new file mode 100644 index 000000000..90192020c --- /dev/null +++ b/src/formula/Actions/InvertAction.h @@ -0,0 +1,80 @@ +/* + * InvertAction.h + * + * Created on: Jun 22, 2014 + * Author: Manuel Sascha Weiand + */ + +#ifndef STORM_FORMULA_ACTION_INVERTACTION_H_ +#define STORM_FORMULA_ACTION_INVERTACTION_H_ + +#include "src/formula/Actions/AbstractAction.h" + +namespace storm { +namespace property { +namespace action { + +template <class T> +class InvertAction : public AbstractAction<T> { + + typedef typename AbstractAction<T>::Result Result; + +public: + + InvertAction() { + //Intentionally left empty. + } + + /*! + * Virtual destructor + * To ensure that the right destructor is called + */ + virtual ~InvertAction() { + //Intentionally left empty + } + + /*! + * + */ + virtual Result evaluate(Result const & result, storm::modelchecker::prctl::AbstractModelChecker<T> const & mc) const override { + return evaluate(result); + } + + /*! + * + */ + virtual Result evaluate(Result const & result, storm::modelchecker::csl::AbstractModelChecker<T> const & mc) const override { + return evaluate(result); + } + + /*! + * + */ + virtual Result evaluate(Result const & result, storm::modelchecker::ltl::AbstractModelChecker<T> const & mc) const override { + return evaluate(result); + } + + /*! + * + */ + virtual std::string toString() const override { + return "invert"; + } + +private: + + /*! + * + */ + virtual Result evaluate(Result const & result) const { + storm::storage::BitVector out(result.selection); + return Result(~out, result.stateMap, result.pathResult, result.stateResult); + } +}; + +} //namespace action +} //namespace property +} //namespace storm + + +#endif /* STORM_FORMULA_ACTION_INVERTACTION_H_ */ diff --git a/src/formula/Actions/RangeAction.h b/src/formula/Actions/RangeAction.h index 3952419ae..ce8b0e2ae 100644 --- a/src/formula/Actions/RangeAction.h +++ b/src/formula/Actions/RangeAction.h @@ -10,8 +10,6 @@ #include "src/formula/Actions/AbstractAction.h" -#include <string> - namespace storm { namespace property { namespace action { @@ -19,14 +17,21 @@ namespace action { template <class T> class RangeAction : public AbstractAction<T> { + typedef typename AbstractAction<T>::Result Result; + public: RangeAction() : from(0), to(0) { //Intentionally left empty. } + /*! + * Excluding the state with position to. + */ RangeAction(uint_fast64_t from, uint_fast64_t to) : from(from), to(to) { - //Intentionally left empty. + if(from > to) { + throw storm::exceptions::IllegalArgumentException() << "The end of the range is lower than its beginning"; + } } /*! @@ -40,56 +45,71 @@ public: /*! * */ - virtual std::vector<T> evaluate(std::vector<T> input) const override { - // The range constructor is used here instead of manipulating the incoming vector. - // While deleting the element at the end of the vector is efficient, deleting elements at any position but the end is not. - // Also this leaves the incoming vector unchanged. - std::vector<T> out(input.begin() + from, input.begin() + to); - return out; + virtual Result evaluate(Result const & result, storm::modelchecker::prctl::AbstractModelChecker<T> const & mc) const override { + return evaluate(result); } /*! * */ - virtual storm::storage::BitVector evaluate(storm::storage::BitVector input) const override { - //Initialize the output vector. - storm::storage::BitVector out(to - from + 1); - - storm::storage::BitVector::const_iterator it = input.begin(); - - //Proceed the set index iterator to the first set bit within the range. - for(; *it < from; ++it); + virtual Result evaluate(Result const & result, storm::modelchecker::csl::AbstractModelChecker<T> const & mc) const override { + return evaluate(result); + } - //Fill the output vector. - for(; *it <= to; ++it) { - out.set(*it-from); - } - return out; + /*! + * + */ + virtual Result evaluate(Result const & result, storm::modelchecker::ltl::AbstractModelChecker<T> const & mc) const override { + return evaluate(result); } /*! * */ virtual std::string toString() const override { - std::string out = "range, "; + std::string out = "range("; out += std::to_string(from); out += ", "; out += std::to_string(to); + out += ")"; return out; } +private: + /*! * */ - virtual std::string toFormulaString() const override { - std::string out = "\"range\", "; - out += std::to_string(from); - out += ", "; - out += std::to_string(to); - return out; + virtual Result evaluate(Result const & result) const { + //Initialize the output vector. + storm::storage::BitVector out(result.selection.size()); + + uint_fast64_t end = to - from; + + // Safety check for access bounds. + if(from > result.stateMap.size()) { + LOG4CPLUS_WARN(logger, "Range begins behind the end of the states by " << to - result.stateMap.size() << ". No state was selected."); + std::cout << "Range begins behind the end of the states by " << to - result.stateMap.size() << ". No state was selected." << std::endl; + + return Result(out, result.stateMap, result.pathResult, result.stateResult); + } + + if(to > result.stateMap.size()) { + + end = result.selection.size() - from; + + LOG4CPLUS_WARN(logger, "Range ends behind the end of the states by " << to - result.stateMap.size() << ". The range has been cut at the last state."); + std::cout << "Range ends behind the end of the states by " << to - result.stateMap.size() << ". The range has been cut at the last state." << std::endl; + } + + //Fill the output vector. + for(uint_fast64_t i=0; i < end; i++) { + out.set(result.stateMap[from + i], result.selection[result.stateMap[from + i]]); + } + + return Result(out, result.stateMap, result.pathResult, result.stateResult); } -private: uint_fast64_t from; uint_fast64_t to; diff --git a/src/formula/Actions/SortAction.h b/src/formula/Actions/SortAction.h new file mode 100644 index 000000000..5a4c1c622 --- /dev/null +++ b/src/formula/Actions/SortAction.h @@ -0,0 +1,174 @@ +/* + * SortAction.h + * + * Created on: Jun 22, 2014 + * Author: Manuel Sascha Weiand + */ + +#ifndef STORM_FORMULA_ACTION_SORTACTION_H_ +#define STORM_FORMULA_ACTION_SORTACTION_H_ + +#include "src/formula/Actions/AbstractAction.h" +#include <cctype> + +namespace storm { +namespace property { +namespace action { + +template <class T> +class SortAction : public AbstractAction<T> { + + typedef typename AbstractAction<T>::Result Result; + +public: + + enum SortingCategory {INDEX, VALUE}; + + SortAction() : category(INDEX), ascending(true) { + //Intentionally left empty. + } + + SortAction(SortingCategory category, bool ascending = true) : category(category), ascending(ascending) { + //Intentionally left empty. + } + + /*! + * Virtual destructor + * To ensure that the right destructor is called + */ + virtual ~SortAction() { + //Intentionally left empty + } + + /*! + * + */ + virtual Result evaluate(Result const & result, storm::modelchecker::prctl::AbstractModelChecker<T> const & mc) const override { + return evaluate(result); + } + + /*! + * + */ + virtual Result evaluate(Result const & result, storm::modelchecker::csl::AbstractModelChecker<T> const & mc) const override { + return evaluate(result); + } + + /*! + * + */ + virtual Result evaluate(Result const & result, storm::modelchecker::ltl::AbstractModelChecker<T> const & mc) const override { + return evaluate(result); + } + + /*! + * + */ + virtual std::string toString() const override { + std::string out = "sort, "; + switch (category) { + case INDEX: + out += "index"; + break; + case VALUE: + out += "value"; + break; + default: + LOG4CPLUS_INFO(logger, "Unknown sorting category of value " << category << "."); + std::cout << "Unknown sorting category of value " << category << "." << std::endl; + break; + } + out += ", "; + out += ascending ? "ascending" : "descending"; + return out; + } + + +private: + + /*! + * + */ + Result evaluate(Result const & result) const { + + if(category == VALUE) { + //TODO + + if(result.pathResult.size() != 0) { + return Result(result.selection, sort(result.stateMap, result.pathResult), result.pathResult, result.stateResult); + } else { + return Result(result.selection, sort(result.stateMap, result.stateResult), result.pathResult, result.stateResult); + } + + } else { + return Result(result.selection, sort(result.stateMap.size()), result.pathResult, result.stateResult); + } + } + + /*! + * + */ + std::vector<uint_fast64_t> sort(uint_fast64_t length) const { + + // Project the vector down to its first component. + std::vector<uint_fast64_t> outMap(length); + + // Sort the combined vector. + if(ascending) { + for(uint_fast64_t i = 0; i < length; i++) { + outMap[i] = i; + } + } else { + for(uint_fast64_t i = 0; i < length; i++) { + outMap[i] = length - i - 1; + } + } + + return outMap; + } + + /*! + * + */ + std::vector<uint_fast64_t> sort(std::vector<uint_fast64_t> const & stateMap, std::vector<T> const & values) const { + + // Prepare the new state map. + std::vector<uint_fast64_t> outMap(stateMap); + + // Sort the state map. + if(ascending) { + std::sort(outMap.begin(), outMap.end(), [&] (uint_fast64_t a, uint_fast64_t b) -> bool { return values[a] <= values[b]; }); + } else { + std::sort(outMap.begin(), outMap.end(), [&] (uint_fast64_t a, uint_fast64_t b) -> bool { return values[a] >= values[b]; }); + } + + return outMap; + } + + /*! + * + */ + std::vector<uint_fast64_t> sort(std::vector<uint_fast64_t> const & stateMap, storm::storage::BitVector const & values) const { + + // Prepare the new state map. + std::vector<uint_fast64_t> outMap(stateMap); + + // Sort the state map. + if(ascending) { + std::sort(outMap.begin(), outMap.end(), [&] (uint_fast64_t a, uint_fast64_t b) -> bool { return values[a] <= values[b]; }); + } else { + std::sort(outMap.begin(), outMap.end(), [&] (uint_fast64_t a, uint_fast64_t b) -> bool { return values[a] >= values[b]; }); + } + + return outMap; + } + + SortingCategory category; + bool ascending; +}; + +} //namespace action +} //namespace property +} //namespace storm + +#endif /* STORM_FORMULA_ACTION_SORTACTION_H_ */ diff --git a/src/formula/Csl/CslFilter.h b/src/formula/Csl/CslFilter.h index 14c578be7..ae5c256d9 100644 --- a/src/formula/Csl/CslFilter.h +++ b/src/formula/Csl/CslFilter.h @@ -122,24 +122,6 @@ public: } } - bool validate() const { - // Test whether the stored filter actions are consistent in relation to themselves and to the ingoing modelchecking result. - - // Do a dynamic cast to test for the actual formula type. - if(dynamic_cast<AbstractStateFormula<T>*>(child) != nullptr) { - //TODO: Actual validation. - } - else if (dynamic_cast<AbstractPathFormula<T>*>(child) != nullptr) { - //TODO: Actual validation. - } - else { - // This branch should be unreachable. If you ended up here, something strange has happened. - //TODO: Error here. - } - - return true; - } - virtual std::string toString() const override { std::string desc = ""; diff --git a/src/formula/Prctl/PrctlFilter.h b/src/formula/Prctl/PrctlFilter.h index 407b4f6c3..77a8c35f7 100644 --- a/src/formula/Prctl/PrctlFilter.h +++ b/src/formula/Prctl/PrctlFilter.h @@ -13,6 +13,17 @@ #include "src/formula/Prctl/AbstractPathFormula.h" #include "src/formula/Prctl/AbstractStateFormula.h" #include "src/modelchecker/prctl/AbstractModelChecker.h" +#include "src/formula/Actions/AbstractAction.h" + +namespace storm { +namespace property { +namespace action { + template <typename T> class AbstractAction; +} +} +} + +#include <algorithm> namespace storm { namespace property { @@ -21,6 +32,8 @@ namespace prctl { template <class T> class PrctlFilter : public storm::property::AbstractFilter<T> { + typedef typename storm::property::action::AbstractAction<T>::Result Result; + public: PrctlFilter() : AbstractFilter<T>(UNDEFINED), child(nullptr) { @@ -51,125 +64,26 @@ public: LOG4CPLUS_INFO(logger, "Model checking formula\t" << this->toString()); std::cout << "Model checking formula:\t" << this->toString() << std::endl; - // Do a dynamic cast to test for the actual formula type and call the correct evaluation function. - if(dynamic_cast<AbstractStateFormula<T>*>(child) != nullptr) { - - // Check the formula and apply the filter actions. - storm::storage::BitVector result; - - try { - result = evaluate(modelchecker, dynamic_cast<AbstractStateFormula<T>*>(child)); - } catch (std::exception& e) { - std::cout << "Error during computation: " << e.what() << "Skipping property." << std::endl; - LOG4CPLUS_ERROR(logger, "Error during computation: " << e.what() << "Skipping property."); - std::cout << std::endl << "-------------------------------------------" << std::endl; + Result result; - return; - } - - // Now write out the result. - - if(this->actions.empty()) { - - // There is no filter action given. So provide legacy support: - // Return the results for all states labeled with "init". - LOG4CPLUS_INFO(logger, "Result for initial states:"); - std::cout << "Result for initial states:" << std::endl; - for (auto initialState : modelchecker.template getModel<storm::models::AbstractModel<T>>().getInitialStates()) { - LOG4CPLUS_INFO(logger, "\t" << initialState << ": " << (result.get(initialState) ? "satisfied" : "not satisfied")); - std::cout << "\t" << initialState << ": " << result.get(initialState) << std::endl; - } + try { + if(dynamic_cast<AbstractStateFormula<T> *>(child) != nullptr) { + result = evaluate(modelchecker, dynamic_cast<AbstractStateFormula<T> *>(child)); + } else if (dynamic_cast<AbstractPathFormula<T> *>(child) != nullptr) { + result = evaluate(modelchecker, dynamic_cast<AbstractPathFormula<T> *>(child)); + } else if (dynamic_cast<AbstractRewardPathFormula<T> *>(child) != nullptr) { + result = evaluate(modelchecker, dynamic_cast<AbstractRewardPathFormula<T> *>(child)); } - + } catch (std::exception& e) { + std::cout << "Error during computation: " << e.what() << "Skipping property." << std::endl; + LOG4CPLUS_ERROR(logger, "Error during computation: " << e.what() << "Skipping property."); std::cout << std::endl << "-------------------------------------------" << std::endl; + return; } - else if (dynamic_cast<AbstractPathFormula<T>*>(child) != nullptr) { - - // Check the formula and apply the filter actions. - std::vector<T> result; - - try { - result = evaluate(modelchecker, dynamic_cast<AbstractPathFormula<T>*>(child)); - } catch (std::exception& e) { - std::cout << "Error during computation: " << e.what() << "Skipping property." << std::endl; - LOG4CPLUS_ERROR(logger, "Error during computation: " << e.what() << "Skipping property."); - std::cout << std::endl << "-------------------------------------------" << std::endl; - return; - } - - // Now write out the result. - - if(this->actions.empty()) { + writeOut(result, modelchecker); - // There is no filter action given. So provide legacy support: - // Return the results for all states labeled with "init". - LOG4CPLUS_INFO(logger, "Result for initial states:"); - std::cout << "Result for initial states:" << std::endl; - for (auto initialState : modelchecker.template getModel<storm::models::AbstractModel<T>>().getInitialStates()) { - LOG4CPLUS_INFO(logger, "\t" << initialState << ": " << result[initialState]); - std::cout << "\t" << initialState << ": " << result[initialState] << std::endl; - } - } - - std::cout << std::endl << "-------------------------------------------" << std::endl; - - } - else if (dynamic_cast<AbstractRewardPathFormula<T>*>(child) != nullptr) { - - // Check the formula and apply the filter actions. - std::vector<T> result; - - try { - result = evaluate(modelchecker, dynamic_cast<AbstractRewardPathFormula<T>*>(child)); - } catch (std::exception& e) { - std::cout << "Error during computation: " << e.what() << "Skipping property." << std::endl; - LOG4CPLUS_ERROR(logger, "Error during computation: " << e.what() << "Skipping property."); - std::cout << std::endl << "-------------------------------------------" << std::endl; - - return; - } - - // Now write out the result. - - if(this->actions.empty()) { - - // There is no filter action given. So provide legacy support: - // Return the results for all states labeled with "init". - LOG4CPLUS_INFO(logger, "Result for initial states:"); - std::cout << "Result for initial states:" << std::endl; - for (auto initialState : modelchecker.template getModel<storm::models::AbstractModel<T>>().getInitialStates()) { - LOG4CPLUS_INFO(logger, "\t" << initialState << ": " << result[initialState]); - std::cout << "\t" << initialState << ": " << result[initialState] << std::endl; - } - } - - std::cout << std::endl << "-------------------------------------------" << std::endl; - - } - else { - // This branch should be unreachable. If you ended up here, something strange has happened. - //TODO: Error here. - } - } - - bool validate() const { - // Test whether the stored filter actions are consistent in relation to themselves and to the ingoing modelchecking result. - - // Do a dynamic cast to test for the actual formula type. - if(dynamic_cast<AbstractStateFormula<T>*>(child) != nullptr) { - //TODO: Actual validation. - } - else if (dynamic_cast<AbstractPathFormula<T>*>(child) != nullptr) { - //TODO: Actual validation. - } - else { - // This branch should be unreachable. If you ended up here, something strange has happened. - //TODO: Error here. - } - - return true; } virtual std::string toString() const override { @@ -220,10 +134,10 @@ public: for(auto action : this->actions) { desc += action->toString(); - desc += ", "; + desc += "; "; } - // Remove the last ", ". + // Remove the last "; ". desc.pop_back(); desc.pop_back(); @@ -242,10 +156,10 @@ public: for(auto action : this->actions) { desc += action->toString(); - desc += ", "; + desc += "; "; } - // Remove the last ", ". + // Remove the last "; ". desc.pop_back(); desc.pop_back(); @@ -259,7 +173,7 @@ public: return desc; } - virtual std::string toPrettyString() const override{ + virtual std::string toPrettyString() const override { std::string desc = "Filter: "; desc += "\nActions:"; for(auto action : this->actions) { @@ -279,61 +193,122 @@ public: private: - storm::storage::BitVector evaluate(storm::modelchecker::prctl::AbstractModelChecker<T> const & modelchecker, AbstractStateFormula<T>* formula) const { + Result evaluate(storm::modelchecker::prctl::AbstractModelChecker<T> const & modelchecker, AbstractStateFormula<T> * formula) const { // First, get the model checking result. - storm::storage::BitVector result; + Result result; if(this->opt != UNDEFINED) { // If it is specified that min/max probabilities/rewards should be computed, call the appropriate method of the model checker. - result = modelchecker.checkOptimizingOperator(*formula, this->opt == storm::property::MINIMIZE ? true : false); + result.stateResult = modelchecker.checkOptimizingOperator(*formula, this->opt == storm::property::MINIMIZE ? true : false); } else { - result = formula->check(modelchecker); + result.stateResult = formula->check(modelchecker); } - - // Now apply all filter actions and return the result. - for(auto action : this->actions) { - result = action->evaluate(result); - } - return result; + return evaluateActions(result, modelchecker); } - std::vector<T> evaluate(storm::modelchecker::prctl::AbstractModelChecker<T> const & modelchecker, AbstractPathFormula<T>* formula) const { + Result evaluate(storm::modelchecker::prctl::AbstractModelChecker<T> const & modelchecker, AbstractPathFormula<T> * formula) const { // First, get the model checking result. - std::vector<T> result; + Result result; if(this->opt != UNDEFINED) { // If it is specified that min/max probabilities/rewards should be computed, call the appropriate method of the model checker. - result = modelchecker.checkOptimizingOperator(*formula, this->opt == storm::property::MINIMIZE ? true : false); + result.pathResult = modelchecker.checkOptimizingOperator(*formula, this->opt == storm::property::MINIMIZE ? true : false); } else { - result = formula->check(modelchecker, false); + result.pathResult = formula->check(modelchecker, false); } - // Now apply all filter actions and return the result. - for(auto action : this->actions) { - result = action->evaluate(result); - } - return result; + return evaluateActions(result, modelchecker); } - std::vector<T> evaluate(storm::modelchecker::prctl::AbstractModelChecker<T> const & modelchecker, AbstractRewardPathFormula<T>* formula) const { + Result evaluate(storm::modelchecker::prctl::AbstractModelChecker<T> const & modelchecker, AbstractRewardPathFormula<T> * formula) const { // First, get the model checking result. - std::vector<T> result; + Result result; if(this->opt != UNDEFINED) { // If it is specified that min/max probabilities/rewards should be computed, call the appropriate method of the model checker. - result = modelchecker.checkOptimizingOperator(*formula, this->opt == storm::property::MINIMIZE ? true : false); + result.pathResult = modelchecker.checkOptimizingOperator(*formula, this->opt == storm::property::MINIMIZE ? true : false); } else { - result = formula->check(modelchecker, false); + result.pathResult = formula->check(modelchecker, false); + } + + return evaluateActions(result, modelchecker); + } + + Result evaluateActions(Result result, storm::modelchecker::prctl::AbstractModelChecker<T> const & modelchecker) const { + + // Init the state selection and state map vectors. + result.selection = storm::storage::BitVector(result.stateResult.size(), true); + result.stateMap = std::vector<uint_fast64_t>(result.selection.size()); + for(uint_fast64_t i = 0; i < result.selection.size(); i++) { + result.stateMap[i] = i; } // Now apply all filter actions and return the result. for(auto action : this->actions) { - result = action->evaluate(result); + result = action->evaluate(result, modelchecker); } return result; } + + void writeOut(Result const & result, storm::modelchecker::prctl::AbstractModelChecker<T> const & modelchecker) const { + + // Test for the kind of result. Values or states. + if(!result.pathResult.empty()) { + + // Write out the selected value results in the order given by the stateMap. + if(this->actions.empty()) { + + // There is no filter action given. So provide legacy support: + // Return the results for all states labeled with "init". + LOG4CPLUS_INFO(logger, "Result for initial states:"); + std::cout << "Result for initial states:" << std::endl; + for (auto initialState : modelchecker.template getModel<storm::models::AbstractModel<T>>().getInitialStates()) { + LOG4CPLUS_INFO(logger, "\t" << initialState << ": " << result.pathResult[initialState]); + std::cout << "\t" << initialState << ": " << result.pathResult[initialState] << std::endl; + } + } else { + LOG4CPLUS_INFO(logger, "Result for " << result.selection.getNumberOfSetBits() << " selected states:"); + std::cout << "Result for " << result.selection.getNumberOfSetBits() << " selected states:" << std::endl; + + for(uint_fast64_t i = 0; i < result.stateMap.size(); i++) { + if(result.selection.get(result.stateMap[i])) { + LOG4CPLUS_INFO(logger, "\t" << result.stateMap[i] << ": " << result.pathResult[result.stateMap[i]]); + std::cout << "\t" << result.stateMap[i] << ": " << result.pathResult[result.stateMap[i]] << std::endl; + } + } + } + + } else { + + // Write out the selected state results in the order given by the stateMap. + if(this->actions.empty()) { + + // There is no filter action given. So provide legacy support: + // Return the results for all states labeled with "init". + LOG4CPLUS_INFO(logger, "Result for initial states:"); + std::cout << "Result for initial states:" << std::endl; + for (auto initialState : modelchecker.template getModel<storm::models::AbstractModel<T>>().getInitialStates()) { + LOG4CPLUS_INFO(logger, "\t" << initialState << ": " << (result.stateResult[initialState] ? "satisfied" : "not satisfied")); + std::cout << "\t" << initialState << ": " << result.stateResult[initialState] << std::endl; + } + } else { + LOG4CPLUS_INFO(logger, "Result for " << result.selection.getNumberOfSetBits() << " selected states:"); + std::cout << "Result for " << result.selection.getNumberOfSetBits() << " selected states:" << std::endl; + + for(uint_fast64_t i = 0; i < result.stateMap.size(); i++) { + if(result.selection.get(result.stateMap[i])) { + LOG4CPLUS_INFO(logger, "\t" << result.stateMap[i] << ": " << (result.stateResult[result.stateMap[i]] ? "satisfied" : "not satisfied")); + std::cout << "\t" << result.stateMap[i] << ": " << (result.stateResult[result.stateMap[i]] ? "satisfied" : "not satisfied") << std::endl; + } + } + } + } + + std::cout << std::endl << "-------------------------------------------" << std::endl; + } + AbstractPrctlFormula<T>* child; }; diff --git a/src/parser/CslParser.cpp b/src/parser/CslParser.cpp index 296deecc0..9e38a9c59 100644 --- a/src/parser/CslParser.cpp +++ b/src/parser/CslParser.cpp @@ -11,7 +11,11 @@ // The action class headers. #include "src/formula/Actions/AbstractAction.h" +#include "src/formula/Actions/BoundAction.h" +#include "src/formula/Actions/InvertAction.h" +#include "src/formula/Actions/FormulaAction.h" #include "src/formula/Actions/RangeAction.h" +#include "src/formula/Actions/SortAction.h" // If the parser fails due to ill-formed data, this exception is thrown. #include "src/exceptions/WrongFormatException.h" @@ -50,6 +54,10 @@ struct CslParser::CslGrammar : qi::grammar<Iterator, storm::property::csl::CslFi (qi::lit(">"))[qi::_val = storm::property::GREATER] | (qi::lit("<="))[qi::_val = storm::property::LESS_EQUAL] | (qi::lit("<"))[qi::_val = storm::property::LESS]); + sortingCategory = ( + (qi::lit("index"))[qi::_val = storm::property::action::SortAction<double>::INDEX] | + (qi::lit("value"))[qi::_val = storm::property::action::SortAction<double>::VALUE] + ); //Comment: Empty line or line starting with "//" comment = (qi::lit("//") >> *(qi::char_))[qi::_val = nullptr]; @@ -136,11 +144,37 @@ struct CslParser::CslGrammar : qi::grammar<Iterator, storm::property::csl::CslFi phoenix::new_<storm::property::csl::CslFilter<double>>(qi::_1, storm::property::UNDEFINED, true)]; steadyStateNoBoundOperator.name("steady state no bound operator"); - rangeAction = (qi::lit("range") >> qi::lit(",") >> qi::uint_ >> qi::lit(",") >> qi::uint_)[qi::_val = - phoenix::new_<storm::property::action::RangeAction<double>>(qi::_1, qi::_2)]; - rangeAction.name("range action for the formula filter"); + // This block defines rules for parsing filter actions. + boundAction = (qi::lit("bound") > qi::lit("(") >> comparisonType >> qi::lit(",") >> qi::double_ >> qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::action::BoundAction<double>>(qi::_1, qi::_2)]; + boundAction.name("bound action"); + + invertAction = qi::lit("invert")[qi::_val = phoenix::new_<storm::property::action::InvertAction<double>>()]; + invertAction.name("invert action"); + + formulaAction = (qi::lit("formula") > qi::lit("(") >> stateFormula >> qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::action::FormulaAction<double>>(qi::_1)]; + formulaAction.name("formula action"); + + rangeAction = ( + (qi::lit("range") >> qi::lit("(") >> qi::uint_ >> qi::lit(",") > qi::uint_ >> qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::action::RangeAction<double>>(qi::_1, qi::_2)] | + (qi::lit("range") >> qi::lit("(") >> qi::uint_ >> qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::action::RangeAction<double>>(qi::_1, qi::_1 + 1)] + ); + rangeAction.name("range action"); + + sortAction = ( + (qi::lit("sort") > qi::lit("(") >> sortingCategory >> qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::action::SortAction<double>>(qi::_1)] | + (qi::lit("sort") > qi::lit("(") >> sortingCategory >> qi::lit(", ") >> qi::lit("asc") > qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::action::SortAction<double>>(qi::_1, true)] | + (qi::lit("sort") > qi::lit("(") >> sortingCategory >> qi::lit(", ") >> qi::lit("desc") > qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::action::SortAction<double>>(qi::_1, false)] + ); + sortAction.name("sort action"); - abstractAction = (rangeAction) >> (qi::eps | qi::lit(",")); + abstractAction = (rangeAction) >> (qi::eps | qi::lit(";")); abstractAction.name("filter action"); filter = (qi::lit("filter") >> qi::lit("[") >> +abstractAction >> qi::lit("]") >> qi::lit("(") >> formula >> qi::lit(")"))[qi::_val = @@ -165,7 +199,11 @@ struct CslParser::CslGrammar : qi::grammar<Iterator, storm::property::csl::CslFi qi::rule<Iterator, storm::property::csl::CslFilter<double>*(), Skipper> steadyStateNoBoundOperator; qi::rule<Iterator, storm::property::action::AbstractAction<double>*(), Skipper> abstractAction; + qi::rule<Iterator, storm::property::action::BoundAction<double>*(), Skipper> boundAction; + qi::rule<Iterator, storm::property::action::InvertAction<double>*(), Skipper> invertAction; + qi::rule<Iterator, storm::property::action::FormulaAction<double>*(), Skipper> formulaAction; qi::rule<Iterator, storm::property::action::RangeAction<double>*(), Skipper> rangeAction; + qi::rule<Iterator, storm::property::action::SortAction<double>*(), Skipper> sortAction; qi::rule<Iterator, storm::property::csl::AbstractCslFormula<double>*(), Skipper> formula; qi::rule<Iterator, storm::property::csl::AbstractCslFormula<double>*(), Skipper> comment; @@ -191,6 +229,7 @@ struct CslParser::CslGrammar : qi::grammar<Iterator, storm::property::csl::CslFi qi::rule<Iterator, std::string(), Skipper> freeIdentifierName; qi::rule<Iterator, storm::property::ComparisonType(), Skipper> comparisonType; + qi::rule<Iterator, storm::property::action::SortAction<double>::SortingCategory(), Skipper> sortingCategory; }; diff --git a/src/parser/PrctlParser.cpp b/src/parser/PrctlParser.cpp index 49bfe281b..0fb8b538a 100644 --- a/src/parser/PrctlParser.cpp +++ b/src/parser/PrctlParser.cpp @@ -4,7 +4,11 @@ // The action class headers. #include "src/formula/Actions/AbstractAction.h" +#include "src/formula/Actions/BoundAction.h" +#include "src/formula/Actions/InvertAction.h" +#include "src/formula/Actions/FormulaAction.h" #include "src/formula/Actions/RangeAction.h" +#include "src/formula/Actions/SortAction.h" // If the parser fails due to ill-formed data, this exception is thrown. #include "src/exceptions/WrongFormatException.h" @@ -38,17 +42,21 @@ namespace parser { template<typename Iterator, typename Skipper> struct PrctlParser::PrctlGrammar : qi::grammar<Iterator, storm::property::prctl::PrctlFilter<double>*(), Skipper > { PrctlGrammar() : PrctlGrammar::base_type(start) { - //This block contains helper rules that may be used several times + // This block contains helper rules that may be used several times freeIdentifierName = qi::lexeme[qi::alpha >> *(qi::alnum | qi::char_('_'))]; comparisonType = ( (qi::lit(">="))[qi::_val = storm::property::GREATER_EQUAL] | (qi::lit(">"))[qi::_val = storm::property::GREATER] | (qi::lit("<="))[qi::_val = storm::property::LESS_EQUAL] | (qi::lit("<"))[qi::_val = storm::property::LESS]); - //Comment: Empty line or line starting with "//" + sortingCategory = ( + (qi::lit("index"))[qi::_val = storm::property::action::SortAction<double>::INDEX] | + (qi::lit("value"))[qi::_val = storm::property::action::SortAction<double>::VALUE] + ); + // Comment: Empty line or line starting with "//" comment = (qi::lit("//") >> *(qi::char_))[qi::_val = nullptr]; - //This block defines rules for parsing state formulas + // This block defines rules for parsing state formulas stateFormula %= orFormula; stateFormula.name("state formula"); orFormula = andFormula[qi::_val = qi::_1] > *(qi::lit("|") > andFormula)[qi::_val = @@ -61,8 +69,8 @@ struct PrctlParser::PrctlGrammar : qi::grammar<Iterator, storm::property::prctl: phoenix::new_<storm::property::prctl::Not<double>>(qi::_1)]; notFormula.name("not formula"); - //This block defines rules for "atomic" state formulas - //(Propositions, probabilistic/reward formulas, and state formulas in brackets) + // This block defines rules for "atomic" state formulas + // (Propositions, probabilistic/reward formulas, and state formulas in brackets) atomicStateFormula %= probabilisticBoundOperator | rewardBoundOperator | atomicProposition | qi::lit("(") >> stateFormula >> qi::lit(")") | qi::lit("[") >> stateFormula >> qi::lit("]"); atomicStateFormula.name("atomic state formula"); atomicProposition = (freeIdentifierName)[qi::_val = @@ -76,7 +84,7 @@ struct PrctlParser::PrctlGrammar : qi::grammar<Iterator, storm::property::prctl: phoenix::new_<storm::property::prctl::RewardBoundOperator<double> >(qi::_1, qi::_2, qi::_3)]); rewardBoundOperator.name("reward bound operator"); - //This block defines rules for parsing probabilistic path formulas + // This block defines rules for parsing probabilistic path formulas pathFormula = (boundedEventually | eventually | next | globally | boundedUntil | until | qi::lit("(") >> pathFormula >> qi::lit(")") | qi::lit("[") >> pathFormula >> qi::lit("]")); pathFormula.name("path formula"); boundedEventually = (qi::lit("F") >> qi::lit("<=") > qi::int_ > stateFormula)[qi::_val = @@ -98,7 +106,7 @@ struct PrctlParser::PrctlGrammar : qi::grammar<Iterator, storm::property::prctl: phoenix::new_<storm::property::prctl::Until<double>>(phoenix::bind(&storm::property::prctl::AbstractStateFormula<double>::clone, phoenix::bind(&std::shared_ptr<storm::property::prctl::AbstractStateFormula<double>>::get, qi::_a)), qi::_2)]; until.name("path formula (for probabilistic operator)"); - //This block defines rules for parsing reward path formulas + // This block defines rules for parsing reward path formulas. rewardPathFormula = (cumulativeReward | reachabilityReward | instantaneousReward | steadyStateReward | qi::lit("(") >> rewardPathFormula >> qi::lit(")") | qi::lit("[") >> rewardPathFormula >> qi::lit("]")); rewardPathFormula.name("path formula (for reward operator)"); cumulativeReward = (qi::lit("C") > qi::lit("<=") > qi::double_)[qi::_val = @@ -115,9 +123,9 @@ struct PrctlParser::PrctlGrammar : qi::grammar<Iterator, storm::property::prctl: formula = (pathFormula | stateFormula); formula.name("PRCTL formula"); - //This block defines rules for parsing formulas with noBoundOperators - //Note that this is purely for legacy support. - //NoBoundOperators are no longer part of the formula tree and are therefore deprecated. + // This block defines rules for parsing formulas with noBoundOperators. + // Note that this is purely for legacy support. + // NoBoundOperators are no longer part of the formula tree and are therefore deprecated. noBoundOperator = (probabilisticNoBoundOperator | rewardNoBoundOperator); noBoundOperator.name("no bound operator"); probabilisticNoBoundOperator = ( @@ -141,15 +149,46 @@ struct PrctlParser::PrctlGrammar : qi::grammar<Iterator, storm::property::prctl: ); rewardNoBoundOperator.name("no bound operator"); - rangeAction = (qi::lit("range") >> qi::lit(",") >> qi::uint_ >> qi::lit(",") >> qi::uint_)[qi::_val = - phoenix::new_<storm::property::action::RangeAction<double>>(qi::_1, qi::_2)]; - rangeAction.name("range action for the formula filter"); - abstractAction = (rangeAction) >> (qi::eps | qi::lit(",")); + // This block defines rules for parsing filter actions. + boundAction = (qi::lit("bound") > qi::lit("(") >> comparisonType >> qi::lit(",") >> qi::double_ >> qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::action::BoundAction<double>>(qi::_1, qi::_2)]; + boundAction.name("bound action"); + + invertAction = qi::lit("invert")[qi::_val = phoenix::new_<storm::property::action::InvertAction<double>>()]; + invertAction.name("invert action"); + + formulaAction = (qi::lit("formula") > qi::lit("(") >> stateFormula >> qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::action::FormulaAction<double>>(qi::_1)]; + formulaAction.name("formula action"); + + rangeAction = ( + (qi::lit("range") >> qi::lit("(") >> qi::uint_ >> qi::lit(",") > qi::uint_ >> qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::action::RangeAction<double>>(qi::_1, qi::_2)] | + (qi::lit("range") >> qi::lit("(") >> qi::uint_ >> qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::action::RangeAction<double>>(qi::_1, qi::_1 + 1)] + ); + rangeAction.name("range action"); + + sortAction = ( + (qi::lit("sort") > qi::lit("(") >> sortingCategory >> qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::action::SortAction<double>>(qi::_1)] | + (qi::lit("sort") > qi::lit("(") >> sortingCategory >> qi::lit(", ") >> qi::lit("asc") > qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::action::SortAction<double>>(qi::_1, true)] | + (qi::lit("sort") > qi::lit("(") >> sortingCategory >> qi::lit(", ") >> qi::lit("desc") > qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::action::SortAction<double>>(qi::_1, false)] + ); + sortAction.name("sort action"); + + abstractAction = (rangeAction) >> (qi::eps | qi::lit(";")); abstractAction.name("filter action"); - filter = (qi::lit("filter") > qi::lit("[") >> +abstractAction >> qi::lit("]") >> qi::lit("(") >> formula >> qi::lit(")"))[qi::_val = + filter = (qi::lit("filter") >> qi::lit("[") >> +abstractAction >> qi::lit("]") > qi::lit("(") >> formula >> qi::lit(")"))[qi::_val = phoenix::new_<storm::property::prctl::PrctlFilter<double>>(qi::_2, qi::_1)] | + (qi::lit("filter") >> qi::lit("[") >> qi::lit("max") > +abstractAction >> qi::lit("]") >> qi::lit("(") >> formula >> qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::prctl::PrctlFilter<double>>(qi::_2, qi::_1, storm::property::MAXIMIZE)] | + (qi::lit("filter") >> qi::lit("[") >> qi::lit("min") > +abstractAction >> qi::lit("]") >> qi::lit("(") >> formula >> qi::lit(")"))[qi::_val = + phoenix::new_<storm::property::prctl::PrctlFilter<double>>(qi::_2, qi::_1, storm::property::MINIMIZE)] | (noBoundOperator)[qi::_val = qi::_1] | (formula)[qi::_val = @@ -169,7 +208,11 @@ struct PrctlParser::PrctlGrammar : qi::grammar<Iterator, storm::property::prctl: qi::rule<Iterator, storm::property::prctl::PrctlFilter<double>*(), Skipper> rewardNoBoundOperator; qi::rule<Iterator, storm::property::action::AbstractAction<double>*(), Skipper> abstractAction; + qi::rule<Iterator, storm::property::action::BoundAction<double>*(), Skipper> boundAction; + qi::rule<Iterator, storm::property::action::InvertAction<double>*(), Skipper> invertAction; + qi::rule<Iterator, storm::property::action::FormulaAction<double>*(), Skipper> formulaAction; qi::rule<Iterator, storm::property::action::RangeAction<double>*(), Skipper> rangeAction; + qi::rule<Iterator, storm::property::action::SortAction<double>*(), Skipper> sortAction; qi::rule<Iterator, storm::property::prctl::AbstractPrctlFormula<double>*(), Skipper> formula; qi::rule<Iterator, storm::property::prctl::AbstractPrctlFormula<double>*(), Skipper> comment; @@ -201,6 +244,7 @@ struct PrctlParser::PrctlGrammar : qi::grammar<Iterator, storm::property::prctl: qi::rule<Iterator, std::string(), Skipper> freeIdentifierName; qi::rule<Iterator, storm::property::ComparisonType(), Skipper> comparisonType; + qi::rule<Iterator, storm::property::action::SortAction<double>::SortingCategory(), Skipper> sortingCategory; };