/// <summary>
        /// Gets result of execution of the FA on the string
        /// </summary>
        /// <param name="input">Input string</param>
        /// <returns>Execution result</returns>
        public ResultEnum Execute(string input)
        {
            var errors = FAAnalyzer.GetErrors(Graph);

            if (errors.Count > 0)
            {
                throw new InvalidOperationException(errors.Aggregate("", (folder, error) => folder + error + "\n"));
            }
            var FA = FiniteAutomata.ConvertGraphToAutomata(Graph.Edges.ToList(), Graph.Vertices.ToList());

            return(FA.DoAllTransitions(input) ? ResultEnum.Passed : ResultEnum.Failed);
        }
        /// <summary>
        /// Gets FA model which executes input string step by step
        /// </summary>
        /// <param name="input">Input string</param>
        /// <returns>FA with specified graph and string</returns>
        public FiniteAutomata StartDebug(string input)
        {
            var errors = FAAnalyzer.GetErrors(Graph);

            if (errors.Count > 0)
            {
                throw new InvalidOperationException(errors.Aggregate("", (folder, error) => folder + error + "\n"));
            }
            var FA = FiniteAutomata.ConvertGraphToAutomata(Graph.Edges.ToList(), Graph.Vertices.ToList());

            FA.SetString(input);
            return(FA);
        }
        public static BidirectionalGraph <NodeViewModel, EdgeViewModel> Convert(
            BidirectionalGraph <NodeViewModel, EdgeViewModel> nfaGraph)
        {
            RequireValidNfa(nfaGraph);

            var dfaGraph = new BidirectionalGraph <NodeViewModel, EdgeViewModel>();
            var nfa      = FiniteAutomata.ConvertGraphToAutomata(nfaGraph.Edges.ToList(), nfaGraph.Vertices.ToList());

            var unhandledQueue  = new Queue <Tuple <HashSet <int>, NodeViewModel> >();
            var handledStates   = new HashSet <HashSet <int> >(HashSet <int> .CreateSetComparer());
            var statesToNodeMap = new Dictionary <HashSet <int>, NodeViewModel>(HashSet <int> .CreateSetComparer());

            var initStates = nfa.EpsilonClosure(
                nfaGraph.Vertices
                .Where(v => v.IsInitial)
                .Select(v => (int)v.ID).ToList()
                ).ToHashSet();
            var initNodes         = initStates.Select(id => nfaGraph.Vertices.FirstOrDefault(v => v.ID == id)).ToList();
            var initCompositeNode = CreateCompositeNode(initNodes);

            initCompositeNode.IsInitial = true;
            unhandledQueue.Enqueue(new Tuple <HashSet <int>, NodeViewModel>(initStates, initCompositeNode));
            statesToNodeMap[initStates] = initCompositeNode;
            dfaGraph.AddVertex(initCompositeNode);

            while (unhandledQueue.Count != 0)
            {
                var(sourceStates, sourceNode) = unhandledQueue.Dequeue();
                if (!handledStates.Add(sourceStates))
                {
                    continue;
                }
                var newEdges = new Dictionary <NodeViewModel, List <char> >();
                foreach (var ch in nfa.Alphabet)
                {
                    var targetStates = nfa.EpsilonClosure(nfa.GetAllNewStates(sourceStates.ToList(), ch)).ToHashSet();
                    if (targetStates.Count == 0)
                    {
                        continue;
                    }
                    var targetNodes = targetStates
                                      .Select(id => nfaGraph.Vertices.FirstOrDefault(v => v.ID == id))
                                      .ToList();
                    NodeViewModel targetNode;
                    if (statesToNodeMap.ContainsKey(targetStates))
                    {
                        targetNode = statesToNodeMap[targetStates];
                    }
                    else
                    {
                        targetNode = CreateCompositeNode(targetNodes);
                        statesToNodeMap[targetStates] = targetNode;
                        dfaGraph.AddVertex(targetNode);
                    }

                    if (newEdges.ContainsKey(targetNode))
                    {
                        newEdges[targetNode].Add(ch);
                    }
                    else
                    {
                        newEdges[targetNode] = new List <char> {
                            ch
                        };
                    }

                    unhandledQueue.Enqueue(new Tuple <HashSet <int>, NodeViewModel>(targetStates, targetNode));
                }

                newEdges.ForEach(entry =>
                                 dfaGraph.AddEdge(new EdgeViewModel(sourceNode, entry.Key)
                {
                    TransitionTokensString = new string(entry.Value.ToArray())
                })
                                 );
            }

            return(dfaGraph);
        }