diff --git a/include/aidge/graphRegex/GraphParser.hpp b/include/aidge/graphRegex/GraphParser.hpp index 06d098e995933e223146c37567f8d6895340e47d..018be1e44304f6189d1a0eb105fc4d8d1500a928 100644 --- a/include/aidge/graphRegex/GraphParser.hpp +++ b/include/aidge/graphRegex/GraphParser.hpp @@ -21,7 +21,7 @@ class GraphParser{ */ GraphParser(const std::string gRegexExpressions); - virtual ~GraphParser(); + virtual ~GraphParser() = default; /** * @brief AST graph creation function diff --git a/include/aidge/graphRegex/GraphStrInterpreter.hpp b/include/aidge/graphRegex/GraphStrInterpreter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a1fb5c2e2f4877179b07a7c7942da223247500ad --- /dev/null +++ b/include/aidge/graphRegex/GraphStrInterpreter.hpp @@ -0,0 +1,40 @@ +#ifndef __AIDGE_GRAPH_FSM_INTERPRETER_H__ +#define __AIDGE_GRAPH_FSM_INTERPRETER_H__ + +#include <iostream> +#include <sstream> +#include <memory> +#include <algorithm> + +#include "aidge/utilsParsing/AstNode.hpp" +#include "aidge/graphRegex/GraphRegexTypes.hpp" +#include "aidge/graphRegex/GraphParser.hpp" +#include "aidge/graphRegex/matchFsm/FsmGraph.hpp" + +namespace Aidge { + + class GraphStrInterpreter + { + private: + /* data */ + GraphParser mParser; + std::string mToTest; + public: + GraphStrInterpreter(const std::string graphMatchExpr); + virtual ~GraphStrInterpreter() =default; + + + std::string interpret(void); + + private: + + + std::string visit(std::shared_ptr<AstNode<gRegexTokenTypes>> AstTree); + }; + + + +} + + +#endif //__AIDGE_GRAPH_STM_INTERPRETER_H__ \ No newline at end of file diff --git a/include/aidge/graphRegex/matchFsm/FsmGraph.hpp b/include/aidge/graphRegex/matchFsm/FsmGraph.hpp index d6ef8742d0a5a59947ad713d5dde0aebdd592796..94eafd051dab065be917446ee4b8ad60207b1c57 100644 --- a/include/aidge/graphRegex/matchFsm/FsmGraph.hpp +++ b/include/aidge/graphRegex/matchFsm/FsmGraph.hpp @@ -24,7 +24,7 @@ private: std::set<std::shared_ptr<FsmEdge>> mEdges; public: FsmGraph(/* args */); - virtual ~FsmGraph();// = default; + virtual ~FsmGraph() = default; std::shared_ptr<MatchResult> test(std::vector<NodePtr>& StartNodes); diff --git a/include/aidge/graphRegex/matchFsm/FsmNode.hpp b/include/aidge/graphRegex/matchFsm/FsmNode.hpp index 6a31c20fbbb98a51536dde4e217def22953372d2..18b78fe89cbcc480132c9b42859c5578123eda2f 100644 --- a/include/aidge/graphRegex/matchFsm/FsmNode.hpp +++ b/include/aidge/graphRegex/matchFsm/FsmNode.hpp @@ -57,7 +57,7 @@ namespace Aidge{ public: FsmNode(bool isAValid,bool isAStart ); - virtual ~FsmNode();// = default; + virtual ~FsmNode() = default; /** * @brief use to MAG the actual context , and return all the posible new context * @details one input context can generate a multitude of contexts because a graph node diff --git a/include/aidge/graphRegex/matchFsm/FsmRunTimeContext.hpp b/include/aidge/graphRegex/matchFsm/FsmRunTimeContext.hpp index 5c73f83be9c1f2ec09ed16153f41b49e02537464..f1fb4b02684901fb0576c864401e134ae1616a73 100644 --- a/include/aidge/graphRegex/matchFsm/FsmRunTimeContext.hpp +++ b/include/aidge/graphRegex/matchFsm/FsmRunTimeContext.hpp @@ -61,7 +61,7 @@ namespace Aidge{ FsmRunTimeContext(std::shared_ptr<FsmRunTimeContext> fsmRunTime); FsmRunTimeContext(std::shared_ptr<FsmRunTimeContext> fsmRunTime,std::shared_ptr<FsmNode> actState ,NodePtr actOpNode ); - virtual ~FsmRunTimeContext();//=default; + virtual ~FsmRunTimeContext()=default; /** * @defgroup FsmRunTimeContextRejected Function for managing rejected nodes diff --git a/include/aidge/nodeTester/ConditionalParser.hpp b/include/aidge/nodeTester/ConditionalParser.hpp index 59041a19f88e2895cf4e6e1f4d1266edd8bcb9fc..79eff676ee2a2687c6f604adff343ba7b114b4d5 100644 --- a/include/aidge/nodeTester/ConditionalParser.hpp +++ b/include/aidge/nodeTester/ConditionalParser.hpp @@ -36,7 +36,7 @@ class ConditionalParser{ */ ConditionalParser(const std::string ConditionalExpressions); - virtual ~ConditionalParser() ;// = default; + virtual ~ConditionalParser() = default; /** * @brief AST graph creation function * @return The AST tree diff --git a/src/graphRegex/GraphLexer.cpp b/src/graphRegex/GraphLexer.cpp index 437c45f5088f459613cb63bbbdb96b7ea4e09145..61214f96a090fef5d28cb0ce1a009644d9570880 100644 --- a/src/graphRegex/GraphLexer.cpp +++ b/src/graphRegex/GraphLexer.cpp @@ -88,7 +88,6 @@ std::shared_ptr<ParsingToken<gRegexTokenTypes>> GraphLexer::getNextToken(void){ mPosition++; if (mPosition < mRegularExpressions.length()) currentChars += mRegularExpressions[mPosition]; - } //we end the match 2 posibility //we are at the end of the mConditionalExpressions and we need to ensure the match @@ -99,7 +98,6 @@ std::shared_ptr<ParsingToken<gRegexTokenTypes>> GraphLexer::getNextToken(void){ { throw badTokenError(currentChars,mPosition); } - //mPosition++; // we stop all by going pos > lengt } diff --git a/src/graphRegex/GraphParser.cpp b/src/graphRegex/GraphParser.cpp index be7b6904023436c822bb1c6ab2c81d0b8de40f02..5aa653c482dae82c2e9fa02bfc36b2ffc821785f 100644 --- a/src/graphRegex/GraphParser.cpp +++ b/src/graphRegex/GraphParser.cpp @@ -54,11 +54,13 @@ std::shared_ptr<AstNode<gRegexTokenTypes>> GraphParser::constructAstExp(void) if (mCurrentToken->getType() == gRegexTokenTypes::KEY ){ ackToken(gRegexTokenTypes::KEY ); if (mCurrentToken->getType() == gRegexTokenTypes::QOM ){ + token = mCurrentToken->copy(); ackToken(gRegexTokenTypes::QOM ); std::shared_ptr<AstNode<gRegexTokenTypes>> newNode = std::make_shared<AstNode<gRegexTokenTypes>>(token, std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{node}); return newNode; }else if (mCurrentToken->getType() == gRegexTokenTypes::QZM ){ + token = mCurrentToken->copy(); ackToken(gRegexTokenTypes::QZM ); std::shared_ptr<AstNode<gRegexTokenTypes>> newNode = std::make_shared<AstNode<gRegexTokenTypes>>(token, std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{node}); @@ -149,7 +151,7 @@ std::shared_ptr<AstNode<gRegexTokenTypes>> GraphParser::constructAstDomain(void) } /* - allExpr: seq (SEP allExpr)* + allExpr: seq (SEP allExpr)* | STOP */ std::shared_ptr<AstNode<gRegexTokenTypes>> GraphParser::constructAstAllExpr(void) { @@ -160,6 +162,11 @@ std::shared_ptr<AstNode<gRegexTokenTypes>> GraphParser::constructAstAllExpr(void { std::shared_ptr<ParsingToken<gRegexTokenTypes>> token = mCurrentToken->copy(); ackToken(gRegexTokenTypes::SEP); + + if(mCurrentToken->getType() == gRegexTokenTypes::STOP ) + { + return left; + } std::shared_ptr<AstNode<gRegexTokenTypes>> newNode = std::make_shared<AstNode<gRegexTokenTypes>>(token, std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{left,constructAstAllExpr()}); left = newNode; diff --git a/src/graphRegex/GraphStrInterpreter.cpp b/src/graphRegex/GraphStrInterpreter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ad24b5b9b0fee5fba34dd7397132bec2410fd23 --- /dev/null +++ b/src/graphRegex/GraphStrInterpreter.cpp @@ -0,0 +1,38 @@ +#include "aidge/graphRegex/GraphStrInterpreter.hpp" + +using namespace Aidge; + +GraphStrInterpreter::GraphStrInterpreter(const std::string graphMatchExpr):mParser(graphMatchExpr){ + mToTest = graphMatchExpr; + mToTest.erase(std::remove_if(mToTest.begin(), mToTest.end(), ::isspace), mToTest.end()); +} + + +std::string GraphStrInterpreter::visit(std::shared_ptr<AstNode<gRegexTokenTypes>> AstTree){ + + std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>> nextAstNodes = AstTree->getChilds(); + + if(AstTree->getType() == gRegexTokenTypes::SEP){ + return visit(nextAstNodes[0])+";"+visit(nextAstNodes[1]); + }else if(AstTree->getType() == gRegexTokenTypes::NEXT){ + return visit(nextAstNodes[0])+"->"+visit(nextAstNodes[1]); + }else if(AstTree->getType() == gRegexTokenTypes::QOM){ + return visit(nextAstNodes[0])+"+"; + }else if(AstTree->getType() == gRegexTokenTypes::QZM){ + return visit(nextAstNodes[0])+"*"; + }else if(AstTree->getType() == gRegexTokenTypes::KEY || AstTree->getType() == gRegexTokenTypes::CKEY){ + return AstTree->getValue(); + }else if(AstTree->getType() == gRegexTokenTypes::LPAREN){ + return "("+visit(nextAstNodes[0])+")"; + }else{ + throw std::logic_error("visit Bad token type" ); + } + + +} + + +std::string GraphStrInterpreter::interpret(void){ + std::shared_ptr<AstNode<gRegexTokenTypes>> tree = mParser.parse(); + return visit(tree); +} \ No newline at end of file diff --git a/src/graphRegex/matchFsm/FsmEdge.cpp b/src/graphRegex/matchFsm/FsmEdge.cpp index 19b6c356e63c1438c45bd85750f67a059918535c..593da06abe18576d435ae55718d379aa5b682d60 100644 --- a/src/graphRegex/matchFsm/FsmEdge.cpp +++ b/src/graphRegex/matchFsm/FsmEdge.cpp @@ -47,7 +47,7 @@ void FsmEdge::propagateRelativePos(void){ myRelativeID.insert(kvp.first); } - for (const auto nextWeakEdge : mNodeDest->getEdges()){ + for (const auto& nextWeakEdge : mNodeDest->getEdges()){ if (auto nextEdge = nextWeakEdge.lock()) { diff --git a/unit_tests/graphRegex/Test_FsmMatch.cpp b/unit_tests/graphRegex/Test_FsmMatch.cpp index 132a8606e7eb26f651ea951f7879817dd7f0e244..d89b274b3c287b0ee3af97b899c6fbd22e973148 100644 --- a/unit_tests/graphRegex/Test_FsmMatch.cpp +++ b/unit_tests/graphRegex/Test_FsmMatch.cpp @@ -23,7 +23,7 @@ TEST_CASE("FsmMatch") { allTest["A"]->insertLambda("isConv",+[](NodePtr NodeOp){return NodeOp->type() == "Conv";}); allTest["B"]->insertLambda("isConv",+[](NodePtr NodeOp){return NodeOp->type() == "Conv";}); - std::shared_ptr<GraphFsmInterpreter> fsmGenerator = std::make_shared<GraphFsmInterpreter>("A#->B",allTest); + std::shared_ptr<GraphFsmInterpreter> fsmGenerator = std::make_shared<GraphFsmInterpreter>("A->A",allTest); std::shared_ptr<FsmGraph> fsm = fsmGenerator->interpret(); @@ -51,9 +51,38 @@ TEST_CASE("FsmMatch") { REQUIRE( result->getBiggerSolution() == std::set<NodePtr>{conv,conv1}); } - SECTION("split"){ + SECTION("2 branche graph"){ + std::shared_ptr<GraphView> g1 = std::make_shared<GraphView>("TestGraph"); + std::shared_ptr<Node> conv = GenericOperator("Conv", 1, 1, 1, "c"); + std::shared_ptr<Node> conv1 = GenericOperator("Conv", 1, 1, 1, "c1"); + std::shared_ptr<Node> conv2 = GenericOperator("Fc", 1, 1, 1, "c2"); + + g1->add(conv); + g1->addChild(conv1,conv); + g1->addChild(conv2,conv); + + REQUIRE(g1->getNodes() == std::set<std::shared_ptr<Node>>({conv,conv1,conv2})); + REQUIRE(g1->inputNodes() == std::set<std::shared_ptr<Node>>({conv})); + REQUIRE(g1->outputNodes() == std::set<std::shared_ptr<Node>>({conv1,conv2})); + + + ///////////// + + std::map<std::string,std::shared_ptr<ConditionalInterpreter>> allTest = { + {"A",std::make_shared<ConditionalInterpreter>("isConv($)==true")}, + {"B",std::make_shared<ConditionalInterpreter>("isFc($)==true")} + }; + allTest["A"]->insertLambda("isConv",+[](NodePtr NodeOp){return NodeOp->type() == "Conv";}); + allTest["B"]->insertLambda("isFc",+[](NodePtr NodeOp){return NodeOp->type() == "Fc";}); + + std::shared_ptr<GraphFsmInterpreter> fsmGenerator = std::make_shared<GraphFsmInterpreter>("A#->A; A#->B",allTest); + std::shared_ptr<FsmGraph> fsm = fsmGenerator->interpret(); + + std::vector<std::shared_ptr<Node>> startNodes = {conv,conv}; + auto result = fsm->test(startNodes); + REQUIRE( result->getBiggerSolution() == std::set<NodePtr>{conv,conv1,conv2}); } diff --git a/unit_tests/graphRegex/Test_GraphLexer.cpp b/unit_tests/graphRegex/Test_GraphLexer.cpp index 9b922e5bd70ee1537f54100a2b8e9c826ff5e0c2..1b8cc8e018546ebfe3f84202d9404db27b17449b 100644 --- a/unit_tests/graphRegex/Test_GraphLexer.cpp +++ b/unit_tests/graphRegex/Test_GraphLexer.cpp @@ -73,7 +73,7 @@ TEST_CASE("GraphRegex", "Lexer") { ////////////////// //TEST GENERATOR ////////////////// - const std::size_t numRandomElements = 1000; + const std::size_t numRandomElements = 10000; std::vector<std::tuple<gRegexTokenTypes, std::string>> testVector; std::string testString; diff --git a/unit_tests/graphRegex/Test_GraphParser.cpp b/unit_tests/graphRegex/Test_GraphParser.cpp index ff74b676598d5fe63fe47b5c5cd24ba123aca004..857caa06f4e5fa383e79ea22bfe1ca28ac0973c8 100644 --- a/unit_tests/graphRegex/Test_GraphParser.cpp +++ b/unit_tests/graphRegex/Test_GraphParser.cpp @@ -6,6 +6,8 @@ using namespace Aidge; + + //generative function , std::string domain(); std::string exp() { int randomValue = std::rand() % 3; diff --git a/unit_tests/graphRegex/Test_graphRegexAST.cpp b/unit_tests/graphRegex/Test_graphRegexAST.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1cdb0bc1934983a26ab742bfe8879455077219cc --- /dev/null +++ b/unit_tests/graphRegex/Test_graphRegexAST.cpp @@ -0,0 +1,71 @@ +#include <catch2/catch_test_macros.hpp> +#include "aidge/graphRegex/GraphStrInterpreter.hpp" + + +using namespace Aidge; +TEST_CASE("GraphStrInterpreter") { + + + + std::vector<std::string> tests = { + + + //sequ + "A;", + "A->B", + "A->B->C", + //seq and common + "A#", + "A#->B", + "A#->B#", + "A#->B#->C", + "A#->B#->C#", + "A->B#->C", + //sequ quantif + + "A+", + "A+->B+", + "A->B+->C", + //sequ quantif * + "A*", + "A*->B*", + "A->B*->C", + + //sequ quantif + "A*", + "A*->B+", + "A+->B*->C", + //others + + "(A#->B->C#)+", + "(A#->B)+;A#->B->C", + "B+->B->B", + "B#->R*", + "(B#->R)*", + "A->C->B#->B;B#->R", + "B#->R", + "A->C#;A->C#;A->C#;A->C#;A->C#;A->C#", + "B#->R;B#->R", + "A# -> C -> B#; B#->A#", + + // Add more test cases here + }; + + SECTION("AST Regex bijection") { + + for (const std::string& test : tests) { + std::shared_ptr<GraphStrInterpreter> strGenerator = std::make_shared<GraphStrInterpreter>(test); + std::string astString = strGenerator->interpret(); + //supress space in the test becase erase in the AST + std::string testNoS = test; + testNoS.erase(std::remove_if(testNoS.begin(), testNoS.end(), ::isspace), testNoS.end()); + //if the last char is ; (SEP) it will not in the AST and it's not a bug erase it + if (!testNoS.empty() && testNoS.back() == ';') { + // Remove the last character + testNoS.pop_back(); + } + //test + REQUIRE(astString == testNoS); + } + + } +} \ No newline at end of file