private static void WriteStates(TextWriter writer, FiniteAutomata automata)
 {
     writer.WriteLine($"\"\" [shape=none]");
     foreach (var state in automata.States)
     {
         writer.WriteLine($"\"{state.StateName}\" [shape= {(state.IsFinal ? "doublecircle" : "circle")}]");
     }
 }
 private static void PrepareDotFile(FiniteAutomata automata)
 {
     using (var writer = new StreamWriter($"../../../{DotFileName}", false))
     {
         writer.WriteLine("digraph myAutomation {");
         writer.WriteLine("rankdir=LR;");
         WriteStates(writer, automata);
         WriteTransitions(writer, automata);
         writer.WriteLine("}");
     }
 }
 private static void WriteTransitions(TextWriter writer, FiniteAutomata automata)
 {
     writer.WriteLine($"\"\" -> \"{automata.States.GetInitialState().StateName}\"");
     foreach (var state in automata.States)
     {
         foreach (var transition in state.Transitions)
         {
             writer.WriteLine(
                 $"\"{state.StateName}\" -> \"{transition.TransitionTo.StateName}\" [label = \"{transition.GetTextForGraphLabel()}\"]");
         }
     }
 }
        public static void WriteToFile(FiniteAutomata automata, string fileName)
        {
            using (var w = File.CreateText($"../../../{fileName}.txt"))
            {
                w.WriteLine($"# {automata.Comment}");
                w.WriteLine(
                    $"alphabet: {string.Join(",", automata.Alphabet.AlphabetChars.Select(char.ToLower).ToList())}");
                w.WriteLine(
                    $"states: {string.Join(",", automata.States.OrderByDescending(x => x.IsInitial).Select(x => x.StateName))}");
                w.WriteLine(
                    $"final: {string.Join(",", automata.States.Where(x => x.IsFinal).Select(x => x.StateName))}");
                w.WriteLine("transitions:");
                foreach (var state in automata.States)
                {
                    foreach (var transition in state.Transitions)
                    {
                        w.WriteLine(
                            $"{transition.TransitionFrom.StateName}," +
                            $"{(transition.TransitionChar == Epsilon.Letter ? '_' : transition.TransitionChar)}" +
                            $" --> {transition.TransitionTo.StateName}");
                    }
                }
                w.WriteLine("end.");
                w.WriteLine(Environment.NewLine);

                if (automata.TestWords.Any())
                {
                    w.WriteLine("words:");
                    foreach (var word in automata.TestWords)
                    {
                        w.WriteLine($"{word},{(word.IsAccepted ? "y" : "n")}");
                    }
                    w.WriteLine("end.");
                }
                w.WriteLine(Environment.NewLine);
                w.WriteLine($"finite: {(automata.IsFinite ? "y" : "n")}");
                w.WriteLine(Environment.NewLine);
                w.WriteLine($"dfa: {(automata.IsDfa ? "y" : "n")}");
            }
        }
        public virtual FiniteAutomata ToDfa()
        {
            if (this.IsDfa)
            {
                return(this);
            }

            // A dictionary to store the combined state and it's individual states.
            var currentStatesDict     = new Dictionary <State, List <State> >();
            var notProcessedYetStates = new List <State>();
            var finishedStates        = new List <State>();

            // First get the epsilon closure. Then make a single state and add it to the to be processed states.
            var initialEpsilonClosure = this.GetPossibleEpsilonStates(new List <State>()
            {
                this.States.GetInitialState()
            })
                                        .OrderBy(x => x.StateName)
                                        .ToList();
            var initialDfaState =
                this.MakeSingleState(initialEpsilonClosure, true, initialEpsilonClosure.Any(x => x.IsFinal));

            notProcessedYetStates.Add(initialDfaState);
            currentStatesDict.Add(initialDfaState, initialEpsilonClosure);
            while (notProcessedYetStates.Any())
            {
                // Always process the first one. We know that there is at least 1 because of the check in the while loop.
                var toBeProcessed = notProcessedYetStates[0];
                var currentStates = currentStatesDict[toBeProcessed];
                foreach (var letter in this.Alphabet.AlphabetChars)
                {
                    // 1. Get all the possible states reachable by the letter. If any then also get the epsilon closures that can be reached
                    // from these states. Note the ordering by name to ensure consistency and to avoid scenarios where {2,3} is considered a different
                    // state than {3,2}.
                    var states = this.GetPossibleStates(currentStates, letter);
                    if (states.Any())
                    {
                        var statesAndEpsilonClosure = this.GetPossibleEpsilonStates(states)
                                                      .OrderBy(x => x.StateName)
                                                      .ToList();
                        // Note that we mark the combined state as final as long as any of the states in the set are final.
                        var newState = this.MakeSingleState(
                            statesAndEpsilonClosure, false, statesAndEpsilonClosure.Any(x => x.IsFinal));
                        if (toBeProcessed.StateName == "B")
                        {
                            var z = false;
                        }
                        // Note that we can check if the new state is not actually the same one - in case of a self-loop.
                        newState = newState.Equals(toBeProcessed) ? toBeProcessed : newState;
                        // If the resulting state has already been processed -> assign it to the variable. Else add it to the to be processed list.
                        if (finishedStates.Contains(newState))
                        {
                            newState = finishedStates.Single(x => x.Equals(newState));
                        }
                        else if (!notProcessedYetStates.Contains(newState))
                        {
                            notProcessedYetStates.Add(newState);
                            currentStatesDict.Add(newState, statesAndEpsilonClosure);
                        }
                        toBeProcessed.AddTransition(new Transition(letter, toBeProcessed, newState));
                    }
                    // If there is no states reachable by letter that means we need a sink. First verify if one doesn't already exist. If it does, add a transition
                    // to it. Else create a new sink, make a self-transition for each letter to also ensure the sink is considered DFA and then add it directly
                    // to the finished states list.
                    else
                    {
                        var sink = finishedStates.SingleOrDefault(x => x.IsSink);
                        if (sink == null)
                        {
                            sink = new State("Sink", false, false, true);
                            foreach (var sinkLetter in this.Alphabet.AlphabetChars)
                            {
                                sink.AddTransition(new Transition(sinkLetter, sink, sink));
                            }
                            finishedStates.Add(sink);
                        }
                        toBeProcessed.AddTransition(new Transition(letter, toBeProcessed, sink));
                    }
                }
                foreach (var finished in finishedStates)
                {
                    // Make sure to update existing references to keep the transitions up to date.
                    var transitionsTo =
                        finished.Transitions.Where(x => x.TransitionTo.StateName == toBeProcessed.StateName);
                    foreach (var trans in transitionsTo)
                    {
                        trans.TransitionTo = toBeProcessed;
                    }
                }
                // Finally add the processed state to the final ones and remove it from the to be processed. Also clean up the dictionary.
                finishedStates.Add(toBeProcessed);
                notProcessedYetStates.Remove(toBeProcessed);
                currentStatesDict.Remove(toBeProcessed);
            }
            var automata = new FiniteAutomata(this.Comment, this.Alphabet, new List <State>(finishedStates), this.TestWords, true, false);

            automata.AcceptWords();
            return(automata);
        }
 public static string CreateNodeGraphImage(FiniteAutomata automata)
 {
     PrepareDotFile(automata);
     return(CreateAutomataGraph());
 }