From 27a6d72aaa1c1284dd469b9c9e0ca06ffa198927 Mon Sep 17 00:00:00 2001 From: vl241552 <vincent.lorrain@cea.fr> Date: Mon, 2 Oct 2023 14:18:52 +0000 Subject: [PATCH] [GraphRegex] fix and Test str --- include/aidge/graphRegex/GraphParser.hpp | 2 +- .../aidge/graphRegex/GraphStrInterpreter.hpp | 40 +++++++++++ .../aidge/graphRegex/matchFsm/FsmGraph.hpp | 2 +- include/aidge/graphRegex/matchFsm/FsmNode.hpp | 2 +- .../graphRegex/matchFsm/FsmRunTimeContext.hpp | 2 +- .../aidge/nodeTester/ConditionalParser.hpp | 2 +- src/graphRegex/GraphLexer.cpp | 2 - src/graphRegex/GraphParser.cpp | 9 ++- src/graphRegex/GraphStrInterpreter.cpp | 38 ++++++++++ src/graphRegex/matchFsm/FsmEdge.cpp | 2 +- unit_tests/graphRegex/Test_FsmMatch.cpp | 33 ++++++++- unit_tests/graphRegex/Test_GraphLexer.cpp | 2 +- unit_tests/graphRegex/Test_GraphParser.cpp | 2 + unit_tests/graphRegex/Test_graphRegexAST.cpp | 71 +++++++++++++++++++ 14 files changed, 197 insertions(+), 12 deletions(-) create mode 100644 include/aidge/graphRegex/GraphStrInterpreter.hpp create mode 100644 src/graphRegex/GraphStrInterpreter.cpp create mode 100644 unit_tests/graphRegex/Test_graphRegexAST.cpp diff --git a/include/aidge/graphRegex/GraphParser.hpp b/include/aidge/graphRegex/GraphParser.hpp index 06d098e99..018be1e44 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 000000000..a1fb5c2e2 --- /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 d6ef8742d..94eafd051 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 6a31c20fb..18b78fe89 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 5c73f83be..f1fb4b026 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 59041a19f..79eff676e 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 437c45f50..61214f96a 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 be7b69040..5aa653c48 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 000000000..8ad24b5b9 --- /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 19b6c356e..593da06ab 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 132a8606e..d89b274b3 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 9b922e5bd..1b8cc8e01 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 ff74b6765..857caa06f 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 000000000..1cdb0bc19 --- /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 -- GitLab