예제 #1
0
        /// <summary>
        /// Concatinates two NDFA's.
        /// </summary>
        /// <param name="m1">The second NDFA to concatinate with.</param>
        /// <returns>The new graph that is this and m1 concatinated.</returns>
        public Graph Concat(Graph m1)
        {
            var m = new Graph ();
            var m2 = this;

            var m1FinalStates = m1.FindFinalStates (m1.StartState);

            foreach (var finalState in m1FinalStates) {
                //create a new connection to m2 initial state
                var m1FinalTom2Initial = new GraphStateConnection () {
                    Start = finalState,
                    End = m2.StartState,
                    ConnectedBy =
                        Word.Epsilon
                };

                //make the connection
                finalState.Out.Add (m1FinalTom2Initial);

                //kill m1 final states and leave m2 as finals for m
                finalState.IsFinal = false;
            }

            //update state count for new graph
            m.StartState = m1.StartState;
            m.StateCount = m1.StateCount + m2.StateCount;
            if (updateStateNumber) {
                RenumberStates (m.StartState);
            }
            return m;
        }
예제 #2
0
            public void CreatesCorrectConnection()
            {
                var m1Start = new GraphState () {
                    StateNumber = 0,
                    IsFinal = true
                };

                var m2Start = new GraphState () {
                    StateNumber = 1,
                    IsFinal = true
                };

                var m1 = new Graph () {
                    StartState = m1Start
                };

                var m2 = new Graph () {
                    StartState = m2Start
                };

                var ndfa = m1.Concat (m2);

                ndfa.StartState.Out[0].Start.Should ().Be (m2Start);
                ndfa.StartState.Out[0].End.Should ().Be (m1Start);
                ndfa.StartState.Out[0].ConnectedBy.Letter.Should ().Be (Word.Epsilon.Letter);
                ndfa.StartState.Out[0].ConnectedBy.Mapping.Should ().Be (Word.Epsilon.Mapping);
            }
예제 #3
0
        Graph ProcessOperation(Graph initGraph, Operation op, Stack<Word> opStack)
        {
            // create base graph if not done already.
            if(initGraph == null){
                //start of our graph
                initGraph = Graph.CreateNewGraph(opStack.Pop());
            }

            //if kleene operation, do it here.
            if (op.Mapping == OperationType.Kleene) {
                initGraph = initGraph.Kleene ();
            }

            //now process each operation
            while(opStack.Count != 0){
                //get next letter to work with.
                var wordToAdd = opStack.Pop();

                //depending on the mapped type, do operation on graph
                //with the new letter.
                if(op.Mapping == OperationType.Concat)
                    initGraph = initGraph.Concat(wordToAdd);
                else if(op.Mapping == OperationType.Union)
                    initGraph = initGraph.Union(wordToAdd);
            }

            //return the created graph.
            return initGraph;
        }
예제 #4
0
        /// <summary>
        /// Parses a given expression into a graph.
        /// </summary>
        /// <returns>The built graph.</returns>
        /// <param name="expression">The expression to create the graph from.</param>
        /// <param name="initGraph">The graph to append too. Used for recursion.</param>
        public Graph ParseExpression(string expression, Graph initGraph = null)
        {
            var lang = new Language ();
            var ops = new Operations ();
            expression = expression.Trim ();
            var opStack = new Stack<Word>();

            foreach (char letter in expression) {
                //find the language mapping
                var inLanguage = lang
                    .DefaultIfEmpty(null)
                    .FirstOrDefault (w => w.Letter == letter);

                //find the operation mapping
                var inOps = ops
                    .DefaultIfEmpty(null)
                    .FirstOrDefault(w => w.Letter == letter);

                //not in the language or operators
                if(inLanguage == null && inOps == null){
                    throw new InvalidLanguageException("Invalid input: " + letter);
                }

                //it is valid language input, so add it to the list.
                if(inLanguage != null){
                    opStack.Push(inLanguage);
                    continue;
                }
                else{
                    //not a letter, so must be an operation
                    //verify that it has the correct arg count for that type of operation.
                    if (opStack.Count != inOps.MinArgCount && initGraph == null) {
                        throw new InvalidLanguageException (
                            string.Format(
                                "Unbalanced arguement count for operation (expected {0}, but got {1}.",
                                inOps.MinArgCount, opStack.Count
                            ));
                    }
                    //operation, so stop, and process graph
                    initGraph = ProcessOperation(initGraph, inOps, opStack);
                }
            }

            //expression was given with no operation, so error out.
            if (opStack.Count > 0) {
                throw new InvalidLanguageException ("No operation was specified in the given expression.");
            }

            //once done with graph, renumber the states.
            initGraph.RenumberStates ();

            //return the completed graph.
            return initGraph;
        }
예제 #5
0
        public void Print(Graph toPrint)
        {
            //if state has been visited, don't do it again to avoid SO

            List<GraphState> visited = new List<GraphState> ();
            List<string> output = new List<string> ();

            //output start state
            Console.WriteLine ("Start state is: q" + toPrint.StartState.StateNumber);

            //find all state strings to output.
            PrintStatesOutputs (toPrint.StartState, visited, output);

            //now print each row.
            foreach (var row in output.OrderBy (s => s)) {
                Console.WriteLine (row);
            }
        }
예제 #6
0
            public void CreatesOneConnection()
            {
                var m1Start = new GraphState () {
                    StateNumber = 0,
                    IsFinal = true
                };

                var m2Start = new GraphState () {
                    StateNumber = 1,
                    IsFinal = true
                };

                var m1 = new Graph () {
                    StartState = m1Start
                };

                var m2 = new Graph () {
                    StartState = m2Start
                };

                var ndfa = m1.Concat (m2);
                ndfa.StartState.Out.Count.Should ().Be (1);
            }
예제 #7
0
            public void HasLoopConnection()
            {
                var m1Start = new GraphState () {
                    IsFinal = true
                };

                var m1 = new Graph () {
                    StartState = m1Start
                };

                var ndfa = m1.Kleene();
                var self = ndfa.StartState.Out [0].End.Out [0].End;
                self.Should ().Be (ndfa.StartState);
            }
예제 #8
0
            public void HasCorrectFinalStates()
            {
                var m1Start = new GraphState () {
                    StateNumber = 0,
                    IsFinal = true
                };

                var m2Start = new GraphState () {
                    StateNumber = 1,
                    IsFinal = true
                };

                var m1 = new Graph () {
                    StartState = m1Start
                };

                var m2 = new Graph () {
                    StartState = m2Start
                };

                var ndfa = m1.Concat (m2);
                var finals = ndfa.FindFinalStates (ndfa.StartState);
                finals.Count.Should ().Be (1);
                finals [0].Should ().Be (m1Start);
            }
예제 #9
0
            public void HasCorrectStateCount()
            {
                var m1Start = new GraphState () {
                    IsFinal = true
                };

                var m2Start = new GraphState () {
                    IsFinal = true
                };

                var m1 = new Graph () {
                    StartState = m1Start
                };

                var m2 = new Graph () {
                    StartState = m2Start
                };

                var ndfa = m1.Union (m2);
                ndfa.StateCount.Should ().Be (4);
            }
예제 #10
0
            public void StateNumbersCorrect()
            {
                var m1Start = new GraphState () {
                    IsFinal = true
                };

                var m2Start = new GraphState () {
                    IsFinal = true
                };

                var m1 = new Graph () {
                    StartState = m1Start
                };

                var m2 = new Graph () {
                    StartState = m2Start
                };

                var ndfa = m1.Union (m2);
                ndfa.StartState.StateNumber.Should ().Be (0);
                ndfa.StartState.Out [0].End.StateNumber.Should ().Be (1);
            }
예제 #11
0
            public void CreatesCorrectEpsilonConnections()
            {
                var m1Start = new GraphState () {
                    IsFinal = true
                };

                var m2Start = new GraphState () {
                    IsFinal = true
                };

                var m1 = new Graph () {
                    StartState = m1Start
                };

                var m2 = new Graph () {
                    StartState = m2Start
                };

                var finalState = new GraphState {
                    StateNumber = 2,
                    IsFinal = true
                };

                var ndfa = m1.Union (m2);

                ndfa.StartState.Out[0].Start.Should ().Be (ndfa.StartState);
                ndfa.StartState.Out[0].End.Should ().Be (m1Start);
                ndfa.StartState.Out[0].ConnectedBy.Letter.Should ().Be (Word.Epsilon.Letter);
                ndfa.StartState.Out[0].ConnectedBy.Mapping.Should ().Be (Word.Epsilon.Mapping);

                ndfa.StartState.Out[1].Start.Should ().Be (ndfa.StartState);
                ndfa.StartState.Out[1].End.Should ().Be (m2Start);
                ndfa.StartState.Out[1].ConnectedBy.Letter.Should ().Be (Word.Epsilon.Letter);
                ndfa.StartState.Out[1].ConnectedBy.Mapping.Should ().Be (Word.Epsilon.Mapping);

                //epsilons to final state
                var firstFinal = ndfa.StartState.Out[0].End;
                var secondFinal = ndfa.StartState.Out [1].End;

                var finalConnection1 = firstFinal.Out [0];
                finalConnection1.ConnectedBy.Should ().Be (Word.Epsilon);
                finalConnection1.Start.Should ().Be (firstFinal);

                var finalConnection2 = secondFinal.Out [0];
                finalConnection2.ConnectedBy.Should ().Be (Word.Epsilon);

                finalConnection2.Start.Should ().Be (secondFinal);

                //now check the final state

                finalConnection1.End.Should ().Be (finalState);
                finalConnection2.End.Should ().Be (finalState);
            }
예제 #12
0
            public void CreatesFourConnections()
            {
                var m1Start = new GraphState () {
                    IsFinal = true
                };

                var m2Start = new GraphState () {
                    IsFinal = true
                };

                var m1 = new Graph () {
                    StartState = m1Start
                };

                var m2 = new Graph () {
                    StartState = m2Start
                };

                var ndfa = m1.Union (m2);
                ndfa.StartState.Out.Count.Should ().Be (2);
                ndfa.StartState.Out [0].End.Out.Count.Should ().Be (1);
                ndfa.StartState.Out [1].End.Out.Count.Should ().Be (1);
            }
예제 #13
0
        /// <summary>
        /// Performs the Union on two NDFA's. 
        /// </summary>
        /// <param name="m2">The NDFA to Union with.</param>
        /// <returns>>A new NDFA that is the union of the two graphs.</returns>
        public Graph Union(Graph m2)
        {
            var m = new Graph ();
            var m1 = this;

            //new start state
            m.StartState = new GraphState ();

            //new q0
            var newFinalState = new GraphState () {
                IsFinal = true
            };

            //connection from q0 to q1 over epsilon
            var q0Toq1 = new GraphStateConnection () {
                ConnectedBy = Word.Epsilon,
                Start = m.StartState,
                End = m1.StartState
            };

            //connection from q0 to q2
            var q0Toq2 = new GraphStateConnection () {
                ConnectedBy = Word.Epsilon,
                Start = m.StartState,
                End = m2.StartState
            };

            //attach states.
            m.StartState.Out.Add (q0Toq1);
            m.StartState.Out.Add (q0Toq2);

            var m1Finals = FindFinalStates (m1.StartState);
            var m2Finals = FindFinalStates (m2.StartState);

            foreach (var final in m1Finals) {
                final.IsFinal = false;
                var finalConnection = new GraphStateConnection () {
                    Start = final,
                    End = newFinalState,
                    ConnectedBy = Word.Epsilon
                };
                final.Out.Add (finalConnection);
            }

            foreach (var final in m2Finals) {
                final.IsFinal = false;
                var finalConnection = new GraphStateConnection () {
                    Start = final,
                    End = newFinalState,
                    ConnectedBy = Word.Epsilon
                };
                final.Out.Add (finalConnection);
            }

            //update the total state count
            m.StateCount = m1.StateCount + m2.StateCount + 2;
            if (updateStateNumber) {
                RenumberStates (m.StartState);
            }
            return m;
        }
예제 #14
0
            public void StateNumbersCorrect()
            {
                var m1 = new Graph () {
                    StartState =  new GraphState () {
                        IsFinal = false,
                        StateNumber = 0
                    }
                };

                m1.StartState.Out.Add (new GraphStateConnection () {
                    ConnectedBy = new Word('a'),
                    Start = m1.StartState,
                    End = new GraphState() {
                        StateNumber = 1
                    }
                });

                var ndfa = m1.Kleene ();
                ndfa.StartState.Out [0].End.StateNumber.Should ().Be (0);
                ndfa.StartState.Out [0].End.Out[0].End.StateNumber.Should ().Be (1);
                ndfa.StartState.StateNumber.Should ().Be (2);
            }
예제 #15
0
 /// <summary>
 /// Helper method to create a new graph based on a specified word.
 /// Creates a two node graph that is connected by the specified word.
 /// </summary>
 /// <returns>The new graph.</returns>
 /// <param name="fromConnection">The word to connect by.</param>
 internal static Graph CreateNewGraph(Word fromConnection)
 {
     var graph = new Graph () {
         StartState = new GraphState() { StateNumber = 0 }
     };
     graph.StartState.Out.Add (new GraphStateConnection () {
         Start = graph.StartState,
         End = new GraphState() { StateNumber = 1, IsFinal = true },
         ConnectedBy = fromConnection
     });
     graph.StateCount = 2;
     return graph;
 }
예제 #16
0
            public void HasCorrectTwoStateCount()
            {
                var m1Start = new GraphState () {
                    StateNumber = 0,
                    IsFinal = true
                };

                var m2Start = new GraphState () {
                    StateNumber = 1,
                    IsFinal = true
                };

                var m1 = new Graph () {
                    StartState = m1Start
                };

                var m2 = new Graph () {
                    StartState = m2Start
                };

                var ndfa = m1.Concat (m2);
                ndfa.StateCount.Should ().Be (2);
            }
예제 #17
0
            public void HasCorrectSingleFinalState()
            {
                var m1Start = new GraphState () {
                    IsFinal = true
                };

                var m1 = new Graph () {
                    StartState = m1Start
                };

                var finals = m1.FindFinalStates (m1.StartState);
                finals [0].Should ().Be (m1Start);
            }
예제 #18
0
            public void HasCorrectCount()
            {
                var m1Start = new GraphState () {
                    IsFinal = true
                };

                var m1 = new Graph () {
                    StartState = m1Start
                };

                var finals = m1.FindFinalStates (m1.StartState);
                finals.Count.Should ().Be (1);
            }
예제 #19
0
            public void CountsOnlyOneFinal()
            {
                var m1Start = new GraphState () {
                    IsFinal = true
                };
                var secondFinal = new GraphState () {
                    IsFinal = true
                };
                var thirdFinal = new GraphState () {
                    IsFinal = true
                };
                var m1 = new Graph () {
                    StartState = m1Start
                };

                var epsilonConnection1 = new GraphStateConnection {
                    Start = m1Start,
                    End = secondFinal,
                    ConnectedBy = Word.Epsilon
                };

                var epsilonConnection2 = new GraphStateConnection {
                    Start = secondFinal,
                    End = thirdFinal,
                    ConnectedBy = Word.Epsilon
                };

                m1.StartState.Out.Add (epsilonConnection1);
                secondFinal.Out.Add (epsilonConnection2);

                var finals = m1.FindFinalStates (m1.StartState);
                finals.Count.Should ().Be (3);
            }
예제 #20
0
            public void NewInitialShouldBeFinal()
            {
                var m1Start = new GraphState () {
                    IsFinal = true
                };

                var m1 = new Graph () {
                    StartState = m1Start
                };

                var ndfa = m1.Kleene ();
                ndfa.StartState.IsFinal.Should ().BeTrue ();
            }
예제 #21
0
        /// <summary>
        /// Perfoms a Kleene operation on the graph.
        /// </summary>
        /// <returns>The new graph after the Kleene operation.</returns>
        public Graph Kleene()
        {
            var m = new Graph ();
            var m1 = this;

            var finals = FindFinalStates (m1.StartState);
            var oldInitial = m1.StartState;

            //create new init and final state.
            var newInitial = new GraphState (){
                IsFinal = true,
                StateNumber = m1.StateCount + 1
            };

            //create connection from new initial to the old initial through epsilon
            var initialEpsilonConnection = new GraphStateConnection {
                End = oldInitial,
                Start = newInitial,
                ConnectedBy = Word.Epsilon
            };

            //add the connection to the states.
            newInitial.Out.Add (initialEpsilonConnection);

            foreach (var finalState in finals) {
                //now create epsilon connections from final to original start state
                var finalToOldInitialConnection = new GraphStateConnection {
                    End = newInitial,
                    Start = finalState,
                    ConnectedBy = Word.Epsilon
                };

                finalState.IsFinal = false;

                //now connect them
                finalState.Out.Add(finalToOldInitialConnection);
            }

            //now attach the new init state to the graph
            m.StartState = newInitial;
            m.StateCount = m1.StateCount + 1;
            return m;
        }