diff --git a/include/aidge/graphRegex/GraphFsmInterpreter.hpp b/include/aidge/graphRegex/GraphFsmInterpreter.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..545b34e722c4b0842c73371b7a698255bbab07cc
--- /dev/null
+++ b/include/aidge/graphRegex/GraphFsmInterpreter.hpp
@@ -0,0 +1,73 @@
+#ifndef __AIDGE_GRAPH_FSM_INTERPRETER_H__
+#define __AIDGE_GRAPH_FSM_INTERPRETER_H__
+
+#include <string>
+#include <memory>
+
+#include "aidge/utilsParsing/AstNode.hpp"
+#include "aidge/graphRegex/GraphRegexTypes.hpp"
+#include "aidge/graphRegex/GraphParser.hpp"
+#include "aidge/graphRegex/matchFsm/FsmGraph.hpp"
+
+namespace Aidge {
+
+    class GraphFsmInterpreter
+    {
+    private:
+        /* data */
+        GraphParser mParser;
+        std::size_t mActGroupe;
+        std::map<std::string,std::shared_ptr<ConditionalInterpreter>> mNodesCondition;
+
+    public:
+        GraphFsmInterpreter(const std::string graphMatchExpr,std::map<std::string,std::shared_ptr<ConditionalInterpreter>> nodesCondition);
+        virtual ~GraphFsmInterpreter() =default;
+
+
+        std::shared_ptr<FsmGraph>  interpret(void);
+
+        private:
+        
+
+        std::shared_ptr<FsmGraph> visit(std::shared_ptr<AstNode<gRegexTokenTypes>> AstTree);
+
+        /**
+         * @defgroup graphFsmInterpreterF Functions for interpreting AST nodes 
+         * @brief For each node type in the AST, define how build the FsmGraph
+         */
+
+
+        /**
+         * @ingroup graphFsmInterpreterF
+         * @brief leaf of fsm make the fsm for test one transition 
+         */
+        std::shared_ptr<FsmGraph> keyF(std::shared_ptr<AstNode<gRegexTokenTypes>> AstNode);
+        /**
+         * @ingroup graphFsmInterpreterF
+         * @brief combine two fsm of two expression.
+         */
+        std::shared_ptr<FsmGraph> sepF(std::shared_ptr<FsmGraph> leftFsm,std::shared_ptr<FsmGraph> rigthFsm);
+        /**
+         * @ingroup graphFsmInterpreterF
+         * @brief combine two to make a new that match leftFsm next rigthFsm
+         */
+        std::shared_ptr<FsmGraph> nextF(std::shared_ptr<FsmGraph> leftFsm,std::shared_ptr<FsmGraph> rigthFsm);
+        /**
+         * @ingroup graphFsmInterpreterF
+         * @brief make the fsm match +
+         */
+        std::shared_ptr<FsmGraph> qomF(std::shared_ptr<FsmGraph> fsm);
+        /**
+         * @ingroup graphFsmInterpreterF
+         * @brief  make the fsm match *
+         */
+        std::shared_ptr<FsmGraph> qzmF(std::shared_ptr<FsmGraph> fsm);
+
+    };
+
+
+
+}
+
+
+#endif //__AIDGE_GRAPH_STM_INTERPRETER_H__
\ No newline at end of file
diff --git a/include/aidge/graphRegex/GraphLexer.hpp b/include/aidge/graphRegex/GraphLexer.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..88698ef3450750136e4c42eead3f2de5897a8b28
--- /dev/null
+++ b/include/aidge/graphRegex/GraphLexer.hpp
@@ -0,0 +1,68 @@
+#ifndef __AIDGE_GRAPH_LEXER_H__
+#define __AIDGE_GRAPH_LEXER_H__
+
+#include <string>
+#include <memory>
+#include <regex>
+#include <stdexcept> //error
+#include <sstream>
+
+#include "aidge/utilsParsing/ParsingToken.hpp"
+#include "aidge/graphRegex/GraphRegexTypes.hpp"
+
+namespace Aidge {
+
+    class GraphLexer
+    {
+
+    public:
+    GraphLexer( const std::string gRegexExpressions );
+
+    /**
+     * @brief Get the next token on the gRegexExpressions
+     * @return ConditionalToken 
+     */
+    std::shared_ptr<ParsingToken<gRegexTokenTypes>> getNextToken(void);
+    /**
+     * @brief Restart at the start of the gRegexExpressions 
+     * 
+     */
+    void rstPosition(void);
+
+    /**
+     * @brief Test if the string is completely read 
+     * @return bool 
+     */
+    bool isEnd(void);
+
+
+    /**
+     * @brief Get the representation of the class
+     * @return string 
+     */
+    const std::string rep();
+
+    private:
+
+    /**
+     * @brief Constructs an error message to display the character not understood by the lexer 
+     * @return error mesage 
+     */
+    std::runtime_error badTokenError(const std::string& currentChars,std::size_t position);
+
+    /**
+     * @brief The expression of the test to be performed on the nodes
+     */
+    const std::string mRegularExpressions;
+    /**
+     * @brief The lexer's current position in mConditionalExpressions
+     */
+    std::size_t mPosition;
+
+    };
+}
+
+
+
+
+#endif //__AIDGE_GRAPH_LEXER_H__
\ No newline at end of file
diff --git a/include/aidge/graphRegex/GraphParser.hpp b/include/aidge/graphRegex/GraphParser.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d0234afbf72b7b8b2a5bb0582289bd36e92c1299
--- /dev/null
+++ b/include/aidge/graphRegex/GraphParser.hpp
@@ -0,0 +1,95 @@
+#ifndef _AIDGE_GRAPH_PARSER_H_
+#define _AIDGE_GRAPH_PARSER_H_
+
+
+#include <memory> // for shared_ptr
+#include "aidge/graphRegex/GraphLexer.hpp"
+#include "aidge/utilsParsing/AstNode.hpp"
+#include "aidge/graphRegex/GraphRegexTypes.hpp"
+
+namespace Aidge{
+
+/**
+ * @brief this class uses the lexer to create an AST according to a set of gramer rules 
+ */
+class GraphParser{
+    
+    public:
+    /**
+     * @brief AST graph creation function 
+     * @param gRegexExpressions String representing the logical fuction to be performed
+     */
+    GraphParser(const std::string gRegexExpressions);
+
+    /**
+     * @brief AST graph creation function 
+     * @return The AST tree 
+     */
+    std::shared_ptr<AstNode<gRegexTokenTypes>> parse(void);
+
+
+    private:
+    /**
+     * @brief restart at the start of the ConditionalExpressions for LEXER and restart  mCurrentToken
+     */
+    void rstParser(void);
+    
+    //////////////////
+
+    /**
+     * @defgroup ParsingFunctions Function for creating AST
+     * @brief Functions for recursive construction of the AST representing grammar rules
+     */
+
+    /**
+     * @ingroup ParsingFunctions
+     * @brief Token reading and verification function  
+     * 
+     */
+    void ackToken(gRegexTokenTypes  tokenType);
+
+    //TODO TODO
+    /**
+     * @ingroup ParsingFunctions
+     * @brief Function of grammar rules for key :  KEY(QOM | QZM)? | CKEY 
+     * @return AST node 
+     */
+    std::shared_ptr<AstNode<gRegexTokenTypes>> constructAstExp(void);
+
+    /**
+    * @ingroup ParsingFunctions
+    * @brief Function of grammar rules for sequence :  seq :exp (NEXT seq)* 
+    * @return AST node 
+    */
+    std::shared_ptr<AstNode<gRegexTokenTypes>> constructAstSeq(void);
+
+    /**
+    * @ingroup ParsingFunctions
+    * @brief Function of grammar rules for domain : (seq NEXT domain)? | LPAREN domain RPAREN (QOM | QZM) (NEXT domain)? 
+    * @return AST node 
+    */
+    std::shared_ptr<AstNode<gRegexTokenTypes>> constructAstDomain(void);
+    
+    /**
+    * @ingroup ParsingFunctions
+    * @brief Function of grammar rules for multiple exepresion : allExpr: domain (SEP allExpr)*
+    * @return AST node 
+    */
+    std::shared_ptr<AstNode<gRegexTokenTypes>> constructAstAllExpr(void);
+
+
+    /**
+    * @brief The actual token in the parce
+    */
+    std::shared_ptr<ParsingToken<gRegexTokenTypes>> mCurrentToken;
+    /**
+    * @brief The lexem use
+    */
+    GraphLexer mLexer;
+
+};
+
+
+}
+
+#endif //_AIDGE_GRAPH_PARSER_H_
diff --git a/include/aidge/graphRegex/GraphRegexTypes.hpp b/include/aidge/graphRegex/GraphRegexTypes.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ddb9d581aa8fff1e0f7f9fa35d8bb398fc1e4d71
--- /dev/null
+++ b/include/aidge/graphRegex/GraphRegexTypes.hpp
@@ -0,0 +1,29 @@
+
+#ifndef __AIDGE_GREGEX_TOKEN_TYPES_H__
+#define __AIDGE_GREGEX_TOKEN_TYPES_H__
+
+
+namespace Aidge {
+    /**
+     * @brief enum for all types of token use in the of the regex 
+     * 7-5 type
+     * 4-0 id
+    */
+    enum class gRegexTokenTypes
+    {
+        NEXT                = (1 << 4)+1, /**< -> */ 
+
+        QOM                 = (1 << 5)+1, /**< + */ 
+        QZM                 = (1 << 5)+2, /**< * */ 
+
+        KEY                 = (1 << 6)+2, /**< [A-Za-z_0-9]+ */ 
+        CKEY                = (1 << 6)+1, /**< [A-Za-z_0-9]+#[0-9]* */ 
+        
+        SEP                 = (1<<7) +1, /**< \( */
+        LPAREN              = (1<<7) +2, /**< \( */
+        RPAREN              = (1<<7) +3, /**< \) */
+        STOP                = 0,
+    };
+
+}
+#endif //__AIDGE_GREGEX_TOKEN_TYPES_H__
\ No newline at end of file
diff --git a/include/aidge/graphRegex/matchFsm/FsmEdge.hpp b/include/aidge/graphRegex/matchFsm/FsmEdge.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..995f147892a51ff189d3fe944811329f32b702a8
--- /dev/null
+++ b/include/aidge/graphRegex/matchFsm/FsmEdge.hpp
@@ -0,0 +1,218 @@
+#ifndef __AIDGE_FSM_EDGE_H__
+#define __AIDGE_FSM_EDGE_H__
+
+#include <memory>
+#include <set>
+#include <string>
+
+//#include "graphRegex/matchFsm/FsmNode.hpp"
+#include "aidge/nodeTester/ConditionalInterpreter.hpp"
+//#include "graphRegex/matchFsm/FsmRunTimeContext.hpp"
+
+
+namespace Aidge{
+
+    class FsmNode;
+    class FsmRunTimeContext;
+
+    struct EdgeTestResult {
+        bool success;
+        std::set<NodePtr> node;
+    };
+
+    /**
+     * @brief virtual class use test the node  on the node to validate 
+    */
+    class FsmEdge: public std::enable_shared_from_this<FsmEdge>
+    {
+    private:
+   
+        /**
+         * @brief the relative position to this test relative to all the const key
+         * firse is common id , segond is the relative position 
+        */
+        std::map<size_t,int> mRelativePos;
+        /**
+         * @brief the ptr on the source node
+        */
+        std::shared_ptr<FsmNode> mNodeSource;
+            /**
+         * @brief the ptr on the dest node
+        */
+        std::shared_ptr<FsmNode> mNodeDest;
+
+    public:
+        FsmEdge(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const std::shared_ptr<ConditionalInterpreter>  toTest);
+        virtual  ~FsmEdge() =default;
+
+        /**
+        *  @brief test is the validation of the node , it must be deffine for all types of edge
+        * it takes as argument an FSM traversal context and returns a set of next nodes 
+        *  @return set of next node or nullptr if not next
+        */
+
+        virtual const EdgeTestResult test(const std::shared_ptr<FsmRunTimeContext> stmContext) =0;
+
+        /**
+        *  @brief test is the egde test a common node
+        *  @return true if is a common
+        */
+        virtual bool isCommon(void);
+        /**
+         * @brief get the Common idx of the common test in this edge (if is a common edge)
+         * @return idx of the common
+        */
+        virtual size_t getCommonIdx(void);
+        /**
+         * @brief get the relative postion to the common node deffine in this edge
+         * @return map
+        */
+        const std::map<size_t,int>& getRelative(void);
+        /**
+         * @brief add new relative position 
+        */
+        void updateRelative( const std::map<size_t,int>& relativePos );
+        /**
+         * @brief get source FsmNode
+         * @return FsmNode
+        */
+        std::shared_ptr<FsmNode> getSourceNode(void);
+        /**
+         * @brief set a new source to the edge
+         * @return FsmNode
+        */
+        void reSetSouceNode(const std::shared_ptr<FsmNode>& newSource);
+          /**
+         * @brief get dest FsmNode
+         * @return FsmNode
+        */
+        std::shared_ptr<FsmNode> getDestNode(void);
+        /**
+         * @brief set a new dest to the edge
+         * @return FsmNode
+        */
+        void reSetDestNode(const std::shared_ptr<FsmNode>& newDest);
+        /**
+         * @brief propagate the edge  mRelativePos to the others Edge and recalcul the relative position 
+        */
+        void propagateRelativePos(void);
+
+         /**
+         * @brief test to make on the node to validate 
+         * @see ConditionalInterpreter
+        */
+        const std::shared_ptr<ConditionalInterpreter>  mToTest;
+    };
+
+    /**
+     * @brief class spesialisation for not commun node (node that must be match one Unique) transition
+    */
+    class FsmEdgeUnique:public FsmEdge
+    {
+
+        public:
+        FsmEdgeUnique(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const std::shared_ptr<ConditionalInterpreter>  toTest);
+        //~FsmEdgeUnique() override {}
+         const EdgeTestResult test(const std::shared_ptr<FsmRunTimeContext> stmContext) override;
+    };
+
+    /**
+     * @brief class spesialisation for  commun node transition
+     * @see FsmEdge
+    */
+    class FsmEdgeCommon:public FsmEdge
+    {
+
+        private:
+        /**
+         * @brief the map that defind the ralation between the commonKey find by the lexer and a unique id use to refer to the common node 
+        */
+        static std::map<std::string,int> mCommonIdxMap;
+        /**
+         * @brief the common id test in this transition 
+        */
+        int mCommonIdx;
+        public:
+
+        /**
+         * @brief constructor  commun node ,
+         * @details during construction, 
+         * the node key found by the lexer is converted to a unique id and the relative positions are updated.
+        */
+        FsmEdgeCommon(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const std::shared_ptr<ConditionalInterpreter>  toTest, const std::string commonKey);
+       // ~FsmEdgeCommon() override {}
+        const EdgeTestResult test(const std::shared_ptr<FsmRunTimeContext> stmContext) override;
+        bool isCommon(void) override;
+
+    };
+    
+
+
+    /**
+     * @brief class spesialisation for ref transition 
+     * @see FsmEdge
+    */
+    class FsmEdgeRef:public FsmEdge
+    {
+        private:
+        /**
+         * @brief the id of one common node that we use as an anchor
+        */
+        const int mRefCommonIdx;
+        /**
+         * @brief the delta in terme of child or parent refer to the anchor
+        */
+        const int mdeltaCommonIdx;
+        public:
+        FsmEdgeRef(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const size_t refCommonIdx,const int deltaCommonIdx);
+        //~FsmEdgeRef() override {}
+        const EdgeTestResult test(const std::shared_ptr<FsmRunTimeContext> stmContext) override;
+        
+    };
+
+    /**
+     * @brief class spesialisation for ref empty transition 
+     * @see FsmEdge
+    */
+    class FsmEdgeEmpty:public FsmEdge
+    {
+
+        public:
+        FsmEdgeEmpty(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest);
+        //~FsmEdgeEmpty() override {}
+        const EdgeTestResult test(const std::shared_ptr<FsmRunTimeContext> stmContext) override;
+        
+    };
+
+
+
+////////////////////////
+// FACTORY
+////////////////////////
+
+enum class FsmEdgeTypes {
+    EMPTY = 0,
+    REF,
+    COMMON,
+    UNIQUE
+};
+
+
+class FsmEdgeFactory {
+    public:
+    /**
+    * @brief factory for making edge and read the info in the lexeme of the token
+    * @param source source node of the edge
+    * @param dest Dest node of the edge
+    * @param type type of the edge  
+    * @param lexeme the additional information to build the edge
+    * @return s prt of the edge
+    */
+    static std::shared_ptr<FsmEdge> make(std::shared_ptr<FsmNode> source, std::shared_ptr<FsmNode> dest, 
+    FsmEdgeTypes type,std::map<std::string, std::shared_ptr<ConditionalInterpreter>> allTest,
+    const std::string lexeme = "");
+   };
+
+}
+
+#endif //__AIDGE_FSM_EDGE_H__
\ No newline at end of file
diff --git a/include/aidge/graphRegex/matchFsm/FsmGraph.hpp b/include/aidge/graphRegex/matchFsm/FsmGraph.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a5257eb44b80f51f853427c943efa232071072c4
--- /dev/null
+++ b/include/aidge/graphRegex/matchFsm/FsmGraph.hpp
@@ -0,0 +1,95 @@
+
+#ifndef __AIDGE_FSM_GRAPH_H__
+#define __AIDGE_FSM_GRAPH_H__
+
+#include <set>
+#include <vector>
+#include <memory>
+#include <stdexcept> //error
+
+#include "aidge/graphRegex/matchFsm/FsmNode.hpp"
+#include "aidge/graphRegex/matchFsm/FsmEdge.hpp"
+#include "aidge/graphRegex/matchFsm/MatchResult.hpp"
+namespace Aidge{
+
+
+
+class FsmGraph
+{
+private:
+    std::set<std::size_t> mAllOrigine;
+    std::set<std::shared_ptr<FsmEdge>> mEdges;
+public:
+    FsmGraph(/* args */);
+    virtual ~FsmGraph()  = default;
+
+std::vector<std::shared_ptr<MatchResult>> test(std::vector<NodePtr>& StartNodes);
+
+
+
+const std::set<std::shared_ptr<FsmEdge>>& getEdge(void);
+/**
+ * @brief add edge in the graph, as FsmEdge know the source and dest FsmNode these nodes are also add to the graph
+*/
+void addEdge(std::shared_ptr<FsmEdge> edge);
+
+/**
+ * @brief get the liste of the starting states 
+ * @details we need to use a vector because the order of the nodes is important for start node initialization \ref test()
+*/
+const std::vector<std::shared_ptr<FsmNode>> getStartNodes(void);
+
+/**
+ * @brief get the set of the valide states 
+ * @return set of valide state
+*/
+const std::set<std::shared_ptr<FsmNode>> getValidNodes(void);
+
+/**
+ * @brief get the set of all the node in the graph
+ * @return set of all nodes
+*/
+const std::set<std::shared_ptr<FsmNode>> getNodes(void);
+
+/**
+ * @brief set a groupe idx for all the nodes in the graph
+*/
+void setGroupe(std::size_t groupeIdx);
+
+/**
+ * @brief make the union beteen this graph and an input graph
+ * @param fsmGraph graph to union 
+*/
+void unionG(const std::shared_ptr<FsmGraph> fsmGraph);
+
+
+/**
+ * @brief make the union beteen this graph and an input graph and merge the valide state to the start state 
+ * @param fsmGraph graph to merge 
+*/
+void mergeOneStartOneValid(const std::shared_ptr< FsmGraph> fsmGraph);
+/**
+ * @brief get the number of sub FSM
+ * @return number of sub Fsm
+*/
+std::size_t getNbSubFsm(void);
+
+/**
+ * @brief increment the origine of all node in the graph
+ * @param incr the incrémentation value
+*/
+void incOrigineAllNodeBy(std::size_t incr);
+
+private:
+
+/**
+ * @brief merge tow node of the graph 
+ * @param node
+*/
+void _mergeNode(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest);
+
+};
+
+
+}
+#endif //__AIDGE_FSM_GRAPH_H__ 
\ No newline at end of file
diff --git a/include/aidge/graphRegex/matchFsm/FsmNode.hpp b/include/aidge/graphRegex/matchFsm/FsmNode.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..7155e35c3b52418c3b939880ac48acaefb40a185
--- /dev/null
+++ b/include/aidge/graphRegex/matchFsm/FsmNode.hpp
@@ -0,0 +1,99 @@
+#ifndef __AIDGE_FSM_NODE_H__
+#define __AIDGE_FSM_NODE_H__
+
+#include <set>
+#include <vector>
+#include <memory>
+
+//#include "graphRegex/matchFsm/FsmEdge.hpp"
+//#include "graphRegex/matchFsm/FsmRunTimeContext.hpp"
+
+namespace Aidge{
+    // Forward declaration of the class defined in graphRegex/matchFsm/FsmEdge.hpp
+    class FsmEdge;
+    struct EdgeTestResult;
+    class FsmRunTimeContext;
+
+
+    //------------------------------------------------------------------------------
+
+    // MAY BE IN UTILE
+    template <typename T>
+    struct lex_compare {
+        bool operator() (const std::weak_ptr<T> &lhs, const std::weak_ptr<T> &rhs)const {
+            auto lptr = lhs.lock(), rptr = rhs.lock();
+            if (!rptr) return false; // nothing after expired pointer 
+            if (!lptr) return true;  
+            return lptr < rptr;
+        }
+    };
+
+    /**
+     * @brief is a node in the FSM graph, it's a state in the FSM
+     * @details a state can be and/or :
+     * - a valide state, the match is valide if it stop on this edge
+     * - a start state , the match start on this state
+     * The state is also define by this origine (is the unique id of it's expretion )
+     * and it's groupe (for inner expression TODO)
+    */
+    class FsmNode : public std::enable_shared_from_this<FsmNode>
+    {
+    private:
+        /**
+         * @brief the edge of the node
+         * @details the edge have a shared ref to the node so we use weak ref
+        */
+        std::set<std::weak_ptr<FsmEdge>,lex_compare<FsmEdge>> mEdges;
+        /**
+         * @brief the parent of the node 
+        */
+        std::set<std::weak_ptr<FsmNode>,lex_compare<FsmNode>> mParents;
+
+        std::size_t mOrigineStm = 0;
+        std::size_t mGroupeStm = 0;
+
+        bool mIsAValid;
+        bool mIsAStart;
+
+    public:
+        FsmNode(bool isAValid,bool isAStart );
+        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
+         *  can have more than one child, and each traversal possibility is a new context.
+         * @param actContext the actual context
+         * @return A vector of all the new context
+        */
+        const std::vector<std::shared_ptr<FsmRunTimeContext>> test( std::shared_ptr<FsmRunTimeContext>);
+
+
+        std::size_t getOrigine(void);
+        void incOrigine(std::size_t inc);
+
+
+        void rmEdge(std::shared_ptr<FsmEdge>);
+        void addEdge(std::shared_ptr<FsmEdge>);
+
+        const std::set<std::shared_ptr<FsmNode>> getChildNodes(void);
+
+        const std::set<std::weak_ptr<FsmNode>,lex_compare<FsmNode>> getParentNodes(void);
+        const std::set<std::weak_ptr<FsmEdge>,lex_compare<FsmEdge>> getEdges(void);
+
+        void setGroupe(std::size_t groupeIdx);
+
+        bool isValid(void);
+        bool isStart(void);
+        void unValid(void);
+        void valid(void);
+        void unStart(void);
+        void start(void);
+
+
+
+        void addParent(std::shared_ptr<FsmNode>);
+        void rmParent(std::shared_ptr<FsmNode>);
+    };
+
+}
+#endif //__AIDGE_FSM_NODE_H__
\ No newline at end of file
diff --git a/include/aidge/graphRegex/matchFsm/FsmRunTimeContext.hpp b/include/aidge/graphRegex/matchFsm/FsmRunTimeContext.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..07ada14db1283bed2339f3fd2ef92687bc0e0c3d
--- /dev/null
+++ b/include/aidge/graphRegex/matchFsm/FsmRunTimeContext.hpp
@@ -0,0 +1,174 @@
+#ifndef __AIDGE_FSM_RUN_TIME_CONTEXT_H__
+#define __AIDGE_FSM_RUN_TIME_CONTEXT_H__
+
+#include <memory>
+#include <vector>
+#include <set>
+#include <algorithm>
+
+//#include "graphRegex/matchFsm/FsmNode.hpp"
+#include "aidge/nodeTester/ConditionalInterpreter.hpp"
+#include "aidge/graph/Node.hpp"
+
+
+
+namespace Aidge{
+
+    class FsmNode;
+
+    class FsmNode;
+
+    /**
+     * @brief a class used to save the execution context of state machines, that is the actual state in the FSM, the actual node in the graph
+     * all node that have been Validate,Rejecte or Considered common
+    */
+    class FsmRunTimeContext
+    {
+    private:
+        /**
+         * @brief the list of node rejected for all the context 
+        */
+        static std::vector<std::set<NodePtr>> mRejectedNodes;
+        /**
+         * @brief the actual state of this Context (where it's in the FSM graph)
+        */
+        std::shared_ptr<FsmNode> mActState;
+        /**
+         * @brief the actual node of this Context (where it's in the graph)
+        */
+        NodePtr mActOpNode;
+        /**
+         * @brief the map of the node consider as common and the common ID 
+         * @details we need to store what node it's consider as common because of the end 
+         * resolution of the matching, all node consider as common need to be the same in all context
+        */
+        std::map<NodePtr,std::size_t> mCommonNodes;
+        /**
+         * @brief the map of the node that as been valid in this context , and the test that valide the node
+        */
+        std::map<std::shared_ptr<ConditionalInterpreter>,std::set<NodePtr>> mValidNodes;
+        /**
+         * @brief the index in the rejected node of this context 
+        */
+        std::size_t mLocalIdxRejeced;
+    public:
+        /**
+         * @brief constructor 
+         * @param actState the actual state in the FSM 
+         * @param actOpNode the actual node in the graph
+         * @param idxRejeced the idx in the global regected node vector init -1 as sentinel value of undefind
+        */
+        FsmRunTimeContext(std::shared_ptr<FsmNode> actState ,NodePtr actOpNode ,std::size_t idxRejeced =std::numeric_limits<std::size_t>::max() );
+        FsmRunTimeContext(std::shared_ptr<FsmRunTimeContext> fsmRunTime);
+        FsmRunTimeContext(std::shared_ptr<FsmRunTimeContext> fsmRunTime,std::shared_ptr<FsmNode> actState ,NodePtr actOpNode );
+
+        virtual ~FsmRunTimeContext()=default;
+
+        /**
+         * @defgroup FsmRunTimeContextRejected Function for managing rejected nodes
+         */
+
+        /**
+         * @ingroup FsmRunTimeContextRejected
+         * @brief Add a node as rejected in this context
+         */
+        void addRejectedNode(NodePtr node);
+
+        /**
+         * @ingroup FsmRunTimeContextRejected
+         * @brief get the rejected nodes of this context
+         */
+        std::set<NodePtr> getRejectedNodes(void);
+
+
+        /**
+         * @defgroup FsmRunTimeContextTest Function for test the context 
+         */
+
+        /**
+         * @ingroup FsmRunTimeContextTest
+         * @brief test if the actual state is valide
+         * @return bool
+         */
+        bool isOnValidState(void);
+        /**
+         * @ingroup FsmRunTimeContextTest
+         * @brief test if the node is considered as common in this context
+         * @param node node to test 
+         * @return bool
+         */
+        bool isCommonDefined(NodePtr node);
+        /**
+         * @ingroup FsmRunTimeContextTest
+         * @brief test if has already validated in this context
+         * @param node node to test 
+         * @return bool
+         */
+        bool isAlreadyValid(NodePtr node);
+        /**
+         * @ingroup FsmRunTimeContextTest
+         * @brief test if this context is compatible with an others 
+         * @details to say that two contexts are compatible is to check :
+         *  that the contexts do not validate the same nodes (other than the common ones) 
+         *  and that the common ones have the same idx
+         * @param fsmContext the others context 
+         * @return bool
+         */
+        bool areCompatible(std::shared_ptr<FsmRunTimeContext> fsmContext);
+        /**
+         * @ingroup FsmRunTimeContextTest
+         * @brief test if this context is strictly equal with an others 
+         * @param fsmContext the others context 
+         * @return bool
+         */
+        bool areEqual(std::shared_ptr<FsmRunTimeContext> fsmContext);
+
+        /**
+         * @defgroup FsmRunTimeContextSet Function set context 
+        */
+
+
+        void setCommon(NodePtr node,std::size_t commonIdx);
+
+        
+        void setValid(NodePtr node,std::shared_ptr<ConditionalInterpreter> tag);
+
+        /**
+         * @defgroup FsmRunTimeContextGet Function get context 
+         */
+
+
+        /**
+         * @ingroup FsmRunTimeContextGet
+         * @brief get the sub idx state 
+         * @return bool
+         */
+        std::size_t getSubStmId(void);
+        
+        NodePtr getCommonNodeFromIdx(std::size_t commonIdx);
+        std::size_t getCommonNodeIdx(NodePtr node);
+        std::set<NodePtr> getCommonNodes(void);
+
+        std::map<NodePtr,std::size_t> getCommon(void);
+        std::set<NodePtr> getValidNodes(void);
+
+        std::set<NodePtr> getValidNodesNoCommon(void);
+        std::map<std::shared_ptr<ConditionalInterpreter>,std::set<NodePtr>> getValid(void);
+
+
+        NodePtr getActNode(void);
+        std::shared_ptr<FsmNode> getActState(void);
+
+        
+        /**
+         * @defgroup FsmRunTimeContextMem 
+         */
+
+        void rst(void);
+  
+
+    };
+    
+}
+
+#endif //__AIDGE_FSM_RUN_TIME_CONTEXT_H__
\ No newline at end of file
diff --git a/include/aidge/graphRegex/matchFsm/MatchResult.hpp b/include/aidge/graphRegex/matchFsm/MatchResult.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..8c96cc0e3ea0b5f97cc0826a55919810b8083065
--- /dev/null
+++ b/include/aidge/graphRegex/matchFsm/MatchResult.hpp
@@ -0,0 +1,34 @@
+#ifndef __AIDGE_MATCH_RESULT_H__
+#define __AIDGE_MATCH_RESULT_H__
+
+#include <memory>
+
+#include "aidge/graphRegex/matchFsm/FsmRunTimeContext.hpp"
+
+
+namespace Aidge{
+
+/**
+ * @brief class that old the result of a matching
+ * give acess to all node ant there tag in the expression 
+*/
+class MatchResult
+{
+private:
+    /* data */
+public:
+    MatchResult(std::shared_ptr<FsmRunTimeContext> contexte);
+    virtual ~MatchResult() = default;
+
+    /**
+     * @brief get the set of the node match for une expression 
+     * @return the set of node of the graph that corresponding to an expression 
+    */
+    std::set<NodePtr> getNodes(void);
+};
+
+
+}
+
+
+#endif //__AIDGE_MATCH_RESULT_H__
\ No newline at end of file
diff --git a/include/aidge/nodeTester/ConditionalData.hpp b/include/aidge/nodeTester/ConditionalData.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..9d889d6a0737d4c6cdf026b5c96c73280d93f2ff
--- /dev/null
+++ b/include/aidge/nodeTester/ConditionalData.hpp
@@ -0,0 +1,98 @@
+
+#ifndef _AIDGE_CONDITIONAL_DATA_H_
+#define _AIDGE_CONDITIONAL_DATA_H_
+
+#include <vector>
+#include <string> 
+#include <stdexcept> //error
+#include <memory>
+#include <map>
+namespace Aidge{
+
+
+
+/////////////////////////
+// the data type in AST Intepretation 
+////////////////////////
+
+class BaseConditionalValue {
+public:
+    virtual ~BaseConditionalValue() {}
+};
+
+template <typename T>
+class ConditionalValue : public BaseConditionalValue {
+public:
+    ConditionalValue(const T& data) : value(data) {}
+    T value;
+};
+
+
+struct ConditionalData {
+    /**
+     * @brief generic type to propagete all the different values in the AST interpretation 
+    */
+    //void* value;
+    std::unique_ptr<BaseConditionalValue> value;
+    const std::type_info* type;
+
+    /////////////////////////////////
+    //
+    ////////////////////////////////
+    /**
+     * @brief set a value 
+    */
+    template <typename T>
+    void setValue(const T& newValue) {
+        //make sure that the old value is free
+        deleteValue();
+        value = std::make_unique<ConditionalValue<T>>(newValue);
+        type = &typeid(T);
+    }
+
+    /**
+     * @brief get the actual value 
+     * @details recaste the value to the templaited type and checks that the conversion type is compatible with type 
+     * @tparam the type of the return value 
+     * @return the value 
+    */
+    template <typename T>
+    T getValue() const {
+        if (type && *type == typeid(T)) {
+            //const Value<T>* typedValue = dynamic_cast<const Value<T>*>(static_cast<const BaseValue*>(value));
+            const ConditionalValue<T>* typedValue = dynamic_cast<const ConditionalValue<T>*>(value.get());
+            if (typedValue) {
+                return typedValue->value;
+            }
+        }
+        throw std::runtime_error(std::string("DATA ERROR ") + type->name() + " != " + typeid(T).name());
+    }
+    ///////////////////////////////////
+    //
+    ///////////////////////////////////
+    std::string getType() const {
+        return  type ? type->name() : "nullptr";
+    }
+    
+
+    template <typename T>
+    bool isTypeEqualTo() const {
+        return (type && *type == typeid(T));
+    }
+
+    void deleteValue() {
+        if (type) {
+            value.reset();
+            type = nullptr;
+        }
+    }
+
+    ~ConditionalData() { // TODO best can we have a liste of type supported ?
+       deleteValue();
+    }
+};
+
+}
+
+
+#endif //_AIDGE_CONDITIONAL_DATA_H_
\ No newline at end of file
diff --git a/include/aidge/nodeTester/ConditionalInterpreter.hpp b/include/aidge/nodeTester/ConditionalInterpreter.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e5f971a81b6964c137ae489b46b921953975946d
--- /dev/null
+++ b/include/aidge/nodeTester/ConditionalInterpreter.hpp
@@ -0,0 +1,326 @@
+
+
+#ifndef _AIDGE_CONDITIONAL_INTERPRETER_H_
+#define _AIDGE_CONDITIONAL_INTERPRETER_H_
+
+#include "aidge/nodeTester/ConditionalParser.hpp"
+#include "aidge/nodeTester/ConditionalData.hpp"
+
+#include <memory> // for shared_ptr
+#include <unordered_map>
+#include <functional>
+#include "aidge/graph/Node.hpp"
+#include <sstream>
+
+
+namespace Aidge{
+
+
+
+//////////////////////////////
+//
+/////////////////////////////
+/**
+ * @brief class used to register any lambda function without context, 
+ * it encapsulates the source lambda in a lambda which takes as argument ConditionalData* which are any type. 
+ * @see ConditionalData
+ */
+class ConditionalRegisterFunction {
+    //////////////////////////
+    //Safe recaste
+    //////////////////////////
+
+    /**
+     * @brief recaste the ConditionalData* to the argument type of the lambda
+     * @tparam T type of the lambda argument 
+     * @see ConditionalData
+     */
+    template <typename T>
+    T safeCastInput(ConditionalData* data) {
+        //cnvertion and type cheking
+        if (data->isTypeEqualTo<T>()){
+            return data->getValue<T>();
+        }else{
+            throw std::invalid_argument( "incompatible input type " + data->getType() +" "+ typeid(T).name() );
+        }
+       
+    }
+    
+    
+    /**
+     * @brief recaste the output of the lambda to a  ConditionalData* 
+     * @tparam T type of the lambda return 
+     * @see ConditionalData
+     */
+    template <typename T>
+    ConditionalData* safeCastOutput(T data) {
+        
+        ConditionalData* out = new ConditionalData;
+        out->setValue<T>(data);
+        
+        return out;
+    }
+    
+    
+    
+    
+    //////////////////////
+    // get all the type of the function 
+    //////////////////////
+
+    /**
+     * @brief Retrieves information about a function's return type and argument types.
+     * @tparam T The function type.
+     */
+    template <typename T>
+    struct function_traits;
+    
+
+    /**
+     * @brief Specialization of function_traits for function pointers.
+     * @tparam R The return type of the function.
+     * @tparam Args The argument types of the function.
+     */
+    template <typename R, typename... Args>
+    struct function_traits<R (*)(Args...)> {
+        using return_type = R;
+        static constexpr std::size_t arity = sizeof...(Args);
+    
+        template <std::size_t N>
+        struct argument {
+            static_assert(N < arity, "Index out of range.");
+            using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
+        };
+    };
+
+    /**
+     * @brief Specialization of function_traits for std::function types.
+     * @tparam R The return type of the function.
+     * @tparam Args The argument types of the function.
+     */
+    template <typename R, typename... Args>
+    struct function_traits<std::function<R(Args...)>> {
+        using return_type = R;
+        static constexpr std::size_t arity = sizeof...(Args);
+    
+        template <std::size_t N>
+        struct argument {
+            static_assert(N < arity, "Index out of range.");
+            using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
+        };
+    };
+    
+    /////////////////////
+    //change the function to ConditionalData*(std::vector<ConditionalData*>)
+    /////////////////////
+    
+    /**
+     * @brief Converts a function to a ConditionalData*(std::vector<ConditionalData*>).
+     * @tparam F The type of the function to convert.
+     * @tparam ParamsIdx The indices of the function parameters.
+     * @param f The function to convert.
+     * @return The pointer to the converted function.
+     */
+    template <class F, std::size_t... ParamsIdx>
+    auto funcPointer(F f, std::index_sequence<ParamsIdx...>) {
+        //wrapp the lambda in a new one that as ConditionalData as inputs and output
+    	return [this,f](std::vector<ConditionalData*>  &args) {
+            if (args.size() != sizeof...(ParamsIdx)){
+                std::ostringstream errorMessage;
+                errorMessage << "bad Number of argument: get " << args.size() << " need " << sizeof...(ParamsIdx) << "\n";
+                throw std::runtime_error(errorMessage.str()); 
+            }
+    		//assert(args.size() == sizeof...(ParamsIdx));//the size of the vector valide 
+
+    		using FuncTraits = function_traits<decltype(f)>;
+    		using outType = typename FuncTraits::return_type;
+    		
+    		outType result = f(safeCastInput<typename FuncTraits::template argument<ParamsIdx>::type>(args[ParamsIdx])...);
+    		//typename 
+    		return safeCastOutput<outType>(result);
+    	};
+    }
+    
+    /**
+     * @brief Converts a function pointer to a ConditionalData*(std::vector<ConditionalData*>).
+     * @tparam R The return type of the function.
+     * @tparam Params The parameter types of the function.
+     * @param f The function pointer to convert.
+     * @return The pointer to the converted function.
+     */
+    template <class R,class... Params>
+    auto funcPointer(R (*f)(Params...)) {
+    	return funcPointer(f, std::index_sequence_for<Params...>{});
+    }
+
+    /**
+     * @brief Converts a std::function to a ConditionalData*(std::vector<ConditionalData*>).
+     * @tparam R The return type of the function.
+     * @tparam Params The parameter types of the function.
+     * @param f The function pointer to convert.
+     * @return The pointer to the converted function.
+     */
+    template <class R,class... Params>
+    auto funcPointer(std::function<R(Params...)> f) {
+    	return funcPointer(f, std::index_sequence_for<Params...>{});
+    }
+    
+    
+    ///////////////////
+    // interface
+    ///////////////////
+        
+    public:
+    
+     /**
+     * @brief Default constructor 
+     */
+    ConditionalRegisterFunction(){}
+    
+    
+     /**
+     * @brief Inserts a function into the map with the provided key.
+     * @tparam T The function type.
+     * @param key The key to associate with the function.
+     * @param f The function to insert.
+     */
+    template <class T>
+    void insert(const std::string key,T f){
+        mWlambda.insert({ key, funcPointer(f)});
+    }
+    
+    
+     /**
+     * @brief Runs the function associated with the given key, using the provided vector of input data.
+     * @param key The key of the function to run.
+     * @param datas The vector of input data.
+     * @return A pointer to the output ConditionalData object.
+     */
+    ConditionalData* run(const std::string key,std::vector<ConditionalData*> & datas);
+    
+    private:
+    /// @brief map of name and the converted function.
+    std::map<const std::string, std::function<ConditionalData*(std::vector<ConditionalData*>  &)>> mWlambda;
+};
+
+///////////////////
+//AST tree node
+// ////////////////
+/**
+ * @brief this class interprets AST to generate a test on a graph node. For each AST node, 
+ * it generates an interpretation and registers lambda functions that can be used in the test expression.  
+ * there are two lambda control mechanisms:
+ * - A cpp mechanism which allows any lambda to be inserted into the constructor that use templaite
+ * - A user mechanism limited to lambda bool(NodePtr)
+ * @see ConditionalParser use to get the AST
+ */
+class ConditionalInterpreter
+{
+    private:
+
+    /**
+     * @brief the AST generate by the Parser
+     * @see ConditionalParser
+     */
+    std::shared_ptr<AstNode<ConditionalTokenTypes>> mTree;
+    /**
+     * @brief the registery for the lambda fuction
+     * @see ConditionalRegisterFunction
+    */
+    ConditionalRegisterFunction mLambdaRegiter;
+    
+    public:
+    /**
+     * @brief Constructor 
+     * @param ConditionalExpressions The expression of the test to be performed on the nodes
+     */
+
+    ConditionalInterpreter(const std::string ConditionalExpressions);
+    
+    /**
+     * @brief Test a node depending of the ConditionalExpressions
+     * @details the AST is visit using \ref visit() whith the $ init whit the nodeOp
+     * @return bool the match node has the initialized expresion 
+     * @see visit() This function uses the visit() function to perform the evaluation.
+     */
+    bool test( const NodePtr nodeOp);
+
+    /**
+     * @brief Interface for inserting custom lambda bool(NodePtr) functions in AST interpretation,
+     *         it will be available in the ConditionalExpressions expretion as : key($)
+     * @param key The key that will be used to call the function in the expression
+     * @param f The pointer to function 
+     */
+    void insertLambda(const std::string key,std::function<bool(Aidge::NodePtr)> f);
+
+
+    /////
+
+    private:
+    /**
+     * @brief Recursive AST traversal function, using the for interpreting AST nodes function,
+     * using \ref ASTnodeInterpreterF fuctions
+     * @param NodeOp The node currently being tested 
+     * @param nodes The AST given by the parsing process 
+     */
+    std::vector<ConditionalData*> visit(const ASTNodeCh& nodes, const NodePtr NodeOp );
+
+    /**
+     * @defgroup ASTnodeInterpreterF Functions for interpreting AST nodes 
+     * @brief For each node type in the AST, function defines the processing to be performed 
+     *          they return a  std::vector<ConditionalData*> which corresponds to the value(s) obtained 
+     */
+
+    /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief Function that does something.
+     */
+    std::vector<ConditionalData*> fLambda(const std::shared_ptr<AstNode<ConditionalTokenTypes>>& node,std::vector<ConditionalData*> datas);
+    /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief Converted the lexeme to a int and to ConditionalData*
+     */
+    std::vector<ConditionalData*> fStrToInteger(const std::shared_ptr<AstNode<ConditionalTokenTypes>>& node);
+    /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief Converted the lexeme to a float and to ConditionalData*
+     */
+    std::vector<ConditionalData*> fStrToFloat(const std::shared_ptr<AstNode<ConditionalTokenTypes>>& node);
+    /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief Converted the lexeme to a str and to ConditionalData*
+     */
+    std::vector<ConditionalData*> fStrToStr(const std::shared_ptr<AstNode<ConditionalTokenTypes>>& node);
+
+    /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief makes the == operation between two previously converted ConditionalData* 
+     */
+    std::vector<ConditionalData*> fEq(std::vector<ConditionalData*> datas);
+       /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief makes the != operation between two previously converted ConditionalData* 
+     */
+    std::vector<ConditionalData*> fNeq(std::vector<ConditionalData*> datas);
+    /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief makes the && operation between two previously converted ConditionalData* in bool 
+     */
+    std::vector<ConditionalData*> fAnd(std::vector<ConditionalData*> datas);
+        /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief makes the || operation between two previously converted ConditionalData* in bool 
+     */
+    std::vector<ConditionalData*> fOr(std::vector<ConditionalData*> datas);
+
+    /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief makes the ! operation 
+     */
+    std::vector<ConditionalData*> fNot(std::vector<ConditionalData*> datas);
+};
+
+
+}
+
+#endif //_AIDGE_CONDITIONAL_INTERPRETER_H_
diff --git a/include/aidge/nodeTester/ConditionalLexer.hpp b/include/aidge/nodeTester/ConditionalLexer.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..770f5a11b6ede54107823dc05bb41bbeb0e370eb
--- /dev/null
+++ b/include/aidge/nodeTester/ConditionalLexer.hpp
@@ -0,0 +1,86 @@
+/**
+ * @file
+ * @brief 
+ * @version file 1.0.0
+ * @author vl241552
+ * @copyright
+ *  Copyright (c) 2023 CEA, LIST, Embedded Artificial Intelligence Laboratory. All
+ *  rights reserved.
+ */
+
+
+
+#ifndef _AIDGE_CONDITIONAL_LEXER_H_
+#define _AIDGE_CONDITIONAL_LEXER_H_
+
+#include <string>
+#include <regex>
+#include <memory> // for shared_ptr
+
+
+#include <stdexcept> //error
+#include <sstream>
+
+#include "aidge/nodeTester/ConditionalTypes.hpp"
+#include "aidge/utilsParsing/ParsingToken.hpp"
+namespace Aidge{
+
+
+
+class ConditionalLexer
+{
+
+public:
+ConditionalLexer( const std::string ConditionalExpressions );
+
+/**
+ * @brief Get the next token on the ConditionalExpressions
+ * @return ParsingToken<ConditionalTokenTypes> 
+ */
+std::shared_ptr<ParsingToken<ConditionalTokenTypes>> getNextToken(void);
+/**
+ * @brief Restart at the start of the ConditionalExpressions 
+ * 
+ */
+void rstPosition(void);
+
+/**
+ * @brief Test if the string is completely read 
+ * @return bool 
+ */
+bool isEnd(void);
+
+
+/**
+ * @brief Get the representation of the class
+ * @return string 
+ */
+const std::string rep(){
+   return mConditionalExpressions;
+}
+
+private:
+
+/**
+ * @brief Constructs an error message to display the character not understood by the lexer 
+ * @return error mesage 
+ */
+std::runtime_error badTokenError(const std::string& currentChars,std::size_t position);
+
+/**
+ * @brief The expression of the test to be performed on the nodes
+ */
+const std::string mConditionalExpressions;
+/**
+ * @brief The lexer's current position in mConditionalExpressions
+ */
+std::size_t mPosition;
+
+};
+
+/////////////////////////////////////
+
+
+}
+
+#endif //_AIDGE_CONDITIONAL_LEXER_H_
\ No newline at end of file
diff --git a/include/aidge/nodeTester/ConditionalParser.hpp b/include/aidge/nodeTester/ConditionalParser.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a1d1ccad27f2a6eb6de39d1b22c32a859a3c3c1f
--- /dev/null
+++ b/include/aidge/nodeTester/ConditionalParser.hpp
@@ -0,0 +1,106 @@
+
+
+
+#ifndef _AIDGE_CONDITIONAL_PARSER_H_
+#define _AIDGE_CONDITIONAL_PARSER_H_
+
+
+#include <memory> // for shared_ptr
+
+#include "aidge/nodeTester/ConditionalLexer.hpp"
+#include "aidge/nodeTester/ConditionalTypes.hpp"
+#include "aidge/utilsParsing/ParsingToken.hpp"
+#include "aidge/utilsParsing/AstNode.hpp"
+
+namespace Aidge{
+
+const std::map<ConditionalTokenTypes, std::size_t> ConditionalPrec{
+    {ConditionalTokenTypes::AND,2},
+    {ConditionalTokenTypes::OR,1}
+};
+
+
+    
+
+using ASTNodeCh = std::vector<std::shared_ptr<AstNode<ConditionalTokenTypes>>>;
+
+/**
+ * @brief this class uses the lexer to create an AST according to a set of gramer rules 
+ */
+class ConditionalParser{
+    
+    public:
+    /**
+     * @brief AST graph creation function 
+     * @param ConditionalExpressions String representing the logical fuction to be performed
+     */
+    ConditionalParser(const std::string ConditionalExpressions);
+
+    /**
+     * @brief AST graph creation function 
+     * @return The AST tree 
+     */
+    std::shared_ptr<AstNode<ConditionalTokenTypes>> parse(void);
+
+
+    private:
+    /**
+     * @brief restart at the start of the ConditionalExpressions for LEXER and restart  mCurrentToken
+     */
+    void rstParser(void);
+    
+    //////////////////
+
+    /**
+     * @defgroup ParsingFunctions Function for creating AST
+     * @brief Functions for recursive construction of the AST representing grammar rules
+     */
+
+    /**
+     * @ingroup ParsingFunctions
+     * @brief Token reading and verification function  
+     * 
+     */
+    void ackToken(ConditionalTokenTypes  tokenType);
+
+    /**
+     * @ingroup ParsingFunctions
+     * @brief Function of grammar rules for values : (KEY|INTEGER|FOAT|STRING|LAMBDA lambda)
+     * @return AST node 
+     */
+    std::shared_ptr<AstNode<ConditionalTokenTypes>> constructAstVal(void);
+    /**
+    * @ingroup ParsingFunctions
+    * @brief Function of grammar rules for comparison : val (EQ|NEQ) val | LPAREN expr RPAREN
+    * @return AST node 
+    */
+    std::shared_ptr<AstNode<ConditionalTokenTypes>> constructAstCmpr(void);
+    /**
+    * @ingroup ParsingFunctions
+    * @brief Function of grammar rules for arguments of a lambda : LAMBDA val (ARGSEP val)* RPAREN
+    * @return AST node 
+    */
+    std::shared_ptr<AstNode<ConditionalTokenTypes>> constructAstLambda(void);
+    /**
+    * @ingroup ParsingFunctions
+    * @brief Function of grammar rules for a expresion : cmpr ((AND | OR) cmpr)*
+    * @return AST node 
+    */
+    std::shared_ptr<AstNode<ConditionalTokenTypes>> constructAstExpr(std::size_t precLimit = 0);
+
+
+    /**
+    * @brief The actual token in the parce
+    */
+    std::shared_ptr<ParsingToken<ConditionalTokenTypes>> mCurrentToken;
+    /**
+    * @brief The lexem use
+    */
+    ConditionalLexer mLexer;
+
+};
+
+
+}
+
+#endif //_AIDGE_CONDITIONAL_PARSER_H_
diff --git a/include/aidge/nodeTester/ConditionalTypes.hpp b/include/aidge/nodeTester/ConditionalTypes.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d88ea639a0c44b118e834e7da6d2d0ef0b451ba1
--- /dev/null
+++ b/include/aidge/nodeTester/ConditionalTypes.hpp
@@ -0,0 +1,34 @@
+
+
+#ifndef _AIDGE_CONDITIONAL_TYPES_H_
+#define _AIDGE_CONDITIONAL_TYPES_H_
+namespace Aidge{
+    /**
+     * @brief enum for all types of token use in the parsing 
+     * 7-5 type
+     * 4-0 id
+    */
+    enum class ConditionalTokenTypes
+    {
+        NOT                 = (1 << 4)+3, /**< ! */ 
+        AND                 = (1 << 4)+2, /**< && */ 
+        OR                  = (1 << 4)+1, /**< || */ 
+
+        EQ                  = (1 << 5)+1, /**< == */ 
+        NEQ                 = (1 << 5)+2, /**< != */ 
+
+        KEY                 = (1 << 6) +1 , /**< [A-Za-z][A-Za-z0-9_]* */
+        INTEGER             = (1 << 6) +2 , /**< [0-9]+ */
+        FLOAT               = (1 << 6) +3 , /**< [0-9]+\.[0-9]* */
+        STRING              = (1 << 6) +4 , /**< \'.*\' */
+        BOOL                = (1 << 6) +5 , /**< true|false */
+        NODE                = (1 << 6) +6 , /**< \$ */
+        LAMBDA              = (1 << 6) +7 , /**< [A-Za-z][A-Za-z0-9_]*\( */
+
+        ARGSEP              = (1<<7) +1, /**< , */
+        LPAREN              = (1<<7) +2, /**< \( */
+        RPAREN              = (1<<7) +3, /**< \) */
+        STOP                = 0,
+    };
+}
+#endif
\ No newline at end of file
diff --git a/include/aidge/utilsParsing/AstNode.hpp b/include/aidge/utilsParsing/AstNode.hpp
index 1158ae148a22993476adb00ecbf8ebd24101830c..9eaf30ee753d6c787dbebad3767d210a366e1748 100644
--- a/include/aidge/utilsParsing/AstNode.hpp
+++ b/include/aidge/utilsParsing/AstNode.hpp
@@ -12,11 +12,11 @@
 namespace Aidge{
 
     template <typename EnumType>
-    class AstNode: public std::enable_shared_from_this<AstNode>
+    class AstNode: public std::enable_shared_from_this<AstNode<EnumType>>
     {
         static_assert(std::is_enum<EnumType>::value, "AstNode EnumType must be an enum type");
         public:
-        AstNode(std::shared_ptr<ParsingToken<EnumType>> token,std::vector<std::shared_ptr<AstNode>> child ={}):mToken(token),mChild(child){}
+        AstNode(std::shared_ptr<ParsingToken<EnumType>> token,std::vector<std::shared_ptr<AstNode<EnumType>>> child ={}):mToken(token),mChild(child){}
         /**
          * @brief get the type of the token
          * @return the type
diff --git a/include/aidge/utilsParsing/ParsingToken.hpp b/include/aidge/utilsParsing/ParsingToken.hpp
index 78045cf3085a18bfd0565354fd34aef02ef395bd..265b5a8b04fd3e6a3dd0c7ebdc7ff56d426f4787 100644
--- a/include/aidge/utilsParsing/ParsingToken.hpp
+++ b/include/aidge/utilsParsing/ParsingToken.hpp
@@ -4,10 +4,12 @@
 
 #include <string>
 #include <type_traits>
+#include <sstream> // Include the necessary header
 
 namespace Aidge{
+
     template <typename EnumType>
-    class ParsingToken: public std::enable_shared_from_this<ParsingToken>
+    class ParsingToken: public std::enable_shared_from_this<ParsingToken<EnumType>>
     {
         static_assert(std::is_enum<EnumType>::value, "ParsingToken EnumType must be an enum type");
         public:
@@ -16,7 +18,7 @@ namespace Aidge{
          * @param type one of the token type
          * @param lexeme String representing aditional information of the token
          */
-        ParsingToken(const EnumType type , const std::string lexeme )mLexeme(lexeme),mType(type){}
+        ParsingToken(const EnumType type , const std::string lexeme ):mLexeme(lexeme),mType(type){}
 
         /**
          * @brief get the lexeme
@@ -39,7 +41,10 @@ namespace Aidge{
          * @brief copy the token
          * @return deep copy of the token
          */
-        std::shared_ptr<Aidge::ParsingToken> copy();
+        std::shared_ptr<ParsingToken> copy(){
+            auto newToken = std::make_shared<ParsingToken<EnumType>>(mType,mLexeme);
+            return newToken;
+        }
 
         //TODO
         std::ostringstream rep(void){
@@ -47,6 +52,7 @@ namespace Aidge{
             out << " Token ("  << mLexeme <<")" << "\n";
             return out;
         }
+
         private:
 
         /**
diff --git a/src/graphRegex/GraphFsmInterpreter.cpp b/src/graphRegex/GraphFsmInterpreter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6d04fc97cf6d66ad4ca170b18d078833bd98d7eb
--- /dev/null
+++ b/src/graphRegex/GraphFsmInterpreter.cpp
@@ -0,0 +1,182 @@
+#include "aidge/graphRegex/GraphFsmInterpreter.hpp"
+
+using namespace Aidge; 
+
+
+GraphFsmInterpreter::GraphFsmInterpreter(const std::string graphMatchExpr,std::map<std::string,std::shared_ptr<ConditionalInterpreter>> nodesCondition):mParser(graphMatchExpr){
+    mActGroupe = 0;
+    mNodesCondition = nodesCondition;
+}
+std::shared_ptr<FsmGraph>  GraphFsmInterpreter::interpret(void){
+    mActGroupe = 0;
+    std::shared_ptr<AstNode<gRegexTokenTypes>> tree = mParser.parse();
+    return visit(tree);
+}
+std::shared_ptr<FsmGraph> GraphFsmInterpreter::visit(std::shared_ptr<AstNode<gRegexTokenTypes>> AstTree){
+
+    std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>> nextAstNodes = AstTree->getChilds();
+
+    if(AstTree->getType() == gRegexTokenTypes::SEP){
+        return sepF(visit(nextAstNodes[0]),visit(nextAstNodes[1]));
+    }else if(AstTree->getType() == gRegexTokenTypes::NEXT){
+        return nextF(visit(nextAstNodes[0]),visit(nextAstNodes[1]));
+    }else if(AstTree->getType() == gRegexTokenTypes::QOM){
+        return qomF(visit(nextAstNodes[0]));
+    }else if(AstTree->getType() == gRegexTokenTypes::QZM){
+        return qzmF(visit(nextAstNodes[0]));
+    }else if(AstTree->getType() == gRegexTokenTypes::KEY || AstTree->getType() == gRegexTokenTypes::CKEY){
+        return keyF(AstTree);
+    }else if(AstTree->getType() == gRegexTokenTypes::LPAREN){
+        mActGroupe += 1;
+        std::shared_ptr<FsmGraph> out = visit(nextAstNodes[0]);
+        mActGroupe -= 1;
+        return out;
+    }else{
+        throw std::logic_error("visit Bad token type" );
+    }
+}
+
+
+
+
+std::shared_ptr<FsmGraph> GraphFsmInterpreter::keyF(std::shared_ptr<AstNode<gRegexTokenTypes>> AstNode){
+    
+
+    std::shared_ptr<FsmNode>  start = std::make_shared<FsmNode>(false,true);
+    std::shared_ptr<FsmNode>  valid = std::make_shared<FsmNode>(true,false);
+    std::shared_ptr<FsmGraph> graph = std::make_shared<FsmGraph>();
+    std::shared_ptr<FsmEdge> edge;
+    
+
+    if(AstNode->getType() == gRegexTokenTypes::CKEY){
+        edge = FsmEdgeFactory::make(start,valid,FsmEdgeTypes::COMMON,mNodesCondition,AstNode->getValue());
+    }else if (AstNode->getType() == gRegexTokenTypes::KEY)
+    {
+        edge = FsmEdgeFactory::make(start,valid,FsmEdgeTypes::UNIQUE,mNodesCondition,AstNode->getValue());
+    }else{
+
+        throw std::logic_error("keyF Bad in AST" );
+    }
+    
+    graph->addEdge(edge);
+    graph->setGroupe(mActGroupe);
+    return graph;
+}
+
+
+std::shared_ptr<FsmGraph> GraphFsmInterpreter::sepF(std::shared_ptr<FsmGraph> leftFsm,std::shared_ptr<FsmGraph> rigthFsm){
+
+    size_t idxLeft = leftFsm->getNbSubFsm();
+    rigthFsm->incOrigineAllNodeBy(idxLeft);
+    leftFsm->unionG(rigthFsm);
+    //the rigthFsm is no longer usfull
+    return leftFsm;
+}
+
+
+std::shared_ptr<FsmGraph> GraphFsmInterpreter::nextF(std::shared_ptr<FsmGraph> leftFsm,std::shared_ptr<FsmGraph> rigthFsm){
+    /*
+        combine the 2 Graph
+        all valid node of A are  merge with Start B, Start B is un Start
+        update the relative reference  
+
+           A          B
+        SA -> VA + SB -> VB
+           A    B
+        SA -> q -> VB
+    */
+    leftFsm->mergeOneStartOneValid(rigthFsm);
+    //the rigthFsm is no longer usfull
+    return leftFsm;
+}
+std::shared_ptr<FsmGraph> GraphFsmInterpreter::qomF(std::shared_ptr<FsmGraph> fsm){
+    /*
+        +
+        valid node is connect to the child of Start with the same edge condition
+            A
+        S -> V
+
+            A
+        S -> V
+          (E|R)
+        V -> S
+    */
+
+    std::vector<std::shared_ptr<FsmNode>> allStart =  fsm->getStartNodes();
+    std::set<std::shared_ptr<FsmNode>> allValid = fsm->getValidNodes();
+    std::shared_ptr<FsmEdge> edge;
+
+    if(allStart.size() != 1){
+         throw std::logic_error("qomF Bad in AST" );
+    }
+
+    for(auto start : allStart ){
+        for(auto edgeStart :start->getEdges() ){
+            if (auto sharedEdge = edgeStart.lock()) {
+
+                const std::map<size_t, int> commonRef = sharedEdge->getRelative();
+                bool haveCommon = !commonRef.empty();
+
+                for(auto valid : allValid){
+                    if(haveCommon){
+                        /*
+                        the // quantif case 
+                        get the go back and make a lexeme id(number)
+                        we need to go back to the ref delta min #TODO
+                        */
+                        bool hasMinRef = false;
+                        std::pair<size_t, int> minRef;
+                        for (const auto& entry : commonRef) {
+                            if (!hasMinRef || std::abs(minRef.second) > std::abs(entry.second)) {
+                                hasMinRef = true;
+                                minRef = entry;
+                            }
+                        }
+                        std::stringstream lexem;
+                        lexem << "(" << minRef.first << ", " << minRef.second << ")";
+                        edge = FsmEdgeFactory::make(valid,start,FsmEdgeTypes::REF,mNodesCondition, lexem.str());
+                    }else{
+                        /*
+                        the sequensial quantif case 
+                        no reference to common 
+                        */
+                        edge = FsmEdgeFactory::make(valid,start,FsmEdgeTypes::EMPTY,mNodesCondition,"");
+
+                    }
+                    fsm->addEdge(edge);
+                }
+            }else{
+                throw std::runtime_error("edgeStart weak pointer is expired" );
+            }
+        }
+     
+    }
+    return fsm;
+
+}
+std::shared_ptr<FsmGraph> GraphFsmInterpreter::qzmF(std::shared_ptr<FsmGraph> fsm){
+        /*
+        qomf and a bypass empty start to valide 
+        */
+    fsm = qomF(fsm);
+
+    std::vector<std::shared_ptr<FsmNode>> allStart =  fsm->getStartNodes();
+    std::set<std::shared_ptr<FsmNode>> allValid = fsm->getValidNodes();
+    std::shared_ptr<FsmEdge> edge;
+
+    if(allStart.size() != 1){
+         throw std::logic_error("qzmF Bad in AST" );
+    }
+
+    for(auto start : allStart ){
+       
+        for(auto valid : allValid){
+            edge = FsmEdgeFactory::make(start,valid,FsmEdgeTypes::EMPTY,mNodesCondition,"");
+            fsm->addEdge(edge);
+        }
+    }
+        
+    return fsm;
+
+
+}
\ No newline at end of file
diff --git a/src/graphRegex/GraphLexer.cpp b/src/graphRegex/GraphLexer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..437c45f5088f459613cb63bbbdb96b7ea4e09145
--- /dev/null
+++ b/src/graphRegex/GraphLexer.cpp
@@ -0,0 +1,157 @@
+
+#include "aidge/graphRegex/GraphLexer.hpp"
+
+using namespace Aidge; 
+
+
+GraphLexer::GraphLexer( const std::string gRegexExpressions ):
+mRegularExpressions(gRegexExpressions){
+    mPosition = 0;
+}
+
+std::shared_ptr<ParsingToken<gRegexTokenTypes>> GraphLexer::getNextToken(void){
+    std::string currentChars = "";
+    while (mPosition < mRegularExpressions.length())
+    {
+        //erase all space 
+        if (mRegularExpressions[mPosition] != ' ')
+        {
+            currentChars += mRegularExpressions[mPosition];
+        }
+        else
+        {
+            mPosition++;
+            continue;
+        }
+
+        /////
+        // const lent token
+        /////
+
+        if (std::regex_match(currentChars,std::regex("\\->")))// the next TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::NEXT,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("\\*")))// the * TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::QZM,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("\\+")))// the + TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::QOM,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("\\(")))// the LPAREN TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::LPAREN,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("\\)")))// the RPAREN TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::RPAREN,"");
+        }
+
+        //
+        else if (std::regex_match(currentChars,std::regex(";")))// the SEP TOKEN 
+        {
+            //test if the last sep
+            //std::string subStr = mRegularExpressions.substr(mPosition);
+            mPosition++;
+            return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::SEP,"");
+        }
+
+        /////
+        //unconst lent token
+        /////
+
+        else if (std::regex_match(currentChars,std::regex("[A-Za-z_0-9]")))// the KEY or CKEY
+        {   
+            
+            //read all the key 
+            bool isCKey = false;
+            std::regex keyRegex("[A-Za-z_0-9]+");
+            std::regex cKeyRegex("[A-Za-z_0-9]+\\#[0-9]*");
+
+            while ( mPosition < mRegularExpressions.length()) {
+
+                if(!std::regex_match(currentChars,keyRegex) && !std::regex_match(currentChars,cKeyRegex))
+                {
+                    currentChars.pop_back(); //the last char is the problemes
+                    break;
+                }
+                else if (std::regex_match(currentChars,cKeyRegex)){
+                    isCKey = true;
+                }
+                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
+            //we are not we can continu
+            if (mPosition == mRegularExpressions.length()-1)
+            {
+                if (!std::regex_match(currentChars,keyRegex) && !std::regex_match(currentChars,cKeyRegex))
+                {
+                    throw badTokenError(currentChars,mPosition);
+                }
+                //mPosition++; // we stop all by going pos > lengt
+            }
+
+
+            if (isCKey){
+                return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::CKEY,currentChars);
+            } else{
+                return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::KEY,currentChars);
+            }
+        }
+
+        mPosition++;
+    }
+
+
+    //no more to find no one match the currentChars 
+    if (currentChars.empty()) {
+        return  std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::STOP,"");  // Null shared pointer ;
+    }else{
+        throw badTokenError(currentChars,mPosition);
+    }
+
+}
+
+void GraphLexer::rstPosition(void){
+    if (isEnd()){
+        mPosition = 0;
+    }else{
+        throw badTokenError("end rst",mPosition);
+    }
+}
+
+bool GraphLexer::isEnd(void){
+    return mPosition >= mRegularExpressions.length();
+}
+
+std::runtime_error GraphLexer::badTokenError(const std::string& currentChars,std::size_t position){
+    std::ostringstream errorMessage;
+    errorMessage << "\nBad syntax " << currentChars << " :\n" << mRegularExpressions << "\n";
+    for (std::size_t i = 0; i < position; i++) {
+        errorMessage << ' ';
+    }
+    errorMessage << "^\n";
+
+    return std::runtime_error(errorMessage.str());
+}
+
+  const std::string GraphLexer::rep(){
+    std::string out = mRegularExpressions;
+    out += "\n";
+    for (std::size_t i = 0; i < mPosition; i++) {
+        out += ' ';
+    }
+    out +=  "^\n";
+    return out ;
+    }
\ No newline at end of file
diff --git a/src/graphRegex/GraphParser.cpp b/src/graphRegex/GraphParser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..be7b6904023436c822bb1c6ab2c81d0b8de40f02
--- /dev/null
+++ b/src/graphRegex/GraphParser.cpp
@@ -0,0 +1,174 @@
+#include "aidge/graphRegex/GraphParser.hpp"
+
+using namespace Aidge; 
+
+GraphParser::GraphParser(const std::string gRegexExpressions):
+mLexer(gRegexExpressions)
+{
+    mCurrentToken = mLexer.getNextToken();
+}
+
+
+std::shared_ptr<AstNode<gRegexTokenTypes>> GraphParser::parse(void){
+
+    std::shared_ptr<AstNode<gRegexTokenTypes>> astTree = constructAstAllExpr();
+    rstParser();
+    return astTree;
+}
+
+
+void GraphParser::rstParser(void){
+    mLexer.rstPosition();
+    mCurrentToken = mLexer.getNextToken();
+}
+
+
+void GraphParser::ackToken(gRegexTokenTypes  tokenType){
+    
+    if(mCurrentToken->getType() == tokenType ){
+        try {
+            mCurrentToken = mLexer.getNextToken();
+        } catch (const std::runtime_error& e) {
+            std::ostringstream errorMessage;
+            errorMessage << "Graph Lexer error in Parser :\n"<< e.what() << std::endl;
+            throw std::runtime_error(errorMessage.str());
+        }
+    }else{
+        std::ostringstream errorMessage;
+        errorMessage << "Bad syntax GraphParser " << static_cast<int>(mCurrentToken->getType())  <<"!="<< static_cast<int>(tokenType) << "\n";
+        errorMessage << mLexer.rep();
+        throw std::runtime_error(errorMessage.str());
+    }
+}
+
+/*
+exp : KEY(QOM | QZM)?  | CKEY | domain
+*/
+std::shared_ptr<AstNode<gRegexTokenTypes>> GraphParser::constructAstExp(void)
+{
+
+    try{
+        std::shared_ptr<ParsingToken<gRegexTokenTypes>> token = mCurrentToken->copy();
+        std::shared_ptr<AstNode<gRegexTokenTypes>> node = std::make_shared<AstNode<gRegexTokenTypes>>(token);
+
+        if (mCurrentToken->getType() == gRegexTokenTypes::KEY  ){
+            ackToken(gRegexTokenTypes::KEY );
+            if (mCurrentToken->getType() == gRegexTokenTypes::QOM  ){
+                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  ){
+                ackToken(gRegexTokenTypes::QZM );
+                std::shared_ptr<AstNode<gRegexTokenTypes>> newNode = std::make_shared<AstNode<gRegexTokenTypes>>(token,
+                std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{node});
+                return newNode;
+            }
+            return node;
+        }else if (mCurrentToken->getType() == gRegexTokenTypes::CKEY){
+            ackToken(gRegexTokenTypes::CKEY );
+            return node;
+        }else{
+            return constructAstDomain();
+        }
+
+    } catch (const std::runtime_error& e) {
+        std::ostringstream errorMessage;
+        errorMessage << "GraphParser constructAstExp :\n"<< e.what() << std::endl;
+        throw std::runtime_error(errorMessage.str());
+    }
+}
+
+/*
+seq :exp (NEXT seq)* 
+*/
+std::shared_ptr<AstNode<gRegexTokenTypes>> GraphParser::constructAstSeq(void)
+{
+
+   try{
+   
+        std::shared_ptr<AstNode<gRegexTokenTypes>> left = constructAstExp();
+        if(mCurrentToken->getType() == gRegexTokenTypes::NEXT ) 
+        {
+            std::shared_ptr<ParsingToken<gRegexTokenTypes>> token = mCurrentToken->copy();
+            ackToken(gRegexTokenTypes::NEXT);
+            std::shared_ptr<AstNode<gRegexTokenTypes>> newNode = std::make_shared<AstNode<gRegexTokenTypes>>(token,
+            std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{left,constructAstSeq()});
+            left = newNode;
+        }
+        return left;
+
+    } catch (const std::runtime_error& e) {
+        std::ostringstream errorMessage;
+        errorMessage << "GraphParser constructAstSeq :\n"<< e.what() << std::endl;
+        throw std::runtime_error(errorMessage.str());
+    }
+
+}
+
+
+/*
+LPAREN seq RPAREN (QOM | QZM) 
+*/
+std::shared_ptr<AstNode<gRegexTokenTypes>> GraphParser::constructAstDomain(void)
+{
+
+   try{
+        std::shared_ptr<ParsingToken<gRegexTokenTypes>> token ;
+        std::shared_ptr<AstNode<gRegexTokenTypes>> node ;
+ 
+        token = mCurrentToken->copy();
+        ackToken(gRegexTokenTypes::LPAREN);
+        node = std::make_shared<AstNode<gRegexTokenTypes>>(token,
+        std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{constructAstSeq()});
+        ackToken(gRegexTokenTypes::RPAREN);
+        //(QOM | QZM)
+
+        token = mCurrentToken->copy();
+        if (mCurrentToken->getType() == gRegexTokenTypes::QOM){
+            ackToken(gRegexTokenTypes::QOM);
+            node = std::make_shared<AstNode<gRegexTokenTypes>>(token,
+            std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{node});
+        }else if (mCurrentToken->getType() == gRegexTokenTypes::QZM){
+            ackToken(gRegexTokenTypes::QZM);
+            node = std::make_shared<AstNode<gRegexTokenTypes>>(token,
+            std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{node});
+        }else{
+            std::ostringstream errorMessage;
+            errorMessage << "Bad syntax constructAstDomain must have quantifier \n";
+            throw std::runtime_error(errorMessage.str());
+        }
+   
+        return node;
+
+    } catch (const std::runtime_error& e) {
+        std::ostringstream errorMessage;
+        errorMessage << "GraphParser constructAstDomain :\n"<< e.what() << std::endl;
+        throw std::runtime_error(errorMessage.str());
+    }
+}
+
+/*
+        allExpr: seq (SEP allExpr)*
+*/
+std::shared_ptr<AstNode<gRegexTokenTypes>> GraphParser::constructAstAllExpr(void)
+{
+
+    try{
+        std::shared_ptr<AstNode<gRegexTokenTypes>> left = constructAstSeq();
+        if(mCurrentToken->getType() == gRegexTokenTypes::SEP ) 
+        {
+            std::shared_ptr<ParsingToken<gRegexTokenTypes>> token = mCurrentToken->copy();
+            ackToken(gRegexTokenTypes::SEP);
+            std::shared_ptr<AstNode<gRegexTokenTypes>> newNode = std::make_shared<AstNode<gRegexTokenTypes>>(token,
+            std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{left,constructAstAllExpr()});
+            left = newNode;
+        }
+        return left;
+
+    } catch (const std::runtime_error& e) {
+        std::ostringstream errorMessage;
+        errorMessage << "GraphParser constructAstDomain :\n"<< e.what() << std::endl;
+        throw std::runtime_error(errorMessage.str());
+    }
+}
diff --git a/src/graphRegex/matchFsm/FsmEdge.cpp b/src/graphRegex/matchFsm/FsmEdge.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cb5f8c058fe754674e64c9e400f3d459b356a387
--- /dev/null
+++ b/src/graphRegex/matchFsm/FsmEdge.cpp
@@ -0,0 +1,269 @@
+#include "aidge/graphRegex/matchFsm/FsmEdge.hpp"
+#include "aidge/graphRegex/matchFsm/FsmNode.hpp"
+#include "aidge/graphRegex/matchFsm/FsmRunTimeContext.hpp"
+
+using namespace Aidge; 
+
+std::map<std::string,int> FsmEdgeCommon::mCommonIdxMap;
+
+bool FsmEdge::isCommon(void){
+    return false;
+}
+
+size_t FsmEdge::getCommonIdx(void){
+    return std::numeric_limits<std::size_t>::max();
+}
+const std::map<size_t,int>& FsmEdge::getRelative(void){
+    return mRelativePos;
+}
+void FsmEdge::updateRelative( const std::map<size_t,int>& relativePos ){
+    for (const auto& kvp : relativePos) {
+            mRelativePos.insert(kvp);
+    }
+}
+std::shared_ptr<FsmNode> FsmEdge::getSourceNode(void){
+    return mNodeSource;
+}
+void FsmEdge::reSetSouceNode(const std::shared_ptr<FsmNode>& newSource){
+    mNodeSource->rmEdge(shared_from_this());
+    mNodeSource = newSource;
+    mNodeSource->addEdge(shared_from_this());
+    propagateRelativePos();
+
+}
+std::shared_ptr<FsmNode> FsmEdge::getDestNode(void){
+    return mNodeDest;
+}
+void FsmEdge::reSetDestNode(const std::shared_ptr<FsmNode>& newDest){
+        mNodeDest->rmParent(mNodeSource);
+        mNodeDest = newDest;
+        mNodeDest->addParent(mNodeSource);
+        propagateRelativePos();
+}
+void FsmEdge::propagateRelativePos(void){
+
+    std::set<int> myRelativeID;
+    for (const auto& kvp : mRelativePos) {
+        myRelativeID.insert(kvp.first);
+    }
+
+    for (const auto nextWeakEdge : mNodeDest->getEdges()){
+
+        if (auto nextEdge = nextWeakEdge.lock()) {
+            
+            if(this == nextEdge.get()){
+                continue;
+            }
+            
+
+            std::set<int> nextRelativeID;
+            for (const auto& kvp : nextEdge->getRelative()) {
+                nextRelativeID.insert(kvp.first);
+            }
+
+            // Find elements in myRelativeID but not in nextRelativeID
+            std::set<int> idxsToPush;
+            std::set_difference(myRelativeID.begin(), myRelativeID.end(),
+                                nextRelativeID.begin(), nextRelativeID.end(),
+                                std::inserter(idxsToPush, idxsToPush.begin()));
+
+            // Find elements in nextRelativeID but not in myRelativeID
+            std::set<int> idxsToGet;
+            std::set_difference(nextRelativeID.begin(), nextRelativeID.end(),
+                                myRelativeID.begin(), myRelativeID.end(),
+                                std::inserter(idxsToGet, idxsToGet.begin()));
+
+            //  test for integrity we look if 2 edge refert to the samme
+            //  ref and are link the ref dif is one
+            //  not working for common node
+            //  we can go deeper by find the all pass to a ref and see if the delta is good
+
+            // Find elements present in both myRelativeID and nextRelativeID
+            std::set<int> idxsTotest;
+            for (int idx : nextRelativeID){
+                if (myRelativeID.find(idx) != myRelativeID.end()){
+                    if (std::abs(getRelative().at(idx) - nextEdge->getRelative().at(idx)) != 1) {
+                        throw std::runtime_error("Bad relative");
+                    }
+                }
+            }
+
+
+            
+            // this egde have more relative info than the next
+            std::map<size_t,int> tmpRelative;
+            // we push this info to the next 
+            for( auto idxToPush :idxsToPush ){
+                tmpRelative.insert( std::make_pair(idxToPush, getRelative().at(idxToPush) +1));
+            }
+            if(tmpRelative.size() != 0){
+                nextEdge->updateRelative(tmpRelative);
+                nextEdge->propagateRelativePos();
+            }
+            tmpRelative.clear();
+
+
+            // the next node have more info than me i need to get it
+            for( auto idxToGet :idxsToGet ){
+                tmpRelative.insert( std::make_pair(idxToGet, nextEdge->getRelative().at(idxToGet) -1));
+            }
+            if(tmpRelative.size() != 0){
+                updateRelative(tmpRelative);
+                
+                for(auto weakParent : getSourceNode()->getParentNodes()){
+                    if (auto parent = weakParent.lock()) {
+                        for(auto weakPEdge : parent->getEdges()){
+                            if (auto pEdge = weakPEdge.lock()) {
+                                pEdge->propagateRelativePos();
+                            }else{
+                                throw std::runtime_error("propagateRelativePos parent edge weak pointer is expired" );
+                            }
+                        }
+                    }else{
+                        throw std::runtime_error("propagateRelativePos parent weak pointer is expired" );
+                    }
+                }
+            }
+            tmpRelative.clear();
+        }else{
+            throw std::runtime_error("propagateRelativePos edge weak pointer is expired" );
+        }
+    }
+}
+
+
+
+FsmEdge::FsmEdge(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const std::shared_ptr<ConditionalInterpreter>  toTest)
+:mToTest(toTest)
+{
+    mNodeSource = source;
+    mNodeDest   = dest;
+}
+
+/////surchage
+
+FsmEdgeUnique::FsmEdgeUnique(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const std::shared_ptr<ConditionalInterpreter>  toTest)
+:FsmEdge(source,dest,toTest)
+{
+}
+const EdgeTestResult FsmEdgeUnique::test(const std::shared_ptr<FsmRunTimeContext> stmContext){
+    if(stmContext == nullptr){
+        return {false,std::set<NodePtr>()};//none
+    }
+    auto opNode = stmContext->getActNode();
+    if(mToTest->test(opNode) && opNode->getChildren().size() <= 1){
+        stmContext->setValid(opNode,mToTest);
+        return {true,opNode->getChildren()} ;
+    }else{
+        stmContext->addRejectedNode(opNode);
+        return {false,std::set<NodePtr>()};
+    }
+}
+/////////////////////
+FsmEdgeCommon::FsmEdgeCommon(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const std::shared_ptr<ConditionalInterpreter>  toTest, const std::string commonKey)
+:FsmEdge(source,dest,toTest)
+{
+    //make a uid for common node 
+    if(mCommonIdxMap.find(commonKey) == mCommonIdxMap.end()){
+        mCommonIdxMap.insert(std::make_pair(commonKey, mCommonIdxMap.size()));
+    }
+    mCommonIdx = mCommonIdxMap[commonKey];
+    propagateRelativePos();
+}
+
+
+const EdgeTestResult FsmEdgeCommon::test(const std::shared_ptr<FsmRunTimeContext> stmContext){
+    if(stmContext == nullptr){
+        return {false,std::set<NodePtr>()};//none
+    }
+    auto opNode = stmContext->getActNode();
+
+    if(mToTest->test(opNode)){
+        stmContext->setCommon(opNode,mCommonIdx);
+        stmContext->setValid(opNode,mToTest);
+        return {true,opNode->getChildren()} ;
+    }else{
+        stmContext->addRejectedNode(opNode);
+        return {false,std::set<NodePtr>()};
+    }
+}
+bool FsmEdgeCommon::isCommon(void){
+    return true;
+ }
+//////////////////// TODO FsmEdgeEmpty must be size_t
+FsmEdgeRef::FsmEdgeRef(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const size_t refCommonIdx,const int deltaCommonIdx)
+:FsmEdge(source,dest,nullptr),mRefCommonIdx(refCommonIdx),mdeltaCommonIdx(deltaCommonIdx)
+{
+
+}
+const EdgeTestResult FsmEdgeRef::test(const std::shared_ptr<FsmRunTimeContext> stmContext){
+    
+    NodePtr refNode = stmContext->getCommonNodeFromIdx(mRefCommonIdx);
+    if (refNode){
+
+        //return {true,refNode->getNodeDelta(mdeltaCommonIdx)}; TODO
+    }
+    return  {false,std::set<NodePtr>()};
+    
+
+}
+////////////////////
+FsmEdgeEmpty::FsmEdgeEmpty(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest)
+:FsmEdge(source,dest,nullptr)
+{}
+const EdgeTestResult FsmEdgeEmpty::test(const std::shared_ptr<FsmRunTimeContext> stmContext){
+    if(stmContext == nullptr){
+        return {false,std::set<NodePtr>()};
+    }
+    auto opNode = stmContext->getActNode();
+    return {true,std::set<NodePtr>({opNode})};//none
+}
+
+/// factory
+std::shared_ptr<FsmEdge> FsmEdgeFactory::make(
+std::shared_ptr<FsmNode> source, 
+std::shared_ptr<FsmNode> dest, FsmEdgeTypes type, 
+std::map<std::string, std::shared_ptr<ConditionalInterpreter>> allTest,
+const std::string lexeme)
+{
+        if (type == FsmEdgeTypes::EMPTY) {
+            if (lexeme.empty()) {
+                return std::make_shared<FsmEdgeEmpty>(source, dest);
+            } else {
+                throw std::invalid_argument("error lexem EMPTY");
+            }
+        } else if (type == FsmEdgeTypes::REF) {
+            std::smatch m;
+            std::regex refRegex("\\s*\\(\\s*(\\d+)\\s*,\\s*(-?\\d+)\\s*\\)\\s*");
+            if (std::regex_match(lexeme, m, refRegex)) {
+                int refCommonIdx = std::stoi(m[1]);
+                int deltaCommonIdx = std::stoi(m[2]);
+                return std::make_shared<FsmEdgeRef>(source, dest, refCommonIdx, deltaCommonIdx);
+            } else {
+                throw std::invalid_argument("error lexem REF " + lexeme);
+            }
+        } else if (type == FsmEdgeTypes::COMMON) {
+            std::smatch m;
+            std::regex commonRegex("\\s*(\\w+)#(\\d*)");
+            if (std::regex_match(lexeme, m, commonRegex)) {
+                std::string edgeType = m[1];
+                std::string commonId =  m[2];
+                size_t commonIdx = commonId.empty() ? 0 : std::stoi(commonId) + 1;
+                std::string commonKey = edgeType + std::to_string(commonIdx);
+                return  std::make_shared<FsmEdgeCommon> (source, dest, allTest.at(edgeType), commonKey);
+            } else {
+                throw std::invalid_argument("error lexem COMMON " + lexeme);
+            }
+        } else if (type == FsmEdgeTypes::UNIQUE) {
+            std::regex uniqueRegex("\\s*(\\w+)");
+            std::smatch m;
+            if (std::regex_match(lexeme, m, uniqueRegex)) {
+                std::string edgeType = m[1];
+                return  std::make_shared<FsmEdgeUnique>(source, dest, allTest.at(edgeType));
+            } else {
+                throw std::invalid_argument("error lexem UNIQUE \"" + std::string(lexeme) +" eee\"");
+            }
+        } else {
+            throw std::invalid_argument("Bad edge Type");
+        }
+    }
\ No newline at end of file
diff --git a/src/graphRegex/matchFsm/FsmGraph.cpp b/src/graphRegex/matchFsm/FsmGraph.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2ec9fe75ed810440af2b4771a4c1594223f1c21d
--- /dev/null
+++ b/src/graphRegex/matchFsm/FsmGraph.cpp
@@ -0,0 +1,170 @@
+#include "aidge/graphRegex/matchFsm/FsmGraph.hpp"
+
+using namespace Aidge; 
+
+
+
+FsmGraph::FsmGraph(/* args */){
+
+}
+
+//TODO
+std::vector<std::shared_ptr<MatchResult>> FsmGraph::test(std::vector<NodePtr>& startNodes){
+    std::vector<std::shared_ptr<Aidge::FsmNode>> startNodesFsm = getStartNodes();
+    if(startNodes.size() != startNodesFsm.size()){
+         throw std::runtime_error("bad number of Start nodes");
+    }
+    
+    std::vector<std::shared_ptr<FsmRunTimeContext>> walks;
+    for(std::size_t i = 0; i < startNodes.size(); i++){
+        walks.push_back(std::make_shared<FsmRunTimeContext>(startNodesFsm[i],startNodes[i]));
+    }
+
+    std::vector<std::shared_ptr<FsmRunTimeContext>> allValidContext;
+
+    while (!walks.empty())
+    {
+        std::vector<std::shared_ptr<FsmRunTimeContext>> nextWalks;
+
+        for(auto fsmContext : walks){
+            //if we are in a valid st we save it
+            //it's one solution of the posible solution of the matching 
+            if(fsmContext->isOnValidState()){
+                //TODO not push same fsm use are_equal
+                allValidContext.push_back(fsmContext);
+            }
+
+            std::vector<std::shared_ptr<FsmRunTimeContext>> tmpNextWalks = fsmContext->getActState()->test(fsmContext);
+        }
+    }
+    
+
+}
+
+
+const std::set<std::shared_ptr<FsmEdge>>& FsmGraph::getEdge(void){
+    return mEdges;
+}
+
+void FsmGraph::addEdge(std::shared_ptr<FsmEdge> edge){
+    mEdges.insert(edge);
+    mAllOrigine.insert(edge->getDestNode()->getOrigine());
+    mAllOrigine.insert(edge->getSourceNode()->getOrigine());
+}
+
+const std::vector<std::shared_ptr<FsmNode>> FsmGraph::getStartNodes(void){
+    std::set<std::shared_ptr<FsmNode>> nodes = getNodes();
+    std::vector<std::shared_ptr<FsmNode>> startNodes;
+    for(auto node :nodes){
+        if(node->isStart()){
+            startNodes.push_back(node);
+        }
+    }
+    return startNodes;
+}
+
+const std::set<std::shared_ptr<FsmNode>> FsmGraph::getValidNodes(void){
+    std::set<std::shared_ptr<FsmNode>> nodes = getNodes();
+    std::set<std::shared_ptr<FsmNode>> ValidNodes;
+    for(auto node :nodes){
+        if(node->isValid()){
+            ValidNodes.insert(node);
+        }
+    }
+    //may short
+    return ValidNodes;
+}
+
+const std::set<std::shared_ptr<FsmNode>> FsmGraph::getNodes(void){
+    std::set<std::shared_ptr<FsmNode>> nodes;
+    for(auto edge : mEdges){
+        nodes.insert(edge->getDestNode());
+        nodes.insert(edge->getSourceNode());
+    }
+    return nodes;
+}
+
+void FsmGraph::setGroupe(std::size_t groupeIdx){
+    std::set<std::shared_ptr<FsmNode>> nodes = getNodes();
+    for(auto node :nodes){
+        node->setGroupe(groupeIdx);
+    }
+}
+
+void FsmGraph::unionG(const std::shared_ptr<FsmGraph> fsmGraph){
+
+    for(auto edge : fsmGraph->getEdge()){
+        addEdge(edge);
+    }
+}
+
+void FsmGraph::mergeOneStartOneValid(const std::shared_ptr<FsmGraph> fsmGraph){
+    std::set<std::shared_ptr<FsmNode>> validNodes = getValidNodes();
+    std::vector<std::shared_ptr<FsmNode>> startNodes = fsmGraph->getStartNodes();
+
+    if (startNodes.size() != 1 || validNodes.size() != 1){
+
+        std::ostringstream errorMessage;
+        errorMessage <<"mergeOneStartOneValid  start size: " << startNodes.size() << " valide size : " << validNodes.size()
+        <<" can only merge FSM 1 start 1 valide";
+        throw std::runtime_error(errorMessage.str());
+    }
+
+    unionG(fsmGraph);
+    //for loop useless but for future merge it's coudl be used 
+    for(auto valid : validNodes){
+        valid->unValid();
+        for(auto start : startNodes){
+            start->unStart();
+            _mergeNode(start,valid);
+        }
+    }
+}
+
+std::size_t FsmGraph::getNbSubFsm(void){
+    return mAllOrigine.size();
+}
+
+void FsmGraph::incOrigineAllNodeBy(std::size_t incr){
+    std::set<std::shared_ptr<FsmNode>> nodes = getNodes();
+    for(auto node :nodes){
+        node->incOrigine(incr);
+    }
+    for(auto origin : mAllOrigine){
+        origin += incr;
+    }
+}
+
+void FsmGraph::_mergeNode(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest){
+    std::set<std::shared_ptr<FsmNode>> nodes = getNodes();
+
+    if(nodes.find(source) == nodes.end() || nodes.find(dest) == nodes.end()){
+        throw std::runtime_error("FsmGraph can not merge node not in the graph");
+    }
+    nodes.clear();
+
+    //probagate source attribut
+    if(source->isValid()){
+        dest->valid();
+    }
+    if(source->isStart()){
+        dest->start();
+    }
+
+    //merge source to dest by replace source by dest in all EDGE
+    for(auto edge : mEdges){
+        if(edge->getDestNode() == source ){
+            edge->reSetDestNode(dest);
+        }else if(edge->getSourceNode() == source ){
+            edge->reSetSouceNode(dest);
+        }
+
+    }
+    //check is source is not in graph 
+    nodes = getNodes();
+    if(nodes.find(source) != nodes.end() ){
+        throw std::runtime_error("FsmGraph merge node not effective");
+    }
+    nodes.clear();
+
+}
diff --git a/src/graphRegex/matchFsm/FsmNode.cpp b/src/graphRegex/matchFsm/FsmNode.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..321b786100db5dde0ec567f6867b60b6d319664b
--- /dev/null
+++ b/src/graphRegex/matchFsm/FsmNode.cpp
@@ -0,0 +1,117 @@
+#include "aidge/graphRegex/matchFsm/FsmNode.hpp"
+#include "aidge/graphRegex/matchFsm/FsmEdge.hpp"
+#include "aidge/graphRegex/matchFsm/FsmRunTimeContext.hpp"
+
+using namespace Aidge; 
+
+
+
+FsmNode::FsmNode(bool isAValid,bool isAStart ){
+    mIsAStart =isAStart;
+    mIsAValid =isAValid;
+
+}
+const std::vector<std::shared_ptr<FsmRunTimeContext>> FsmNode::test( std::shared_ptr<FsmRunTimeContext> fsmContext){
+
+
+    std::vector<std::shared_ptr<FsmRunTimeContext>> out;
+    std::shared_ptr<FsmRunTimeContext> newFsmContext ;
+    for(auto edge : mEdges){
+        if (auto sharedEdge = edge.lock()) {
+            std::shared_ptr<FsmNode> nextState =  sharedEdge->getDestNode();
+            newFsmContext = std::make_shared<FsmRunTimeContext>(fsmContext);
+
+            EdgeTestResult edgeRes = sharedEdge->test(newFsmContext);
+
+            if(edgeRes.success){
+                if(edgeRes.node.size() != 0){
+                    for(auto nextNode :edgeRes.node ){
+
+                        if(!newFsmContext->isAlreadyValid(nextNode) || newFsmContext->isCommonDefined(nextNode) ){
+                            out.push_back( std::make_shared<FsmRunTimeContext>(newFsmContext,nextState,nextNode));
+                           
+                        }else{
+                            out.push_back( std::make_shared<FsmRunTimeContext>(newFsmContext,nextState,nullptr));
+                        }
+
+                    }
+                }
+            }
+            newFsmContext.reset();
+
+        }else{
+            throw std::runtime_error("test FsmNode weak pointer is expired" );
+        }
+
+    }
+    return out;
+}
+
+
+
+std::size_t FsmNode::getOrigine(void){
+    return mOrigineStm;
+}
+void FsmNode::incOrigine(std::size_t inc){
+    mOrigineStm += inc;
+}
+void FsmNode::rmEdge(std::shared_ptr<FsmEdge> edge){
+    mEdges.erase(edge);
+}
+
+void FsmNode::addEdge(std::shared_ptr<FsmEdge> edge){
+    mEdges.insert(edge);
+}
+
+const std::set<std::shared_ptr<FsmNode>> FsmNode::getChildNodes(void){
+    std::set<std::shared_ptr<FsmNode>> children;
+    for(auto edge : mEdges){
+         if (auto sharedEdge = edge.lock()) {
+                children.insert(sharedEdge->getDestNode());
+         }else{
+            throw std::runtime_error("getChildNodes FsmNode weak pointer is expired" );
+         }
+    }
+    return children;
+}
+
+
+const std::set<std::weak_ptr<FsmNode>,lex_compare<FsmNode>> FsmNode::getParentNodes(void){
+    return mParents;
+}
+const std::set<std::weak_ptr<FsmEdge>,lex_compare<FsmEdge>> FsmNode::getEdges(void){
+    return mEdges;
+}
+
+void FsmNode::setGroupe(std::size_t groupeIdx){
+    mGroupeStm = groupeIdx;
+    
+}
+
+bool FsmNode::isValid(void){
+    return mIsAValid;
+}
+bool FsmNode::isStart(void){
+    return mIsAStart;
+}
+void FsmNode::unValid(void){
+    mIsAValid =false;
+}
+void FsmNode::valid(void){
+    mIsAValid =true;
+}
+void FsmNode::unStart(void){
+    mIsAStart =false;
+}
+void FsmNode::start(void){
+    mIsAStart =true;
+}
+
+
+
+void FsmNode::addParent(std::shared_ptr<FsmNode> node){
+    mParents.insert(node);
+}
+void FsmNode::rmParent(std::shared_ptr<FsmNode> node){
+    mParents.erase(node);
+}
\ No newline at end of file
diff --git a/src/graphRegex/matchFsm/FsmRunTimeContext.cpp b/src/graphRegex/matchFsm/FsmRunTimeContext.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3e1b5f2a1c4d721ee6948aa809dd3f2620db1924
--- /dev/null
+++ b/src/graphRegex/matchFsm/FsmRunTimeContext.cpp
@@ -0,0 +1,204 @@
+#include "aidge/graphRegex/matchFsm/FsmRunTimeContext.hpp"
+#include "aidge/graphRegex/matchFsm/FsmNode.hpp"
+
+using namespace Aidge; 
+
+std::vector<std::set<NodePtr>> FsmRunTimeContext::mRejectedNodes;
+
+FsmRunTimeContext::FsmRunTimeContext(std::shared_ptr<FsmNode> actState ,NodePtr actOpNode ,std::size_t idxRejeced  ){
+    mActOpNode = actOpNode;
+    mActState  = actState;
+
+    //not define case
+    if(idxRejeced ==  std::numeric_limits<std::size_t>::max()){
+        mLocalIdxRejeced =  mRejectedNodes.size();
+        mRejectedNodes.push_back(std::set<NodePtr>());
+    }else{
+        if(idxRejeced > mRejectedNodes.size()-1 ){
+            throw std::runtime_error("FsmRunTimeContext idxRejeced");
+        }
+        mLocalIdxRejeced =idxRejeced;
+    }
+}
+
+
+
+FsmRunTimeContext::FsmRunTimeContext(std::shared_ptr<FsmRunTimeContext> fsmRunTime){
+    mActOpNode        = fsmRunTime->mActOpNode;
+    mActState         = fsmRunTime->mActState;
+    mCommonNodes      = fsmRunTime->mCommonNodes;
+    mValidNodes       = fsmRunTime->mValidNodes;
+    mLocalIdxRejeced  = fsmRunTime->mLocalIdxRejeced;
+}
+FsmRunTimeContext::FsmRunTimeContext(std::shared_ptr<FsmRunTimeContext> fsmRunTime,std::shared_ptr<FsmNode> actState ,NodePtr actOpNode ){
+    mActOpNode        = actOpNode;
+    mActState         = actState;
+    mCommonNodes      = fsmRunTime->mCommonNodes;
+    mValidNodes       = fsmRunTime->mValidNodes;
+    mLocalIdxRejeced  = fsmRunTime->mLocalIdxRejeced;
+}
+
+void FsmRunTimeContext::addRejectedNode(NodePtr node){
+    mRejectedNodes[mLocalIdxRejeced].insert(node);
+}
+
+std::set<NodePtr> FsmRunTimeContext::getRejectedNodes(void){
+    return mRejectedNodes[mLocalIdxRejeced];
+}
+
+bool FsmRunTimeContext::isOnValidState(void){
+    return mActState->isValid();
+}
+
+bool FsmRunTimeContext::isCommonDefined(NodePtr node){
+    return mCommonNodes.find(node) != mCommonNodes.end();
+}
+
+bool FsmRunTimeContext::isAlreadyValid(NodePtr node){
+    return getValidNodes().find(node) != getValidNodes().end();
+}
+
+bool FsmRunTimeContext::areCompatible(std::shared_ptr<FsmRunTimeContext> fsmContext){
+    /*
+    see if 2 context can be merge
+    it need to have different  mValidNodes exept for common
+    and the same idx for the common
+    */
+
+   //common node 
+
+   for (const auto& ref : getCommon()) {
+        for (const auto& test : fsmContext->getCommon()) {
+            //same index
+            if(ref.second == test.second){
+                if(ref.first != test.first){
+                    return false;
+                }
+            }
+        }
+   }
+
+   //valid nodes
+    std::set<NodePtr> commonElements;
+   
+    std::set_intersection(
+        getValidNodesNoCommon().begin(), getValidNodesNoCommon().end(),
+        fsmContext->getValidNodesNoCommon().begin(),  fsmContext->getValidNodesNoCommon().end(),
+        std::inserter(commonElements, commonElements.end())
+       );
+
+
+    if (!commonElements.empty()) {
+        return false;
+    }
+
+    return true;
+}
+
+bool FsmRunTimeContext::areEqual(std::shared_ptr<FsmRunTimeContext> fsmContext){
+    if(getActNode() != fsmContext->getActNode()){
+        return false;
+    }
+    if (getActState() != fsmContext->getActState()){
+        return false;
+    }
+    if (getValidNodes() != fsmContext->getValidNodes()){
+        return false;
+    }
+    if (getCommon() != fsmContext->getCommon()){
+        return false;
+    }
+
+
+    return true;
+}
+
+void FsmRunTimeContext::setCommon(NodePtr node,std::size_t commonIdx){
+    if(isCommonDefined(node)){
+        if (mCommonNodes.at(node) != commonIdx){
+            throw std::runtime_error("conflict idx in the Common node");
+        }
+    }else{
+        mCommonNodes[node] = commonIdx;
+    }
+}
+
+void FsmRunTimeContext::setValid(NodePtr node,std::shared_ptr<ConditionalInterpreter> tag){
+    //we already find a node of this type 
+    if(mValidNodes.find(tag) != mValidNodes.end()){
+        if(isAlreadyValid(node) && !isCommonDefined(node) ){
+            throw std::runtime_error("setValid you valid tow time");
+        }
+        mValidNodes[tag].insert(node);
+    }else{
+        mValidNodes[tag] = {node};
+    }
+    
+}
+
+std::size_t FsmRunTimeContext::getSubStmId(void){
+    return mActState->getOrigine();
+}
+
+NodePtr FsmRunTimeContext::getCommonNodeFromIdx(std::size_t commonIdx){
+    for (const auto& pair : mCommonNodes) {
+        if (pair.second == commonIdx) {
+            return pair.first; // Return the key when the value is found
+        }
+    }
+    throw std::runtime_error("getCommonNodeFromIdx Value not found in the map");
+}
+
+std::size_t FsmRunTimeContext::getCommonNodeIdx(NodePtr node){
+    if(isCommonDefined(node)){
+        return mCommonNodes.at(node);
+    }
+    throw std::runtime_error("getCommonNodeIdx node not found");
+}
+
+std::set<NodePtr> FsmRunTimeContext::getCommonNodes(void){
+    std::set<NodePtr> nodes;
+    // Iterate over the map and insert values into the set
+    for (const auto& pair : mCommonNodes) {
+        nodes.insert(pair.first);
+    }
+    return nodes;
+}
+
+std::map<NodePtr,std::size_t> FsmRunTimeContext::getCommon(void){
+    return mCommonNodes;
+}
+
+std::set<NodePtr> FsmRunTimeContext::getValidNodes(void){
+    // Create a set to store the values from the map
+    std::set<NodePtr> nodes;
+    // Iterate over the map and insert values into the set
+    for (const auto& pair : mValidNodes) {
+        nodes.insert(pair.second.begin(),pair.second.end());
+    }
+    return nodes;
+}
+
+std::set<NodePtr> FsmRunTimeContext::getValidNodesNoCommon(void){
+    std::set<NodePtr> differenceSet;
+    std::set_difference(getValidNodes().begin(), getValidNodes().end(), getCommonNodes().begin(), getCommonNodes().end(),std::inserter(differenceSet, differenceSet.end()));
+    return differenceSet;
+}
+
+std::map<std::shared_ptr<ConditionalInterpreter>,std::set<NodePtr>> FsmRunTimeContext::getValid(void){
+    return mValidNodes;
+}
+
+NodePtr FsmRunTimeContext::getActNode(void){
+    return mActOpNode;
+}
+
+std::shared_ptr<FsmNode> FsmRunTimeContext::getActState(){
+    return mActState;
+}
+
+
+void FsmRunTimeContext::rst(void){
+    mRejectedNodes.clear();
+}
+
diff --git a/src/graphRegex/matchFsm/MatchResult.cpp b/src/graphRegex/matchFsm/MatchResult.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cb06967bbe9a530d553ec3652a3c9564a084f4a5
--- /dev/null
+++ b/src/graphRegex/matchFsm/MatchResult.cpp
@@ -0,0 +1,4 @@
+#include "aidge/graphRegex/matchFsm/MatchResult.hpp"
+
+using namespace Aidge; 
+
diff --git a/src/nodeTester/ConditionalInterpreter.cpp b/src/nodeTester/ConditionalInterpreter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ccf9794a88bb1a2d90b4799915031f3138641f01
--- /dev/null
+++ b/src/nodeTester/ConditionalInterpreter.cpp
@@ -0,0 +1,359 @@
+
+#include "aidge/nodeTester/ConditionalInterpreter.hpp"
+
+using namespace Aidge; 
+
+
+///////////////////////////////
+//ConditionalRegisterFunction
+///////////////////////////////
+
+    ConditionalData* ConditionalRegisterFunction::run(const std::string key,std::vector<ConditionalData*> & datas){
+
+        auto lambdaIt = mWlambda.find(key);
+        if (lambdaIt != mWlambda.end()) {
+            return lambdaIt->second(datas);
+        }else {
+            throw std::runtime_error("can not run Lambda due to invalid key: " + key);
+        }
+    }
+
+//////////////////////
+//ConditionalInterpreter
+///////////////////////
+    ConditionalInterpreter::ConditionalInterpreter(const std::string ConditionalExpressions)
+    :mLambdaRegiter()
+    {
+
+        ConditionalParser conditionalParser = ConditionalParser(ConditionalExpressions);
+        mTree = conditionalParser.parse();
+        ///lambda by default
+        mLambdaRegiter.insert("getType",+[](NodePtr NodeOp){return NodeOp->type();});
+
+    }
+    
+
+    bool ConditionalInterpreter::test( const NodePtr nodeOp)
+    {
+        try{
+            std::vector<ConditionalData*> r =  visit({mTree},nodeOp);
+   
+        if (r.size() != 1){
+            throw std::runtime_error("Multy output interpretation output");
+        }else{
+            if (!r[0]->isTypeEqualTo<bool>()){
+                throw std::runtime_error("TEST OUT MUST BE A BOOL ");
+            }else{
+                return r[0]->getValue<bool>();
+            }
+        }
+
+        }catch(const std::exception& e){
+            std::ostringstream errorMessage;
+            errorMessage << "Error in test " << "\n\t" << e.what()  << "\n";
+            throw std::runtime_error(errorMessage.str()); 
+        }
+
+    }
+
+    void ConditionalInterpreter::insertLambda(const std::string key,std::function<bool(Aidge::NodePtr)> f){
+        mLambdaRegiter.insert<std::function<bool(Aidge::NodePtr)> >(key, f);
+    }
+
+    /////
+    std::vector<ConditionalData*> ConditionalInterpreter::visit(const ASTNodeCh& nodes, const NodePtr nodeOp ){
+            std::vector<ConditionalData*> dataVector;
+
+            for ( std::shared_ptr<AstNode<ConditionalTokenTypes>> node : nodes) {
+                try{
+                    switch (node->getType()){
+                        ///////////////////////////////////
+                        //OPERATOR
+                        /////////////////////////////////// 
+                        case ConditionalTokenTypes::NOT:
+                            {
+                            std::vector<ConditionalData*> tmp = fNot(visit(node->getChilds(),nodeOp));
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+                        case ConditionalTokenTypes::AND:
+                            {
+                            std::vector<ConditionalData*> tmp = fAnd(visit(node->getChilds(),nodeOp));
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+                        case ConditionalTokenTypes::OR:
+                            {
+                            std::vector<ConditionalData*> tmp = fOr(visit(node->getChilds(),nodeOp));
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+                        case ConditionalTokenTypes::EQ:
+                            {
+                            std::vector<ConditionalData*> tmp = fEq(visit(node->getChilds(),nodeOp));
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+                        case ConditionalTokenTypes::NEQ:
+                            {
+                            std::vector<ConditionalData*> tmp = fNeq(visit(node->getChilds(),nodeOp));
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+
+                        ///////////////////////////////////
+                        //VALUE
+                        ///////////////////////////////////    
+                    
+                        case ConditionalTokenTypes::KEY:
+                            
+                            break;
+                        case ConditionalTokenTypes::INTEGER:
+                            {
+                            std::vector<ConditionalData*> tmp = fStrToInteger(node);
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+                        case ConditionalTokenTypes::FLOAT:
+                            {
+                            std::vector<ConditionalData*> tmp = fStrToFloat(node);
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+                        case ConditionalTokenTypes::STRING:
+                            {
+                            std::vector<ConditionalData*> tmp = fStrToStr(node);
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+                    
+                        case ConditionalTokenTypes::NODE: //TODO
+                            {
+
+                            ConditionalData* data = new ConditionalData;
+                            data->setValue<NodePtr>(nodeOp);
+                            std::vector<ConditionalData*> tmp = {data};
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+
+                            }
+                            break;
+
+                        case ConditionalTokenTypes::LAMBDA:
+                            {
+                            std::vector<ConditionalData*> tmp = fLambda(node,visit(node->getChilds(),nodeOp));
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+
+                        case ConditionalTokenTypes::BOOL: //TODO
+                            {
+                            ConditionalData* data = new ConditionalData;
+                            
+                            if(node->getValue() == "true"){
+                                data->setValue<bool>(true);
+                            }else{
+                                data->setValue<bool>(false);
+                            }
+                            
+                            std::vector<ConditionalData*> tmp = {data};
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+
+                        case ConditionalTokenTypes::ARGSEP:
+                        case ConditionalTokenTypes::LPAREN:
+                        case ConditionalTokenTypes::RPAREN:
+                        case ConditionalTokenTypes::STOP:
+                        default:
+                            throw std::runtime_error("NODE TYPE NOT SUPORTED IN ConditionalInterpreter");
+                    }
+                }catch(const std::exception& e){
+                    std::ostringstream errorMessage;
+                    errorMessage << "Error in visiting AST for node"<< nodeOp->name() << "\n\t" << e.what()  << "\n";
+                    throw std::runtime_error(errorMessage.str()); 
+                }
+            }
+
+            return dataVector;
+    }
+
+
+    //////////////////////
+    //value convertor
+    /////////////////////
+
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fStrToInteger(const std::shared_ptr<AstNode<ConditionalTokenTypes>>& node)
+    {
+        std::vector<ConditionalData*> dataVector;
+        ConditionalData* data = new ConditionalData;
+        data->setValue<int>(std::stoi(node->getValue()));
+        dataVector.push_back(data);
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fStrToFloat(const std::shared_ptr<AstNode<ConditionalTokenTypes>>& node)
+    {
+        std::vector<ConditionalData*> dataVector;
+        ConditionalData* data = new ConditionalData;
+        data->setValue<float>(std::stof(node->getValue()));
+        dataVector.push_back(data);
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fStrToStr(const std::shared_ptr<AstNode<ConditionalTokenTypes>>& node)
+    {
+        std::vector<ConditionalData*> dataVector;
+        ConditionalData* data = new ConditionalData;
+        data->setValue<std::string>(node->getValue());
+        dataVector.push_back(data);
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fLambda(const std::shared_ptr<AstNode<ConditionalTokenTypes>>& node,std::vector<ConditionalData*> datas) 
+    {
+        //if the lambda have input
+        std::vector<ConditionalData*> dataVector;
+        ConditionalData* data;
+        try {
+            data = mLambdaRegiter.run(node->getValue(),datas);
+        } catch (const std::exception& e) {
+            std::ostringstream errorMessage;
+            errorMessage << "Error in conditional interpretation when run the "<<  node->getValue() <<" Lambda\n\t" << e.what()  << "\n";
+            throw std::runtime_error(errorMessage.str()); 
+        }
+        dataVector.push_back(data);
+        datas.clear();
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fEq(std::vector<ConditionalData*> datas)
+    {
+        if (datas.size() != 2){
+            throw std::runtime_error("EQ need 2 arg and get :" + datas.size());
+        }
+        auto a = datas[0];
+        auto b = datas[1];
+
+        if (a->getType() != b->getType()){
+            throw std::runtime_error("EQ Unsuported between type :" + a->getType() +" "+ b->getType());
+        }
+
+        std::vector<ConditionalData*> dataVector;
+
+        ConditionalData* data = new ConditionalData;
+
+        if (a->isTypeEqualTo<int>()) {
+           data->setValue<bool>( a->getValue<int>() == b->getValue<int>());
+        }else if (a->isTypeEqualTo<float>()){
+           data->setValue<bool>( a->getValue<float>() == b->getValue<float>());
+        }else if (a->isTypeEqualTo<std::string>()){
+           data->setValue<bool>( a->getValue<std::string>() == b->getValue<std::string>());
+        }else if (a->isTypeEqualTo<bool>()){
+           data->setValue<bool>( a->getValue<bool>() == b->getValue<bool>());
+        }else{
+           throw std::runtime_error("EQ Unknown type encountered :" + a->getType() );
+        }
+        dataVector.push_back(data);
+        datas.clear();
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fNeq(std::vector<ConditionalData*> datas)
+    {
+        if (datas.size() != 2){
+             throw std::runtime_error("NEQ need 2 arg and get :" + datas.size());
+        }
+        auto a = datas[0];
+        auto b = datas[1];
+
+        if (a->getType() != b->getType()){
+            throw std::runtime_error("NEQ Unsuported between type :" + a->getType() +" "+ b->getType());
+        }
+
+        std::vector<ConditionalData*> dataVector;
+
+        ConditionalData* data = new ConditionalData;
+
+        if (a->isTypeEqualTo<int>()) {
+           data->setValue<bool>( a->getValue<int>() != b->getValue<int>());
+        }else if (a->isTypeEqualTo<float>()){
+           data->setValue<bool>( a->getValue<float>() != b->getValue<float>());
+        }else if (a->isTypeEqualTo<std::string>()){
+           data->setValue<bool>( a->getValue<std::string>() != b->getValue<std::string>());
+        }else
+        {
+           throw std::runtime_error("NEQ Unknown type encountered :" + a->getType() );
+        }
+        dataVector.push_back(data);
+        datas.clear();
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fAnd(std::vector<ConditionalData*> datas)
+    {
+        if (datas.size() != 2){
+           throw std::runtime_error("AND need 2 arg and get :" + datas.size());
+        }
+        auto a = datas[0];
+        auto b = datas[1];
+
+        std::vector<ConditionalData*> dataVector;
+
+        if (a->getType() != typeid(bool).name() || b->getType() != typeid(bool).name()){
+            throw std::runtime_error("AND Unknown type encountered need bool get :" + a->getType() );
+        }
+
+        ConditionalData* data = new ConditionalData;
+        data->setValue<bool>( a->getValue<bool>() && b->getValue<bool>());
+        
+
+        dataVector.push_back(data);
+        datas.clear();
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fOr(std::vector<ConditionalData*> datas)
+    {
+        if (datas.size() != 2){
+             throw std::runtime_error("OR need 2 arg and get :" + datas.size());
+        }
+        auto a = datas[0];
+        auto b = datas[1];
+
+        std::vector<ConditionalData*> dataVector;
+
+        if (a->getType() != typeid(bool).name() || b->getType() != typeid(bool).name()){
+             throw std::runtime_error("OR Unknown type encountered need bool get :" + a->getType() );
+        }
+
+        ConditionalData* data = new ConditionalData;
+        data->setValue<bool>( a->getValue<bool>() || b->getValue<bool>());
+        
+
+        dataVector.push_back(data);
+        datas.clear();
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fNot(std::vector<ConditionalData*> datas)
+        {
+            if (datas.size() != 1){
+                throw std::runtime_error("not need 1 arg and get :" + datas.size());
+            }
+            auto a = datas[0];
+
+            std::vector<ConditionalData*> dataVector;
+
+            if (a->getType() != typeid(bool).name()){
+                throw std::runtime_error("NOT Unknown type encountered need bool get :" + a->getType() );
+            }
+
+            ConditionalData* data = new ConditionalData;
+            data->setValue<bool>( !a->getValue<bool>() );
+            
+
+            dataVector.push_back(data);
+            datas.clear();
+            return dataVector;
+        }
diff --git a/src/nodeTester/ConditionalLexer.cpp b/src/nodeTester/ConditionalLexer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9379bd8409f8f7ec4bae3e0122f88de79718e9dd
--- /dev/null
+++ b/src/nodeTester/ConditionalLexer.cpp
@@ -0,0 +1,242 @@
+#include "aidge/nodeTester/ConditionalLexer.hpp"
+
+using namespace Aidge; 
+
+//////////////////
+//ConditionalLexer
+//////////////////
+
+
+ConditionalLexer::ConditionalLexer( const std::string ConditionalExpressions):
+mConditionalExpressions(ConditionalExpressions)
+{
+    mPosition = 0;
+}
+
+std::shared_ptr<ParsingToken<ConditionalTokenTypes>> ConditionalLexer::getNextToken(void){
+    std::string currentChars = "";
+
+    while (mPosition < mConditionalExpressions.length())
+    {
+        //erase all space 
+        if (mConditionalExpressions[mPosition] != ' ')
+        {
+            currentChars += mConditionalExpressions[mPosition];
+        }
+        else
+        {
+            mPosition++;
+            continue;
+        }
+        //performe tokenisation, find a regex and make a new token
+        
+        if (std::regex_match(currentChars,std::regex("\\&\\&")))// the AND TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::AND,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("\\|\\|")))// the OR TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::OR,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("\\!")))// the Not and not equ
+        {
+            mPosition++;
+            if ( mPosition < mConditionalExpressions.length()){
+                currentChars += mConditionalExpressions[mPosition];
+                if(std::regex_match(currentChars,std::regex("!="))){
+                    mPosition++;
+                    return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::NEQ,"");
+                }else{
+                     return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::NOT,"");
+                }
+            }
+            //a not at the end not ok but it's the parseur work
+            return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::NOT,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("==")))// the EQ TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::EQ,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("\\(")))// the LPAREN TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::LPAREN,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("\\)")))// the RPAREN TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::RPAREN,"");
+        }
+        else if (std::regex_match(currentChars,std::regex(",")))// the RPAREN TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::ARGSEP,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("\\$")))// the ACTNode TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::NODE,"");
+        }
+
+
+        /////
+        //non const lent token
+        /////
+
+        //LAMBDA, KEY , bool //the fuction TAG 
+        else if (std::regex_match(currentChars,std::regex("[A-Za-z_]")))// the KEY TOKEN (a char next )
+        {   
+            //read all the key 
+            bool isLambda = false;
+            std::regex keyRegex("[A-Za-z_0-9]+");
+            std::regex LambdaRegex("[A-Za-z_0-9]+\\(");
+
+            while ( mPosition < mConditionalExpressions.length()) {
+                if(!std::regex_match(currentChars,keyRegex) && !std::regex_match(currentChars,LambdaRegex))
+                {
+                    currentChars.pop_back(); //the last char is the problemes
+                    break;
+                }
+                else if (std::regex_match(currentChars,LambdaRegex)){
+                    isLambda = true;
+                }
+                mPosition++;
+                if (mPosition < mConditionalExpressions.length()) currentChars += mConditionalExpressions[mPosition];
+                //currentChars += mConditionalExpressions[mPosition];
+            }
+            //we end the match 2 posibility 
+            //we are at the end of the mConditionalExpressions and we need to ensure the match
+            //we are not we can continu
+            if (mPosition == mConditionalExpressions.length()-1)
+            {
+                if (!std::regex_match(currentChars,keyRegex) && !std::regex_match(currentChars,LambdaRegex))
+                {
+                    throw badTokenError(currentChars,mPosition);
+                }
+                //mPosition++; // we stop all by going pos > lengt
+            }
+
+
+            if (std::regex_match(currentChars,std::regex("(true|false)"))){
+                return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::BOOL,currentChars);
+
+            } else if (isLambda){
+                currentChars.pop_back();//pop the ( of the lambda
+                return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::LAMBDA,currentChars);
+            } else{
+                return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::KEY,currentChars);
+            }
+            
+        }
+        //numeric value 
+        else if (std::regex_match(currentChars,std::regex("[0-9]")))// the KEY TOKEN (a char next )
+        {   
+            //read all the key 
+            bool isFloat = false;
+            std::regex integerRegex("[0-9]+$");
+            std::regex floatRegex("[0-9]+\\.[0-9]*$");
+
+            while ( mPosition < mConditionalExpressions.length()) {
+
+                if(!std::regex_match(currentChars,integerRegex) && !std::regex_match(currentChars,floatRegex))
+                {
+                    currentChars.pop_back(); // the last char match is not a good one 
+                    break;
+                }
+                else if (std::regex_match(currentChars,floatRegex)){
+                    isFloat = true;
+                }
+                mPosition++;
+                if (mPosition < mConditionalExpressions.length()) currentChars += mConditionalExpressions[mPosition];
+                //currentChars += mConditionalExpressions[mPosition];
+            }
+            //we end the match 2 posibility 
+            //we are at the end of the mConditionalExpressions and we need to ensure the match
+            //we are not we can continu
+            if (mPosition == mConditionalExpressions.length()-1)
+            {
+                if (!std::regex_match(currentChars,integerRegex) && !std::regex_match(currentChars,floatRegex))
+                {
+                     throw badTokenError(currentChars,mPosition);
+                }
+            }
+            
+            if(isFloat){
+                return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::FLOAT,currentChars);
+            }else{
+                return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::INTEGER,currentChars);
+            }
+            
+        }
+        //string TODO
+        else if (std::regex_match(currentChars,std::regex("\'"))) // TODO ' or \'
+        {
+            std::regex strRegex("\'[A-Za-z_0-9\\s]*\'$");
+            while ( mPosition < mConditionalExpressions.length()) {
+                if(std::regex_match(currentChars,strRegex)){
+                    break;
+                }
+                mPosition++;
+                if (mPosition < mConditionalExpressions.length()) currentChars += mConditionalExpressions[mPosition];
+                //currentChars += mConditionalExpressions[mPosition];
+            }
+
+            //test the end condition
+            if (mPosition == mConditionalExpressions.length()-1 ){
+                if (!std::regex_match(currentChars,strRegex)){
+                     throw badTokenError(currentChars,mPosition);
+                }
+                //mPosition++; // we stop all by going pos > lengt
+            }
+
+            mPosition++; // go after the last " 
+            //erase the " char
+            currentChars.pop_back();
+            currentChars.erase(0,1);
+
+            return std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::STRING,currentChars);
+
+        }
+
+        //Array TODO
+
+        mPosition++;
+    }
+
+    //no more to find no one match the currentChars 
+    if (currentChars.empty()) {
+        return  std::make_shared<ParsingToken<ConditionalTokenTypes>>(ConditionalTokenTypes::STOP,"");  // Null shared pointer ;
+    }else{
+        //std::ostringstream errorMessage;
+        //errorMessage << "\nBad syntax " << currentChars << " :\n" << mConditionalExpressions;
+        throw badTokenError(currentChars,mPosition);
+    }
+    
+}
+
+void ConditionalLexer::rstPosition(void){
+    if (isEnd()){
+        mPosition = 0;
+    }else{
+        throw badTokenError("end rst",mPosition);
+    }
+    
+}
+
+bool ConditionalLexer::isEnd(void){
+    return mPosition >= mConditionalExpressions.length();
+}
+
+std::runtime_error ConditionalLexer::badTokenError(const std::string& currentChars,std::size_t position){
+    std::ostringstream errorMessage;
+    errorMessage << "\nBad syntax " << currentChars << " :\n" << mConditionalExpressions << "\n";
+     for (std::size_t i = 0; i < position; i++) {
+        errorMessage << ' ';
+    }
+    errorMessage << "^\n";
+
+    return std::runtime_error(errorMessage.str());
+}
\ No newline at end of file
diff --git a/src/nodeTester/ConditionalParser.cpp b/src/nodeTester/ConditionalParser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7b5dddcc5a6e6b3cef55ac4acf29c80ad992b270
--- /dev/null
+++ b/src/nodeTester/ConditionalParser.cpp
@@ -0,0 +1,188 @@
+
+#include "aidge/nodeTester/ConditionalParser.hpp"
+
+using namespace Aidge;
+
+
+//////////////////////////////
+//ConditionalParser
+//////////////////////////////
+
+ConditionalParser::ConditionalParser(const std::string ConditionalExpressions):mLexer(ConditionalExpressions){
+    mCurrentToken = mLexer.getNextToken();
+}
+
+void ConditionalParser::rstParser(void){
+    mLexer.rstPosition();
+    mCurrentToken = mLexer.getNextToken();
+}
+
+void ConditionalParser::ackToken(ConditionalTokenTypes  tokenType){
+    if(mCurrentToken->getType() == tokenType ){
+
+        try {
+            mCurrentToken = mLexer.getNextToken();
+        } catch (const std::runtime_error& e) {
+            std::ostringstream errorMessage;
+            errorMessage << "Conditional Lexer error in Parser :\n"<< e.what() << std::endl;
+            throw std::runtime_error(errorMessage.str());
+        }
+    }else{
+
+        std::ostringstream errorMessage;
+        errorMessage << "Bad syntax ConditionalParser " << static_cast<int>(mCurrentToken->getType())  <<"!="<< static_cast<int>(tokenType) << "\n";
+        errorMessage << mLexer.rep();
+        throw std::runtime_error(errorMessage.str());
+    }
+}
+
+
+
+std::shared_ptr<AstNode<ConditionalTokenTypes>> ConditionalParser::constructAstVal(void){
+    /*
+    val : (KEY|INTEGER|FOAT|STRING|LAMBDA)
+    */
+    std::shared_ptr<ParsingToken<ConditionalTokenTypes>> token = mCurrentToken->copy();
+
+    if (token->getType() == ConditionalTokenTypes::KEY){
+        ackToken(ConditionalTokenTypes::KEY);
+        return std::make_shared<AstNode<ConditionalTokenTypes>>(token);
+    }
+    else if(token->getType() == ConditionalTokenTypes::INTEGER){
+        ackToken(ConditionalTokenTypes::INTEGER);
+        return std::make_shared<AstNode<ConditionalTokenTypes>>(token);
+    }
+    else if(token->getType() == ConditionalTokenTypes::FLOAT){
+        ackToken(ConditionalTokenTypes::FLOAT);
+        return std::make_shared<AstNode<ConditionalTokenTypes>>(token);
+    }
+    else if(token->getType() == ConditionalTokenTypes::BOOL){
+        ackToken(ConditionalTokenTypes::BOOL);
+        return std::make_shared<AstNode<ConditionalTokenTypes>>(token);
+    }
+    else if(token->getType() == ConditionalTokenTypes::STRING){
+        ackToken(ConditionalTokenTypes::STRING);
+        return std::make_shared<AstNode<ConditionalTokenTypes>>(token);
+
+    }else if(token->getType() == ConditionalTokenTypes::NODE){
+        ackToken(ConditionalTokenTypes::NODE);
+        return std::make_shared<AstNode<ConditionalTokenTypes>>(token);
+
+    }else if(token->getType() == ConditionalTokenTypes::LAMBDA){
+        return constructAstLambda();
+    }
+
+   throw std::runtime_error("ConditionalParser unknow val type "+ token->rep().str() + "\n" + mLexer.rep());
+
+}
+
+std::shared_ptr<AstNode<ConditionalTokenTypes>> ConditionalParser::constructAstLambda(void){
+    /*
+    AstLambda :  LAMBDA val (ARGSEP val)* RPAREN
+    */
+    std::shared_ptr<ParsingToken<ConditionalTokenTypes>> tokenLdb = mCurrentToken->copy();
+    ackToken(ConditionalTokenTypes::LAMBDA);
+    ASTNodeCh paramLambda;
+    //AT LEAST ONE VALUE AS INPUT OF A LAMBDA
+    paramLambda.push_back(constructAstVal());
+    while (mCurrentToken->getType() != ConditionalTokenTypes::RPAREN)
+    {
+        ackToken(ConditionalTokenTypes::ARGSEP);
+        paramLambda.push_back(constructAstVal());
+    }
+    ackToken(ConditionalTokenTypes::RPAREN);
+    return std::make_shared<AstNode<ConditionalTokenTypes>>(tokenLdb,paramLambda);
+}
+
+std::shared_ptr<AstNode<ConditionalTokenTypes>> ConditionalParser::constructAstCmpr(void){
+      /*
+        cmpr   : val (EQ|NEQ) val | LPAREN expr RPAREN
+        NOT ir ?
+      */
+     std::shared_ptr<ParsingToken<ConditionalTokenTypes>> token = mCurrentToken->copy();
+     //we can check the type relation ir  key (EQ|NEQ) val | val (EQ|NEQ) key , but val (EQ|NEQ) val is valid ?
+     if (token->getType() == ConditionalTokenTypes::LPAREN)
+     {
+        ackToken(ConditionalTokenTypes::LPAREN);
+        std::shared_ptr<AstNode<ConditionalTokenTypes>> node = constructAstExpr();
+        ackToken(ConditionalTokenTypes::RPAREN);
+        return node;
+     }else{
+
+        std::shared_ptr<AstNode<ConditionalTokenTypes>> node = constructAstVal();
+        token = mCurrentToken->copy();
+        if (token->getType() == ConditionalTokenTypes::EQ){
+            ackToken(ConditionalTokenTypes::EQ);
+            return std::make_shared<AstNode<ConditionalTokenTypes>>(token,ASTNodeCh{node,constructAstVal()});
+        }else if(token->getType() == ConditionalTokenTypes::NEQ){
+            ackToken(ConditionalTokenTypes::NEQ);
+            return std::make_shared<AstNode<ConditionalTokenTypes>>(token,ASTNodeCh{node,constructAstVal()});
+        }else{
+
+            throw std::runtime_error("constructAstCmpr "+ token->rep().str() + "\n" + mLexer.rep());
+        }
+
+     }
+}
+
+std::shared_ptr<AstNode<ConditionalTokenTypes>> ConditionalParser::constructAstExpr(std::size_t precLimit /*= 0*/){
+    /*
+        expr   : cmpr ((AND | OR) cmpr)*
+        the NOT is not binary OP can be use in pratt
+        precedence H to L: TODO
+        AND
+        OR
+    */
+
+   //the not 
+    std::shared_ptr<AstNode<ConditionalTokenTypes>> left;
+    std::shared_ptr<ParsingToken<ConditionalTokenTypes>> token = mCurrentToken->copy();
+    
+    if (mCurrentToken->getType() == ConditionalTokenTypes::NOT  ){
+        ackToken(ConditionalTokenTypes::NOT );
+        left= std::make_shared<AstNode<ConditionalTokenTypes>>(token,ASTNodeCh{constructAstCmpr()});
+    }else{
+        left= constructAstCmpr();
+    }
+    
+    //pratt
+    while (mCurrentToken->getType() != ConditionalTokenTypes::STOP ) //security 
+    {
+        std::shared_ptr<ParsingToken<ConditionalTokenTypes>> token = mCurrentToken->copy();
+        //if the token is not in the map is not a operator so we consider a prec of 0 
+        if (ConditionalPrec.find(token->getType()) ==ConditionalPrec.end() ){
+            return left;
+        }
+
+        //if my actual operator have a prec <= of the last operator 
+        std::size_t prec = ConditionalPrec.at(token->getType());
+        if (prec <= precLimit){
+            return left;
+        }
+
+        //Act all AND and OR
+        ackToken(token->getType());
+
+        std::shared_ptr<AstNode<ConditionalTokenTypes>> right = constructAstExpr(prec);
+
+        //i'm not sur what append to newNode 
+        //std::shared_ptr<AstNode<ConditionalTokenTypes>> newNode = std::make_shared<AstNode<ConditionalTokenTypes>>(token,ASTNodeCh{left,constructAstCmpr()});
+        std::shared_ptr<AstNode<ConditionalTokenTypes>> newNode = std::make_shared<AstNode<ConditionalTokenTypes>>(token,ASTNodeCh{left,right});
+        left = newNode;
+    }
+    return left;
+}
+
+
+std::shared_ptr<AstNode<ConditionalTokenTypes>> ConditionalParser::parse(void){
+    /*
+        expr   : cmpr ((AND | OR) cmpr)*
+        cmpr   : val (EQ|NEQ) val | LPAREN expr RPAREN | BOOL | LAMBDA 
+        val    : (KEY|INTEGER|FOAT|STRING|LAMBDA)
+        lambda :  LAMBDA val (ARGSEP val)* RPAREN
+    */
+    std::shared_ptr<AstNode<ConditionalTokenTypes>> astTree = constructAstExpr();
+
+    rstParser();
+    return astTree;
+}
\ No newline at end of file
diff --git a/unit_tests/graphRegex/Test_Fsm.cpp b/unit_tests/graphRegex/Test_Fsm.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..518987f53d41c294f888e10080364484f7c5e385
--- /dev/null
+++ b/unit_tests/graphRegex/Test_Fsm.cpp
@@ -0,0 +1,194 @@
+#include <memory>
+
+#include <catch2/catch_test_macros.hpp>
+
+#include "aidge/nodeTester/ConditionalInterpreter.hpp"
+
+#include "aidge/graphRegex/matchFsm/FsmNode.hpp"
+#include "aidge/graphRegex/matchFsm/FsmEdge.hpp"
+#include "aidge/graphRegex/matchFsm/FsmGraph.hpp"
+#include "aidge/graphRegex/matchFsm/FsmRunTimeContext.hpp"
+
+using namespace Aidge;
+
+TEST_CASE("matchFSM", "FsmEdge") {
+
+    SECTION("FsmEdgeUnique constructor") {
+        std::shared_ptr<FsmNode>  nodeA = std::make_shared<FsmNode>(true,false);
+        std::shared_ptr<FsmNode>  nodeB = std::make_shared<FsmNode>(false,true);
+        std::shared_ptr<ConditionalInterpreter> toTest =  std::make_shared<ConditionalInterpreter>("true==true");
+        FsmEdgeUnique EdgeToTest(nodeA,nodeB,toTest);
+
+        REQUIRE(EdgeToTest.getSourceNode() == nodeA);
+        REQUIRE(EdgeToTest.getDestNode() == nodeB);
+        REQUIRE(EdgeToTest.isCommon() == false);
+    }
+    
+    SECTION("FsmEdgeCommon constructor") {
+        std::shared_ptr<FsmNode>  nodeA = std::make_shared<FsmNode>(true,false);
+        std::shared_ptr<FsmNode>  nodeB = std::make_shared<FsmNode>(false,true);
+        std::shared_ptr<ConditionalInterpreter> toTest =  std::make_shared<ConditionalInterpreter>("true==true");
+
+        FsmEdgeCommon EdgeToTest(nodeA,nodeB,toTest,"A");
+
+        REQUIRE(EdgeToTest.getSourceNode() == nodeA);
+        REQUIRE(EdgeToTest.getDestNode() == nodeB);
+        REQUIRE(EdgeToTest.isCommon() == true);
+    }
+
+    SECTION("FsmEdgeRef constructor") {
+        std::shared_ptr<FsmNode>  nodeA = std::make_shared<FsmNode>(true,false);
+        std::shared_ptr<FsmNode>  nodeB = std::make_shared<FsmNode>(false,true);
+        std::shared_ptr<ConditionalInterpreter> toTest =  std::make_shared<ConditionalInterpreter>("true==true");
+
+        FsmEdgeRef EdgeToTest(nodeA,nodeB,0,-1);
+
+        REQUIRE(EdgeToTest.getSourceNode() == nodeA);
+        REQUIRE(EdgeToTest.getDestNode() == nodeB);
+        REQUIRE(EdgeToTest.isCommon() == false);
+    }
+          
+    SECTION("FsmEdgeEmpty constructor") {
+        std::shared_ptr<FsmNode>  nodeA = std::make_shared<FsmNode>(true,false);
+        std::shared_ptr<FsmNode>  nodeB = std::make_shared<FsmNode>(false,true);
+        std::shared_ptr<ConditionalInterpreter> toTest =  std::make_shared<ConditionalInterpreter>("true==true");
+
+        FsmEdgeEmpty EdgeToTest(nodeA,nodeB);
+
+        REQUIRE(EdgeToTest.getSourceNode() == nodeA);
+        REQUIRE(EdgeToTest.getDestNode() == nodeB);
+        REQUIRE(EdgeToTest.isCommon() == false);
+    }
+
+
+    SECTION("FsmEdgeFactory"){
+
+    std::map<std::string, std::shared_ptr<ConditionalInterpreter>> allTest = {
+        {"A",std::make_shared<ConditionalInterpreter>("true==true")},
+        {"B",std::make_shared<ConditionalInterpreter>("true==true")},
+        {"C",std::make_shared<ConditionalInterpreter>("true==true")}
+    };
+
+// make(std::shared_ptr<FsmNode> source, std::shared_ptr<FsmNode> dest, 
+//     FsmEdgeTypes type,std::map<std::string, const std::shared_ptr<ConditionalInterpreter>> allTest,
+//     const std::string& lexeme = "");
+
+        std::shared_ptr<FsmNode>  nodeA = std::make_shared<FsmNode>(false,true);
+        std::shared_ptr<FsmNode>  nodeB = std::make_shared<FsmNode>(true,false);
+//     EMPTY = 0,
+//     REF,
+//     COMMON,
+//     UNIQUE
+
+        std::shared_ptr<FsmEdge> edgeE = FsmEdgeFactory::make(nodeA,nodeB,FsmEdgeTypes::EMPTY,allTest,"");
+        std::shared_ptr<FsmEdge> edgeU = FsmEdgeFactory::make(nodeA,nodeB,FsmEdgeTypes::UNIQUE,allTest,"A");
+        std::shared_ptr<FsmEdge> edgeC = FsmEdgeFactory::make(nodeA,nodeB,FsmEdgeTypes::COMMON,allTest,"A#");
+        std::shared_ptr<FsmEdge> edgeR = FsmEdgeFactory::make(nodeA,nodeB,FsmEdgeTypes::REF,allTest,"(0,1)");
+
+        //test detection of bad syntax lexem
+        REQUIRE_THROWS(FsmEdgeFactory::make(nodeA,nodeB,FsmEdgeTypes::EMPTY,allTest,"A"));
+        REQUIRE_THROWS(FsmEdgeFactory::make(nodeA,nodeB,FsmEdgeTypes::UNIQUE,allTest,"A#"));
+        REQUIRE_THROWS(FsmEdgeFactory::make(nodeA,nodeB,FsmEdgeTypes::COMMON,allTest,"A"));
+        REQUIRE_THROWS(FsmEdgeFactory::make(nodeA,nodeB,FsmEdgeTypes::REF,allTest,"A"));
+
+        REQUIRE(edgeE->getSourceNode() == nodeA);
+        REQUIRE(edgeE->getDestNode() == nodeB);
+    }
+
+    SECTION("graph constructor") {
+        //make the nodes 
+        std::shared_ptr<FsmNode>  nodeA = std::make_shared<FsmNode>(true,false);
+        std::shared_ptr<FsmNode>  nodeB = std::make_shared<FsmNode>(false,false);
+        std::shared_ptr<FsmNode>  nodeC = std::make_shared<FsmNode>(false,true);
+
+        //make the edges
+        std::shared_ptr<ConditionalInterpreter> toTest =  std::make_shared<ConditionalInterpreter>("true==true");
+        std::shared_ptr<FsmEdgeUnique> edgeAB =  std::make_shared<FsmEdgeUnique>(nodeA,nodeB,toTest);
+        std::shared_ptr<FsmEdgeUnique> edgeBC =  std::make_shared<FsmEdgeUnique>(nodeB,nodeC,toTest);
+ 
+        std::shared_ptr<FsmGraph> graph =  std::make_shared<FsmGraph>();
+
+        graph->addEdge(edgeAB);
+        graph->addEdge(edgeBC);
+        
+
+        REQUIRE(graph->getValidNodes() == std::set<std::shared_ptr<FsmNode>>{nodeA});
+        REQUIRE(graph->getStartNodes() == std::vector<std::shared_ptr<FsmNode>>{nodeC});
+    }
+
+
+    SECTION("graph merge") {
+
+        std::shared_ptr<ConditionalInterpreter> toTest =  std::make_shared<ConditionalInterpreter>("true==true");
+
+        //make the nodes 
+        std::shared_ptr<FsmNode>  nodeA = std::make_shared<FsmNode>(false,true);
+        std::shared_ptr<FsmNode>  nodeB = std::make_shared<FsmNode>(false,false);
+        std::shared_ptr<FsmNode>  nodeC = std::make_shared<FsmNode>(true,false);
+
+        //make the edges
+        
+        std::shared_ptr<FsmEdgeUnique> edgeAB =  std::make_shared<FsmEdgeUnique>(nodeA,nodeB,toTest);
+        std::shared_ptr<FsmEdgeUnique> edgeBC =  std::make_shared<FsmEdgeUnique>(nodeB,nodeC,toTest);
+ 
+        std::shared_ptr<FsmGraph> graph =  std::make_shared<FsmGraph>();
+        graph->addEdge(edgeAB);
+        graph->addEdge(edgeBC);
+
+        REQUIRE(graph->getValidNodes() == std::set<std::shared_ptr<FsmNode>>{nodeC});
+        REQUIRE(graph->getStartNodes() == std::vector<std::shared_ptr<FsmNode>>{nodeA});
+        REQUIRE(graph->getNodes() == std::set<std::shared_ptr<FsmNode>>{nodeA,nodeB,nodeC});
+
+                //make the nodes 
+        std::shared_ptr<FsmNode>  node2A = std::make_shared<FsmNode>(false,true);
+        std::shared_ptr<FsmNode>  node2B = std::make_shared<FsmNode>(false,false);
+        std::shared_ptr<FsmNode>  node2C = std::make_shared<FsmNode>(true,false);
+
+
+        std::shared_ptr<FsmEdgeUnique> edge2AB =  std::make_shared<FsmEdgeUnique>(node2A,node2B,toTest);
+        std::shared_ptr<FsmEdgeUnique> edge2BC =  std::make_shared<FsmEdgeUnique>(node2B,node2C,toTest);
+ 
+        std::shared_ptr<FsmGraph> graph2 =  std::make_shared<FsmGraph>();
+
+
+        graph2->addEdge(edge2AB);
+        graph2->addEdge(edge2BC);
+
+        
+        REQUIRE(graph2->getValidNodes() == std::set<std::shared_ptr<FsmNode>>{node2C});
+        REQUIRE(graph2->getStartNodes() == std::vector<std::shared_ptr<FsmNode>>{node2A});
+        REQUIRE(graph2->getNodes() == std::set<std::shared_ptr<FsmNode>>{node2A,node2B,node2C});
+
+
+        graph->mergeOneStartOneValid(graph2);
+
+        REQUIRE(graph->getValidNodes() == std::set<std::shared_ptr<FsmNode>>{node2C});
+        REQUIRE(graph->getStartNodes() == std::vector<std::shared_ptr<FsmNode>>{nodeA});
+        REQUIRE(graph->getNodes() == std::set<std::shared_ptr<FsmNode>>{nodeA,nodeB,nodeC,node2B,node2C});
+    }
+
+
+
+
+}
+
+// TEST_CASE("matchFSM", "FsmGraph") {
+
+//     SECTION("FsmEdgeUnique constructor") {
+//         //make the nodes 
+//         std::shared_ptr<FsmNode>  nodeA = std::make_shared<FsmNode>(true,false);
+//         std::shared_ptr<FsmNode>  nodeB = std::make_shared<FsmNode>(false,true);
+
+//         //make the edges
+//         std::shared_ptr<ConditionalInterpreter> toTest =  std::make_shared<ConditionalInterpreter>("true==true");
+//         std::shared_ptr<FsmEdgeUnique> edge =  std::make_shared<FsmEdgeUnique>(nodeA,nodeB,toTest);
+ 
+//         std::shared_ptr<FsmGraph> graph =  std::make_shared<FsmGraph>();
+
+//         graph->addEdge(edge);
+        
+
+
+//     }
+
+// }
\ No newline at end of file
diff --git a/unit_tests/graphRegex/Test_GraphFsmInterpreter.cpp b/unit_tests/graphRegex/Test_GraphFsmInterpreter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d151f46c0d8b460d15dbe871fc71024a5a902043
--- /dev/null
+++ b/unit_tests/graphRegex/Test_GraphFsmInterpreter.cpp
@@ -0,0 +1,27 @@
+
+#include <catch2/catch_test_macros.hpp>
+
+#include "aidge/graphRegex/GraphFsmInterpreter.hpp"
+
+
+using namespace Aidge;
+TEST_CASE("GraphFsmInterpreter", "GraphFsmInterpreter") {
+
+    SECTION("Construction") {
+        std::map<std::string,std::shared_ptr<ConditionalInterpreter>> allTest = {
+            {"A",std::make_shared<ConditionalInterpreter>("true==true")},
+            {"B",std::make_shared<ConditionalInterpreter>("true==true")},
+            {"C",std::make_shared<ConditionalInterpreter>("true==true")}
+        };
+
+        //GraphFsmInterpreter("A->B",allTest);
+        std::shared_ptr<GraphFsmInterpreter>  fsmGenerator = std::make_shared<GraphFsmInterpreter>("A->B",allTest);
+        std::shared_ptr<FsmGraph> fsm = fsmGenerator->interpret();
+
+        
+        REQUIRE(fsm->getNodes().size() == 3);
+        REQUIRE(fsm->getStartNodes().size() == 1);
+    }
+
+
+}
\ No newline at end of file
diff --git a/unit_tests/graphRegex/Test_GraphLexer.cpp b/unit_tests/graphRegex/Test_GraphLexer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9b922e5bd70ee1537f54100a2b8e9c826ff5e0c2
--- /dev/null
+++ b/unit_tests/graphRegex/Test_GraphLexer.cpp
@@ -0,0 +1,118 @@
+#include <catch2/catch_test_macros.hpp>
+#include "aidge/graphRegex/GraphLexer.hpp"
+#include "aidge/graphRegex/GraphRegexTypes.hpp"
+
+#include "aidge/utilsParsing/ParsingToken.hpp"
+
+
+#include <iostream>
+#include <map>
+#include <functional>
+
+using namespace Aidge;
+
+// NEXT
+// QOM
+// QZM
+// KEY
+// CKEY
+// SEP
+// LPAREN
+// RPAREN
+
+TEST_CASE("GraphRegex", "Lexer") {
+    SECTION("RandomGenerateTest") {
+
+        std::map<gRegexTokenTypes, std::function<std::pair<std::string, std::string>()>> LexerTestMap{
+            {gRegexTokenTypes::NEXT,      +[](){return std::pair<std::string, std::string>("-> ","");}},
+            {gRegexTokenTypes::QOM,       +[](){return std::pair<std::string, std::string>("+ ","");}},
+            {gRegexTokenTypes::QZM,       +[](){return std::pair<std::string, std::string>("* ","");}},
+            {gRegexTokenTypes::SEP,      +[](){return std::pair<std::string, std::string>("; ","");}},
+
+
+
+            {gRegexTokenTypes::KEY,   +[](){
+                std::size_t keyLen = (std::rand() % 20)+1;
+                const std::string characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_";
+                std::size_t randomIndex = std::rand() % characters.size();
+                std::string key;
+                for (std::size_t i = 0; i < keyLen; ++i) {
+                    key += characters[randomIndex];
+                    randomIndex = std::rand() % characters.size();
+                }
+
+                return std::pair<std::string, std::string>(key+" ",key);}
+            },
+
+           {gRegexTokenTypes::CKEY,   +[](){
+                std::size_t keyLen = (std::rand() % 20)+1;
+                const std::string characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_";
+                const std::string num = "1234567890";
+
+                std::size_t randomIndex = std::rand() % characters.size();
+                std::size_t randomNum = std::rand() % num.size();
+                std::string key;
+                std::string idx;
+
+                for (std::size_t i = 0; i < keyLen; ++i) {
+                    key += characters[randomIndex];
+                    idx += num[randomNum];
+                    randomIndex = std::rand() % characters.size();
+                    randomNum = std::rand() % num.size();
+                }
+
+                return std::pair<std::string, std::string>(key+"#"+idx+" ",key+"#"+idx);}
+            },
+
+            {gRegexTokenTypes::LPAREN,   +[](){return std::pair<std::string, std::string>("( ","");}},
+            {gRegexTokenTypes::RPAREN,   +[](){return std::pair<std::string, std::string>(") ","");}}
+            //{gRegexTokenTypes::STOP,     +[](){return std::pair<std::string, std::string>("","");}}
+        };
+
+
+        //////////////////
+        //TEST GENERATOR
+        //////////////////
+        const std::size_t numRandomElements = 1000;
+        std::vector<std::tuple<gRegexTokenTypes, std::string>> testVector;
+
+        std::string testString;
+
+        for (std::size_t i = 0; i < numRandomElements; ++i) {
+
+            int randomIndex = std::rand() % LexerTestMap.size();
+            // Get an iterator to the random element in the map
+            auto it = std::next(LexerTestMap.begin(), randomIndex);
+            // Access the random key and lambda value separately using structured binding
+            gRegexTokenTypes randomKey = it->first;
+
+            std::function<std::pair<std::string, std::string>()> randomValue = it->second;
+            std::pair<std::string, std::string> result = randomValue();
+        
+            testString += result.first;
+            testVector.emplace_back(randomKey, result.second);
+
+       
+        }
+
+        GraphLexer graphLexer = GraphLexer(testString);
+
+        for (std::tuple<gRegexTokenTypes, std::string> testToken : testVector) {
+            gRegexTokenTypes tokenToFind = std::get<0>(testToken);
+            std::string lexemToFind = std::get<1>(testToken);
+            std::shared_ptr<ParsingToken<gRegexTokenTypes>> token = graphLexer.getNextToken();
+
+
+            std::ostringstream errorMessage;
+            errorMessage << "\n we whant :"<< lexemToFind << "\n we get : "<< token->getLexeme() <<"\n"<< "on \n" << testString << " :\n "  ;
+
+            CAPTURE(errorMessage.str());
+            REQUIRE(token->getLexeme() == lexemToFind);
+            REQUIRE(token->getType() == tokenToFind);
+        }
+        std::shared_ptr<ParsingToken<gRegexTokenTypes>> token = graphLexer.getNextToken();
+        REQUIRE(token->getType() == gRegexTokenTypes::STOP);
+    }
+
+
+}
\ No newline at end of file
diff --git a/unit_tests/graphRegex/Test_GraphParser.cpp b/unit_tests/graphRegex/Test_GraphParser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ff74b676598d5fe63fe47b5c5cd24ba123aca004
--- /dev/null
+++ b/unit_tests/graphRegex/Test_GraphParser.cpp
@@ -0,0 +1,80 @@
+
+#include <catch2/catch_test_macros.hpp>
+#include "aidge/graphRegex/GraphParser.hpp"
+#include "aidge/utilsParsing/AstNode.hpp"
+#include <iostream>
+
+
+using namespace Aidge;
+    std::string domain();
+    std::string exp() {
+        int randomValue = std::rand() % 3;
+        switch (randomValue) {
+        case 0:
+            return "A";
+        case 1 :
+            return "A#";
+        default:
+             return domain();
+
+        }
+    }
+
+    std::string seq() {
+        int randomValue = std::rand() % 2;
+        switch (randomValue) {
+        case 0:
+            return exp();
+        default:
+             return  exp()+"->"+seq();
+        }
+    }
+
+    std::string domain() {
+        int randomValue = std::rand() % 2;
+
+        switch (randomValue) {
+            // case 0:
+            //     return  seq();
+            // case 1:
+            //     return  seq() + "->" +domain();
+
+            case 0:
+                return  "("+ seq() +")*";
+            default:
+                return  "("+ seq() +")+";
+
+            // case 4:
+            //     return  "("+ domain() +")*" + "->" +domain();
+            // default:
+            //     return  "("+ domain() +")+" + "->" +domain();
+        }
+    }
+
+    std::string allExpr() {
+        int randomValue = std::rand() % 2;
+        switch (randomValue) {
+            case 0:
+                return  seq();
+            default :
+                return  seq()+ ";" +allExpr();
+        }
+    }
+
+/*
+exp : KEY(QOM | QZM)?  | CKEY | domain
+seq :exp (NEXT seq)* 
+domain :  LPAREN seq RPAREN (QOM | QZM) 
+allExpr: seq (SEP allExpr)*
+*/
+TEST_CASE("GraphParser", "Test_GraphParser") {
+
+    SECTION("Empty") {
+        for (int i = 0; i < 100; ++i) {
+            const std::string test = allExpr();
+            std::cout << test <<"\n";
+            GraphParser graphParser = GraphParser(test);
+            std::shared_ptr<AstNode<gRegexTokenTypes>> tree = graphParser.parse();
+        }
+    }
+}
\ No newline at end of file
diff --git a/unit_tests/nodeTester/Test_ConditionalInterpreter.cpp b/unit_tests/nodeTester/Test_ConditionalInterpreter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4479adfcde81de36f415e44fefc2c6c5483ce758
--- /dev/null
+++ b/unit_tests/nodeTester/Test_ConditionalInterpreter.cpp
@@ -0,0 +1,30 @@
+
+#include <catch2/catch_test_macros.hpp>
+#include "aidge/nodeTester/ConditionalInterpreter.hpp"
+#include "aidge/operator/GenericOperator.hpp"
+
+
+using namespace Aidge;
+
+
+
+TEST_CASE("ConditionalInterpreter", "ConditionalInterpreter") {
+
+    SECTION("custom Lambda") {
+
+        const std::string test = " !toto($) == true " ;
+        ConditionalInterpreter conditionalParser = ConditionalInterpreter(test);
+        conditionalParser.insertLambda("toto",+[](NodePtr NodeOp){return false;});
+        std::shared_ptr<Node> nodeOp = GenericOperator("conv", 0, 0, 0, "Gop1");
+
+        bool result = conditionalParser.test(nodeOp);
+        REQUIRE(result == true);
+    }
+
+    SECTION("syntax error") {
+
+        const std::string test = "'A' == 'A' ,&& ";
+        REQUIRE_THROWS_AS( ConditionalInterpreter(test), std::runtime_error);
+  
+    }
+}
\ No newline at end of file
diff --git a/unit_tests/nodeTester/Test_ConditionalLexer.cpp b/unit_tests/nodeTester/Test_ConditionalLexer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a937c27227dde4fa03ed7733df9e9552c3c1ac7b
--- /dev/null
+++ b/unit_tests/nodeTester/Test_ConditionalLexer.cpp
@@ -0,0 +1,144 @@
+#include <catch2/catch_test_macros.hpp>
+#include "aidge/nodeTester/ConditionalLexer.hpp"
+#include "aidge/utilsParsing/ParsingToken.hpp"
+
+#include <iostream>
+#include <map>
+#include <functional>
+
+using namespace Aidge;
+
+TEST_CASE("nodeTester", "Lexer") {
+    SECTION("RandomGenerateTest") {
+
+        std::map<ConditionalTokenTypes, std::function<std::pair<std::string, std::string>()>> LexerTestMap{
+            {ConditionalTokenTypes::AND,      +[](){return std::pair<std::string, std::string>("&& ","");}},
+            {ConditionalTokenTypes::OR,       +[](){return std::pair<std::string, std::string>("|| ","");}},
+            {ConditionalTokenTypes::EQ,       +[](){return std::pair<std::string, std::string>("== ","");}},
+            {ConditionalTokenTypes::NEQ,      +[](){return std::pair<std::string, std::string>("!= ","");}},
+
+            {ConditionalTokenTypes::KEY,      +[](){return std::pair<std::string, std::string>("A ","A");}},
+
+            {ConditionalTokenTypes::BOOL,     +[](){
+                std::size_t keyLen = (std::rand() % 2);
+                const std::vector<std::string> characters = {"true","false"};
+          
+                return std::pair<std::string, std::string>(characters[keyLen]+" ",characters[keyLen]);}
+            },
+
+            {ConditionalTokenTypes::INTEGER,  +[](){
+                std::size_t keyLen = (std::rand() % 20)+1;
+                const std::string characters = "1234567890";
+                std::size_t randomIndex = std::rand() % characters.size();
+                std::string key;
+                for (std::size_t i = 0; i < keyLen; ++i) {
+                    key += characters[randomIndex];
+                    randomIndex = std::rand() % characters.size();
+                }
+                return std::pair<std::string, std::string>(key+" ",key);}
+            },
+
+            {ConditionalTokenTypes::FLOAT,    +[](){
+                std::size_t keyLen = (std::rand() % 20)+2;
+                const std::string characters = "1234567890";
+                std::size_t randomIndex = std::rand() % characters.size();
+                std::string key;
+                for (std::size_t i = 0; i < keyLen/2; ++i) {
+                    key += characters[randomIndex];
+                    randomIndex = std::rand() % characters.size();
+                }
+                key += ".";
+                for (std::size_t i = 0; i < keyLen/2; ++i) {
+                    key += characters[randomIndex];
+                    randomIndex = std::rand() % characters.size();
+                }
+                return std::pair<std::string, std::string>(key+" ",key);}
+            },
+
+            {ConditionalTokenTypes::STRING,   +[](){
+                std::size_t keyLen = (std::rand() % 20)+1;
+                const std::string characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 ";
+                std::size_t randomIndex = std::rand() % characters.size();
+                std::string key;
+                for (std::size_t i = 0; i < keyLen; ++i) {
+                    key += characters[randomIndex];
+                    randomIndex = std::rand() % characters.size();
+                }
+
+                return std::pair<std::string, std::string>("'"+key+"' ",key);}
+            },
+
+            {ConditionalTokenTypes::LAMBDA,   +[](){
+
+                std::size_t keyLen = (std::rand() % 20)+1;
+                const std::string characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
+                const std::string Startchar = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+                std::size_t randomIndex = std::rand() % characters.size();
+                std::size_t randomStartIndex = std::rand() % Startchar.size();
+
+                std::string key;
+                key += Startchar[randomStartIndex];
+
+                for (std::size_t i = 0; i < keyLen; ++i) {
+                    key += characters[randomIndex];
+                    randomIndex = std::rand() % characters.size();
+                }
+
+                return std::pair<std::string, std::string>(key+"( ",key);}
+            },
+
+            {ConditionalTokenTypes::ARGSEP,   +[](){return std::pair<std::string, std::string>(", ","");}},
+            {ConditionalTokenTypes::NODE,     +[](){return std::pair<std::string, std::string>("$ ","");}},
+            {ConditionalTokenTypes::LPAREN,   +[](){return std::pair<std::string, std::string>("( ","");}},
+            {ConditionalTokenTypes::RPAREN,   +[](){return std::pair<std::string, std::string>(") ","");}}
+            //{ConditionalTokenTypes::STOP,     +[](){return std::pair<std::string, std::string>("","");}}
+        };
+
+
+        //////////////////
+        //TEST GENERATOR
+        //////////////////
+        const std::size_t numRandomElements = 100;
+        std::vector<std::tuple<ConditionalTokenTypes, std::string>> testVector;
+
+        std::string testString;
+
+        for (std::size_t i = 0; i < numRandomElements; ++i) {
+
+            int randomIndex = std::rand() % LexerTestMap.size();
+            // Get an iterator to the random element in the map
+            auto it = std::next(LexerTestMap.begin(), randomIndex);
+            // Access the random key and lambda value separately using structured binding
+            ConditionalTokenTypes randomKey = it->first;
+
+            std::function<std::pair<std::string, std::string>()> randomValue = it->second;
+            std::pair<std::string, std::string> result = randomValue();
+        
+            testString += result.first;
+            testVector.emplace_back(randomKey, result.second);
+
+       
+        }
+
+        ConditionalLexer conditionalLexer = ConditionalLexer(testString);
+
+        for (std::tuple<ConditionalTokenTypes, std::string> testToken : testVector) {
+            ConditionalTokenTypes tokenToFind = std::get<0>(testToken);
+            std::string lexemToFind = std::get<1>(testToken);
+            std::shared_ptr<ParsingToken<ConditionalTokenTypes>> token = conditionalLexer.getNextToken();
+
+
+            std::ostringstream errorMessage;
+            errorMessage << "\n we whant :"<< lexemToFind << "\n we get : "<< token->getLexeme() <<"\n"<< "on \n" << testString << " :\n "  ;
+
+            CAPTURE(errorMessage.str());
+            REQUIRE(token->getLexeme() == lexemToFind);
+            REQUIRE(token->getType() == tokenToFind);
+        }
+        std::shared_ptr<ParsingToken<ConditionalTokenTypes>> token = conditionalLexer.getNextToken();
+        REQUIRE(token->getType() == ConditionalTokenTypes::STOP);
+    }
+
+
+}
\ No newline at end of file
diff --git a/unit_tests/nodeTester/Test_ConditionalParser.cpp b/unit_tests/nodeTester/Test_ConditionalParser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..56adb92b41745001e1790e087f07369918794c5d
--- /dev/null
+++ b/unit_tests/nodeTester/Test_ConditionalParser.cpp
@@ -0,0 +1,75 @@
+
+#include <catch2/catch_test_macros.hpp>
+#include "aidge/nodeTester/ConditionalParser.hpp"
+#include "aidge/utilsParsing/AstNode.hpp"
+
+using namespace Aidge;
+
+    std::string gVal() {
+        int randomValue = std::rand() % 5;
+        switch (randomValue) {
+        case 0:
+            return std::to_string(std::rand() % 101);
+
+        case 1:
+            return std::to_string(std::rand() % 101)+"."+std::to_string(std::rand() % 101);
+
+        case 2:
+             return " 'toto' ";
+        case 3:
+             return " A ";
+
+        case 4:
+             return " A(10) ";
+
+        default:
+             return " true ";
+
+        }
+    }
+
+    std::string gExpr() ;
+    std::string gCmpr() {
+        int randomValue = std::rand() % 3;
+        switch (randomValue) {
+            case 0:
+                return  gVal() + " == " +gVal();
+            case 1:
+                return  "("+ gExpr() +")";
+            default:
+                return  gVal() + " != " +gVal();
+
+        }
+
+
+        return gVal() + " == " +gVal();
+    }
+
+    std::string gExpr() {
+        std::string out = gCmpr();
+        int iterations = std::rand() % 100;
+        for (int i = 0; i < iterations; ++i) {
+            int randomValue = std::rand() % 2;
+            switch (randomValue) {
+                case 0:
+                    return  out +" && " + gCmpr();
+                    break;
+                default:
+                    return  out +" || " + gCmpr();
+                    break;
+            }
+        }
+        return out;
+    }
+
+
+TEST_CASE("ConditionalParser", "ConditionalParser") {
+
+    SECTION("Empty") {
+        for (int i = 0; i < 100; ++i) {
+            const std::string test = gExpr();
+            ConditionalParser conditionalParser = ConditionalParser(test);
+            std::shared_ptr<AstNode<ConditionalTokenTypes>> tree = conditionalParser.parse();
+        }
+    }
+}
\ No newline at end of file