/// <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; }
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); }
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; }
/// <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; }
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); } }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
/// <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; }
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); }
/// <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; }
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); }
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); }
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); }
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); }
public void NewInitialShouldBeFinal() { var m1Start = new GraphState () { IsFinal = true }; var m1 = new Graph () { StartState = m1Start }; var ndfa = m1.Kleene (); ndfa.StartState.IsFinal.Should ().BeTrue (); }
/// <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; }