diff --git a/src/formula/Actions/FormulaAction.h b/src/formula/Actions/FormulaAction.h new file mode 100644 index 000000000..805bc1acb --- /dev/null +++ b/src/formula/Actions/FormulaAction.h @@ -0,0 +1,103 @@ +/* + * PrctlFormulaAction.h + * + * Created on: Jun 6, 2014 + * Author: Manuel Sascha Weiand + */ + +#ifndef STORM_FORMULA_ACTION_FORMULAACTION_H_ +#define STORM_FORMULA_ACTION_FORMULAACTION_H_ + +#include "src/formula/Actions/AbstractAction.h" +#include "src/formula/Prctl/AbstractStateFormula.h" + + +#include + +namespace storm { +namespace property { +namespace action { + +template +class FormulaAction : public AbstractAction { + + typedef typename AbstractAction::Result Result; + +public: + + FormulaAction(storm::property::prctl::AbstractStateFormula* prctlFormula) : prctlFormula(prctlFormula), cslFormula(nullptr) { + //Intentionally left empty. + } + + FormulaAction(storm::property::csl::AbstractStateFormula* cslFormula) : prctlFormula(nullptr), cslFormula(cslFormula) { + //Intentionally left empty. + } + + /*! + * Virtual destructor + * To ensure that the right destructor is called + */ + virtual ~FormulaAction() { + if(prctlFormula != nullptr) { + delete prctlFormula; + } + if(cslFormula != nullptr) { + delete cslFormula; + } + } + + /*! + * + */ + virtual Result evaluate(Result const & result, storm::modelchecker::prctl::AbstractModelChecker const & mc) const override { + + storm::storage::BitVector selection(result.selection); + + //Compute the modelchecking results of the actions state formula and deselect all states that do not satisfy it. + if(prctlFormula != nullptr) { + selection = selection & prctlFormula->check(mc); + } + + return Result(selection, result.stateMap, result.pathResult, result.stateResult); + } + + /*! + * + */ + virtual Result evaluate(Result const & result, storm::modelchecker::csl::AbstractModelChecker const & mc) const override { + + storm::storage::BitVector selection(result.selection); + + //Compute the modelchecking results of the actions state formula and deselect all states that do not satisfy it. + if(cslFormula != nullptr) { + selection = selection & cslFormula->check(mc); + } + + return Result(selection, result.stateMap, result.pathResult, result.stateResult); + } + + /*! + * + */ + virtual std::string toString() const override { + std::string out = "states("; + if(prctlFormula != nullptr) { + out += prctlFormula->toString(); + } else if(cslFormula != nullptr) { + out += cslFormula->toString(); + } + out += ")"; + return out; + } + +private: + storm::property::prctl::AbstractStateFormula* prctlFormula; + storm::property::csl::AbstractStateFormula* cslFormula; + +}; + +} //namespace action +} //namespace property +} //namespace storm + +#endif /* STORM_FORMULA_ACTION_FORMULAACTION_H_ */ diff --git a/src/formula/Csl/CslFilter.h b/src/formula/Csl/CslFilter.h index ae5c256d9..928163fbd 100644 --- a/src/formula/Csl/CslFilter.h +++ b/src/formula/Csl/CslFilter.h @@ -14,6 +14,16 @@ #include "src/formula/Csl/AbstractStateFormula.h" #include "src/modelchecker/csl/AbstractModelChecker.h" +#include "src/formula/Actions/AbstractAction.h" + +namespace storm { +namespace property { +namespace action { + template class AbstractAction; +} +} +} + namespace storm { namespace property { namespace csl { @@ -21,6 +31,8 @@ namespace csl { template class CslFilter : public storm::property::AbstractFilter { + typedef typename storm::property::action::AbstractAction::Result Result; + public: CslFilter() : AbstractFilter(UNDEFINED), child(nullptr), steadyStateQuery(false) { @@ -44,82 +56,31 @@ public: delete child; } - void check(storm::modelchecker::csl::AbstractModelChecker const & modelchecker) const { + void check(storm::modelchecker::prctl::AbstractModelChecker const & modelchecker) const { // Write out the formula to be checked. std::cout << std::endl; - LOG4CPLUS_INFO(logger, "Model checking formula\t" << this->toFormulaString()); - std::cout << "Model checking formula:\t" << this->toFormulaString() << std::endl; + 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*>(child) != nullptr) { + Result result; - // Check the formula and apply the filter actions. - storm::storage::BitVector result; - - try { - result = evaluate(modelchecker, static_cast*>(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; + try { + if(dynamic_cast *>(child) != nullptr) { + result = evaluate(modelchecker, dynamic_cast *>(child)); + } else if (dynamic_cast *>(child) != nullptr) { + result = evaluate(modelchecker, dynamic_cast *>(child)); } - - // 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.getModel().getInitialStates()) { - LOG4CPLUS_INFO(logger, "\t" << initialState << ": " << (result.get(initialState) ? "satisfied" : "not satisfied")); - std::cout << "\t" << initialState << ": " << result.get(initialState) << std::endl; - } - } - + } 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*>(child) != nullptr) { - - // Check the formula and apply the filter actions. - std::vector result; - try { - result = evaluate(modelchecker, static_cast*>(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; + writeOut(result, modelchecker); - 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.getModel().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. - } } virtual std::string toString() const override { @@ -242,10 +203,7 @@ private: // 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 evaluate(storm::modelchecker::csl::AbstractModelChecker const & modelchecker, AbstractPathFormula* formula) const { @@ -259,13 +217,83 @@ private: result = formula->check(modelchecker, false); } + // Now apply all filter actions and return the result. + return evaluateActions(result, modelchecker); + } + + Result evaluateActions(Result result, storm::modelchecker::csl::AbstractModelChecker const & modelchecker) const { + + // Init the state selection and state map vectors. + result.selection = storm::storage::BitVector(result.stateResult.size(), true); + result.stateMap = std::vector(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 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>().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>().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; + } + AbstractCslFormula* child; bool steadyStateQuery; diff --git a/src/formula/Ltl/LtlFilter.h b/src/formula/Ltl/LtlFilter.h index cbc31f71b..96fac586c 100644 --- a/src/formula/Ltl/LtlFilter.h +++ b/src/formula/Ltl/LtlFilter.h @@ -10,6 +10,17 @@ #include "src/formula/AbstractFilter.h" #include "src/modelchecker/ltl/AbstractModelChecker.h" +#include "src/formula/Ltl/AbstractLtlFormula.h" +#include "src/formula/Actions/AbstractAction.h" +#include "src/exceptions/NotImplementedException.h" + +namespace storm { +namespace property { +namespace action { + template class AbstractAction; +} +} +} namespace storm { namespace property { @@ -18,21 +29,23 @@ namespace ltl { template class LtlFilter : public storm::property::AbstractFilter { + typedef typename storm::property::action::AbstractAction::Result Result; + public: - LtlFilter() : child(nullptr) { + LtlFilter() : AbstractFilter(UNDEFINED), child(nullptr) { // Intentionally left empty. } - LtlFilter(AbstractLtlFormula* child) : child(child) { + LtlFilter(AbstractLtlFormula* child, OptimizingOperator opt = UNDEFINED) : AbstractFilter(opt), child(child) { // Intentionally left empty. } - LtlFilter(AbstractLtlFormula* child, action::Action* action) : child(child) { + LtlFilter(AbstractLtlFormula* child, action::AbstractAction* action, OptimizingOperator opt = UNDEFINED) : AbstractFilter(action, opt), child(child) { this->actions.push_back(action); } - LtlFilter(AbstractLtlFormula* child, std::vector*> actions) : AbstractFilter(actions), child(child) { + LtlFilter(AbstractLtlFormula* child, std::vector*> actions, OptimizingOperator opt = UNDEFINED) : AbstractFilter(actions, opt), child(child) { // Intentionally left empty. } @@ -52,15 +65,13 @@ public: // Write out the formula to be checked. std::cout << std::endl; - LOG4CPLUS_INFO(logger, "Model checking formula\t" << this->toFormulaString()); - std::cout << "Model checking formula:\t" << this->toFormulaString() << std::endl; + LOG4CPLUS_INFO(logger, "Model checking formula\t" << this->toString()); + std::cout << "Model checking formula:\t" << this->toString() << std::endl; - - // Check the formula and apply the filter actions. - storm::storage::BitVector result; + Result result; try { - result = evaluate(modelchecker, child); + result = evaluate(modelchecker); } 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."); @@ -69,41 +80,54 @@ public: return; } - // Now write out the result. + writeOut(result, modelchecker); - 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.getModel>().getInitialStates()) { - LOG4CPLUS_INFO(logger, "\t" << initialState << ": " << (result.get(initialState) ? "satisfied" : "not satisfied")); - std::cout << "\t" << initialState << ": " << result.get(initialState) << std::endl; - } + std::string toString() const override { + std::string desc = ""; + + if(this->actions.empty()){ + // There are no filter actions but only the raw state formula. So just print that. + return child->toString(); } - std::cout << std::endl << "-------------------------------------------" << std::endl; - } + desc = "filter["; + + switch(this->opt) { + case MINIMIZE: + desc += " min, "; + break; + case MAXIMIZE: + desc += " max, "; + break; + default: + break; + } - bool validate() const { - // Test whether the stored filter actions are consistent in relation to themselves and to the ingoing modelchecking result. + for(auto action : this->actions) { + desc += action->toString(); + desc += "; "; + } - //TODO: Actual validation. + // Remove the last "; ". + desc.pop_back(); + desc.pop_back(); - return true; - } + desc += "]"; + + desc += "("; + desc += child->toString(); + desc += ")"; - std::string toFormulaString() const { - std::string desc = "filter("; return desc; } - std::string toString() const { + virtual std::string toPrettyString() const override { std::string desc = "Filter: "; desc += "\nActions:"; for(auto action : this->actions) { - desc += "\n\t" + action.toString(); + desc += "\n\t" + action->toString(); } desc += "\nFormula:\n\t" + child->toString(); return desc; @@ -119,17 +143,71 @@ public: private: - storm::storage::BitVector evaluate(storm::modelchecker::ltl::AbstractModelChecker const & modelchecker, AbstractLtlFormula* formula) const { + Result evaluate(storm::modelchecker::ltl::AbstractModelChecker const & modelchecker) const { // First, get the model checking result. - storm::storage::BitVector result = formula->check(modelchecker); + 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. + LOG4CPLUS_ERROR(logger, "Calculation of minimizing and maximizing schedulers for LTL-formula model checking is not yet implemented."); + throw storm::exceptions::NotImplementedException() << "Calculation of minimizing and maximizing schedulers for LTL-formula model checking is not yet implemented."; + } else { + result.stateResult = child->check(modelchecker); + } + + // Now apply all filter actions and return the result. + + // Init the state selection and state map vectors. + result.selection = storm::storage::BitVector(result.stateResult.size(), true); + result.stateMap = std::vector(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::ltl::AbstractModelChecker 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>().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 { + LOG4CPLUS_WARN(logger, "No results could be computed."); + std::cout << "No results could be computed." << std::endl; + } + + std::cout << std::endl << "-------------------------------------------" << std::endl; + } + AbstractLtlFormula* child; }; diff --git a/src/formula/Prctl/PrctlFilter.h b/src/formula/Prctl/PrctlFilter.h index 77a8c35f7..395337b9a 100644 --- a/src/formula/Prctl/PrctlFilter.h +++ b/src/formula/Prctl/PrctlFilter.h @@ -15,6 +15,7 @@ #include "src/modelchecker/prctl/AbstractModelChecker.h" #include "src/formula/Actions/AbstractAction.h" +// TODO: Test if this can be can be ommitted. namespace storm { namespace property { namespace action { @@ -204,6 +205,7 @@ private: result.stateResult = formula->check(modelchecker); } + // Now apply all filter actions and return the result. return evaluateActions(result, modelchecker); } @@ -218,6 +220,7 @@ private: result.pathResult = formula->check(modelchecker, false); } + // Now apply all filter actions and return the result. return evaluateActions(result, modelchecker); } @@ -232,6 +235,7 @@ private: result.pathResult = formula->check(modelchecker, false); } + // Now apply all filter actions and return the result. return evaluateActions(result, modelchecker); } diff --git a/src/parser/CslParser.cpp b/src/parser/CslParser.cpp index 9e38a9c59..f7b11dd14 100644 --- a/src/parser/CslParser.cpp +++ b/src/parser/CslParser.cpp @@ -174,7 +174,7 @@ struct CslParser::CslGrammar : qi::grammar> (qi::eps | qi::lit(";")); + abstractAction = (boundAction | invertAction | formulaAction | rangeAction | sortAction) >> (qi::eps | qi::lit(";")); abstractAction.name("filter action"); filter = (qi::lit("filter") >> qi::lit("[") >> +abstractAction >> qi::lit("]") >> qi::lit("(") >> formula >> qi::lit(")"))[qi::_val = @@ -186,7 +186,7 @@ struct CslParser::CslGrammar : qi::grammar (comment | qi::eps))[qi::_val = qi::_1] | comment ) > qi::eoi; + start = (((filter) > (comment | qi::eps))[qi::_val = qi::_1] | comment[qi::_val = nullptr] ) > qi::eoi; start.name("CSL formula filter start"); } diff --git a/src/parser/LtlFileParser.cpp b/src/parser/LtlFileParser.cpp index a53557b89..d3d9459ae 100644 --- a/src/parser/LtlFileParser.cpp +++ b/src/parser/LtlFileParser.cpp @@ -15,7 +15,7 @@ namespace storm { namespace parser { -std::list*> LtlFileParser(std::string filename) { +std::list*> LtlFileParser(std::string filename) { // Open file std::ifstream inputFileStream(filename, std::ios::in); @@ -24,7 +24,7 @@ std::list*> LtlFileParser(std:: throw storm::exceptions::FileIoException() << message << filename; } - std::list*> result; + std::list*> result; while(!inputFileStream.eof()) { std::string line; diff --git a/src/parser/LtlFileParser.h b/src/parser/LtlFileParser.h index cb187a82f..7c30abc11 100644 --- a/src/parser/LtlFileParser.h +++ b/src/parser/LtlFileParser.h @@ -9,6 +9,7 @@ #define LTLFILEPARSER_H_ #include "formula/Ltl.h" +#include "src/formula/Ltl/LtlFilter.h" #include @@ -21,7 +22,7 @@ namespace parser { * @param filename * @return The list of parsed formulas */ -std::list*> LtlFileParser(std::string filename); +std::list*> LtlFileParser(std::string filename); } //namespace parser } //namespace storm diff --git a/src/parser/LtlParser.cpp b/src/parser/LtlParser.cpp index 5083837b9..6c4787fee 100644 --- a/src/parser/LtlParser.cpp +++ b/src/parser/LtlParser.cpp @@ -10,6 +10,13 @@ #include "src/utility/OsDetection.h" #include "src/utility/constants.h" +// 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/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" @@ -41,18 +48,27 @@ namespace storm { namespace parser { template -struct LtlGrammar : qi::grammar*(), Skipper > { +struct LtlGrammar : qi::grammar*(), Skipper > { LtlGrammar() : LtlGrammar::base_type(start) { //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]); + sortingCategory = ( + (qi::lit("index"))[qi::_val = storm::property::action::SortAction::INDEX] | + (qi::lit("value"))[qi::_val = storm::property::action::SortAction::VALUE] + ); //Comment: Empty line or line starting with "//" comment = (qi::lit("//") >> *(qi::char_))[qi::_val = nullptr]; freeIdentifierName = qi::lexeme[+(qi::alpha | qi::char_('_'))]; //This block defines rules for parsing state formulas - ltlFormula %= orFormula; - ltlFormula.name("LTL formula"); + formula %= orFormula; + formula.name("LTL formula"); orFormula = andFormula[qi::_val = qi::_1] > *(qi::lit("|") > andFormula)[qi::_val = phoenix::new_>(qi::_val, qi::_1)]; orFormula.name("LTL formula"); @@ -68,7 +84,7 @@ struct LtlGrammar : qi::grammar> ltlFormula >> qi::lit(")"); + atomicLtlFormula %= pathFormula | atomicProposition | qi::lit("(") >> formula >> qi::lit(")"); atomicLtlFormula.name("LTL formula"); atomicProposition = (freeIdentifierName)[qi::_val = phoenix::new_>(qi::_1)]; @@ -77,29 +93,73 @@ struct LtlGrammar : qi::grammar> qi::lit("<=") > qi::int_ > ltlFormula)[qi::_val = + boundedEventually = (qi::lit("F") >> qi::lit("<=") > qi::int_ > formula)[qi::_val = phoenix::new_>(qi::_2, qi::_1)]; boundedEventually.name("LTL formula"); - eventually = (qi::lit("F") >> ltlFormula)[qi::_val = + eventually = (qi::lit("F") >> formula)[qi::_val = phoenix::new_ >(qi::_1)]; eventually.name("LTL formula"); - globally = (qi::lit("G") >> ltlFormula)[qi::_val = + globally = (qi::lit("G") >> formula)[qi::_val = phoenix::new_ >(qi::_1)]; globally.name("LTL formula"); - next = (qi::lit("X") >> ltlFormula)[qi::_val = + next = (qi::lit("X") >> formula)[qi::_val = phoenix::new_ >(qi::_1)]; next.name("LTL formula"); - start = (((ltlFormula) > (comment | qi::eps))[qi::_val = qi::_1] | - comment - ) > qi::eoi; + // 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_>(qi::_1, qi::_2)]; + boundAction.name("bound action"); + + invertAction = qi::lit("invert")[qi::_val = phoenix::new_>()]; + invertAction.name("invert action"); + + rangeAction = ( + (qi::lit("range") >> qi::lit("(") >> qi::uint_ >> qi::lit(",") > qi::uint_ >> qi::lit(")"))[qi::_val = + phoenix::new_>(qi::_1, qi::_2)] | + (qi::lit("range") >> qi::lit("(") >> qi::uint_ >> qi::lit(")"))[qi::_val = + phoenix::new_>(qi::_1, qi::_1 + 1)] + ); + rangeAction.name("range action"); + + sortAction = ( + (qi::lit("sort") > qi::lit("(") >> sortingCategory >> qi::lit(")"))[qi::_val = + phoenix::new_>(qi::_1)] | + (qi::lit("sort") > qi::lit("(") >> sortingCategory >> qi::lit(", ") >> qi::lit("asc") > qi::lit(")"))[qi::_val = + phoenix::new_>(qi::_1, true)] | + (qi::lit("sort") > qi::lit("(") >> sortingCategory >> qi::lit(", ") >> qi::lit("desc") > qi::lit(")"))[qi::_val = + phoenix::new_>(qi::_1, false)] + ); + sortAction.name("sort action"); + + abstractAction = (boundAction | invertAction | rangeAction | sortAction) >> (qi::eps | qi::lit(";")); + abstractAction.name("filter action"); + + filter = (qi::lit("filter") >> qi::lit("[") >> +abstractAction >> qi::lit("]") > qi::lit("(") >> formula >> qi::lit(")"))[qi::_val = + phoenix::new_>(qi::_2, qi::_1)] | + (qi::lit("filter") >> qi::lit("[") >> qi::lit("max") > +abstractAction >> qi::lit("]") >> qi::lit("(") >> formula >> qi::lit(")"))[qi::_val = + phoenix::new_>(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_>(qi::_2, qi::_1, storm::property::MINIMIZE)] | + (formula)[qi::_val = + phoenix::new_>(qi::_1)]; + filter.name("PRCTL formula filter"); + + start = (((filter) > (comment | qi::eps))[qi::_val = qi::_1] | comment[qi::_val = nullptr] ) > qi::eoi; start.name("LTL formula"); } - qi::rule*(), Skipper> start; - qi::rule*(), Skipper> comment; + qi::rule*(), Skipper> start; + qi::rule*(), Skipper> filter; + + qi::rule*(), Skipper> abstractAction; + qi::rule*(), Skipper> boundAction; + qi::rule*(), Skipper> invertAction; + qi::rule*(), Skipper> rangeAction; + qi::rule*(), Skipper> sortAction; - qi::rule*(), Skipper> ltlFormula; + qi::rule*(), Skipper> comment; + qi::rule*(), Skipper> formula; qi::rule*(), Skipper> atomicLtlFormula; qi::rule*(), Skipper> andFormula; @@ -107,10 +167,6 @@ struct LtlGrammar : qi::grammar*(), Skipper> atomicProposition; qi::rule*(), Skipper> orFormula; qi::rule*(), Skipper> notFormula; - //qi::rule*(), Skipper> probabilisticBoundOperator; - - //qi::rule*(), Skipper> noBoundOperator; - //qi::rule*(), Skipper> probabilisticNoBoundOperator; qi::rule*(), Skipper> pathFormula; qi::rule*(), Skipper> boundedEventually; @@ -121,6 +177,8 @@ struct LtlGrammar : qi::grammar*(), qi::locals< std::shared_ptr>>, Skipper> until; qi::rule freeIdentifierName; + qi::rule comparisonType; + qi::rule::SortingCategory(), Skipper> sortingCategory; }; @@ -128,7 +186,7 @@ struct LtlGrammar : qi::grammar* storm::parser::LtlParser(std::string formulaString) { +storm::property::ltl::LtlFilter* storm::parser::LtlParser(std::string formulaString) { // Prepare iterators to input. BaseIteratorType stringIteratorBegin = formulaString.begin(); BaseIteratorType stringIteratorEnd = formulaString.end(); @@ -137,7 +195,7 @@ storm::property::ltl::AbstractLtlFormula* storm::parser::LtlParser(std:: // Prepare resulting intermediate representation of input. - storm::property::ltl::AbstractLtlFormula* result_pointer = nullptr; + storm::property::ltl::LtlFilter* result_pointer = nullptr; LtlGrammar grammar; diff --git a/src/parser/LtlParser.h b/src/parser/LtlParser.h index cefcd8f2c..bbf10d259 100644 --- a/src/parser/LtlParser.h +++ b/src/parser/LtlParser.h @@ -9,6 +9,7 @@ #define STORM_PARSER_LTLPARSER_H_ #include "src/formula/Ltl.h" +#include "src/formula/Ltl/LtlFilter.h" namespace storm { namespace parser { @@ -22,7 +23,7 @@ namespace parser { * @param formulaString The string representation of the formula * @throw wrongFormatException If the input could not be parsed successfully */ -storm::property::ltl::AbstractLtlFormula* LtlParser(std::string formulaString); +storm::property::ltl::LtlFilter* LtlParser(std::string formulaString); /*! * Struct for the Ltl grammar, that Boost::Spirit uses to parse the formulas. diff --git a/src/parser/PrctlParser.cpp b/src/parser/PrctlParser.cpp index 0fb8b538a..7675f1cd3 100644 --- a/src/parser/PrctlParser.cpp +++ b/src/parser/PrctlParser.cpp @@ -180,7 +180,7 @@ struct PrctlParser::PrctlGrammar : qi::grammar> (qi::eps | qi::lit(";")); + abstractAction = (boundAction | invertAction | formulaAction | rangeAction | sortAction) >> (qi::eps | qi::lit(";")); abstractAction.name("filter action"); filter = (qi::lit("filter") >> qi::lit("[") >> +abstractAction >> qi::lit("]") > qi::lit("(") >> formula >> qi::lit(")"))[qi::_val =