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