/// <summary>
        /// Removes useless symbols from the grammar.
        /// Assumes that the language is nonempty.
        /// </summary>
        public ContextFreeGrammar RemoveUselessSymbols()
        {
            HashSet <Nonterminal> useful_backwards = new HashSet <Nonterminal>();

            //Lemma 4.1, p. 88, Hopcroft-Ullman
            #region backward reachability
            var variableNodeMap = new Dictionary <Nonterminal, VariableNode>();
            foreach (Nonterminal v in this.variables)
            {
                variableNodeMap[v] = new VariableNode();
            }


            List <ProductionNode> productionLeaves = new List <ProductionNode>();

            foreach (Nonterminal v in this.variables)
            {
                VariableNode parent = variableNodeMap[v];
                foreach (Production p in this.productionMap[v])
                {
                    var            children = Array.ConvertAll(new List <Nonterminal>(p.GetVariables()).ToArray(), w => variableNodeMap[w]);
                    ProductionNode pn       = new ProductionNode(parent, children);
                    if (children.Length == 0)
                    {
                        productionLeaves.Add(pn);
                    }
                    else
                    {
                        foreach (VariableNode child in children)
                        {
                            child.parents.Add(pn);
                        }
                    }
                }
            }

            foreach (ProductionNode leaf in productionLeaves)
            {
                leaf.PropagateMark();
            }

            foreach (Nonterminal v in this.variables)
            {
                if (variableNodeMap[v].isMarked)
                {
                    useful_backwards.Add(v);
                }
            }
            #endregion

            if (!useful_backwards.Contains(this.startSymbol))
            {
                throw new AutomataException(AutomataExceptionKind.LanguageOfGrammarIsEmpty);
            }

            ContextFreeGrammar g1 = this.RestrictToVariables(useful_backwards);

            HashSet <Nonterminal> useful_forwards = new HashSet <Nonterminal>();

            //Lemma 4.2, p. 89, Hopcroft-Ullman
            #region forward reachability
            Stack <Nonterminal> stack = new Stack <Nonterminal>();
            stack.Push(g1.StartSymbol);
            useful_forwards.Add(g1.StartSymbol);

            while (stack.Count > 0)
            {
                Nonterminal v = stack.Pop();
                foreach (Production p in g1.GetProductions(v))
                {
                    foreach (Nonterminal u in p.GetVariables())
                    {
                        if (!useful_forwards.Contains(u))
                        {
                            useful_forwards.Add(u);
                            stack.Push(u);
                        }
                    }
                }
            }

            #endregion

            ContextFreeGrammar g2 = g1.RestrictToVariables(useful_forwards);

            return(g2);
        }
        /// <summary>
        /// Return all useful nonterminal symbols. If checkBackwardsOnly is true, assume that all symbols are reachable from the start symbol.
        /// </summary>
        public HashSet <string> GetUsefulNonterminals(bool checkBackwardsOnly)
        {
            HashSet <Nonterminal> useful_backwards = new HashSet <Nonterminal>();

            //Lemma 4.1, p. 88, Hopcroft-Ullman
            #region backward reachability
            var variableNodeMap = new Dictionary <Nonterminal, VariableNode>();
            foreach (Nonterminal v in this.variables)
            {
                variableNodeMap[v] = new VariableNode();
            }


            List <ProductionNode> productionLeaves = new List <ProductionNode>();

            foreach (Nonterminal v in this.variables)
            {
                VariableNode parent = variableNodeMap[v];
                foreach (Production p in this.productionMap[v])
                {
                    var            children = Array.ConvertAll(new List <Nonterminal>(p.GetVariables()).ToArray(), w => variableNodeMap[w]);
                    ProductionNode pn       = new ProductionNode(parent, children);
                    if (children.Length == 0)
                    {
                        productionLeaves.Add(pn);
                    }
                    else
                    {
                        foreach (VariableNode child in children)
                        {
                            child.parents.Add(pn);
                        }
                    }
                }
            }

            foreach (ProductionNode leaf in productionLeaves)
            {
                leaf.PropagateMark();
            }

            foreach (Nonterminal v in this.variables)
            {
                if (variableNodeMap[v].isMarked)
                {
                    useful_backwards.Add(v);
                }
            }
            #endregion

            //returns the empty set because the language is empty
            if (!useful_backwards.Contains(this.startSymbol))
            {
                return(new HashSet <string>());
            }

            //don't bother to check forward
            if (checkBackwardsOnly)
            {
                var res = new HashSet <string>();
                foreach (var nt in useful_backwards)
                {
                    res.Add(nt.Name);
                }
                return(res);
            }

            ContextFreeGrammar g1 = this.RestrictToVariables(useful_backwards);

            HashSet <Nonterminal> useful_forwards = new HashSet <Nonterminal>();

            //Lemma 4.2, p. 89, Hopcroft-Ullman
            #region forward reachability
            Stack <Nonterminal> stack = new Stack <Nonterminal>();
            stack.Push(g1.StartSymbol);
            useful_forwards.Add(g1.StartSymbol);

            while (stack.Count > 0)
            {
                Nonterminal v = stack.Pop();
                foreach (Production p in g1.GetProductions(v))
                {
                    foreach (Nonterminal u in p.GetVariables())
                    {
                        if (!useful_forwards.Contains(u))
                        {
                            useful_forwards.Add(u);
                            stack.Push(u);
                        }
                    }
                }
            }

            #endregion

            HashSet <string> usefulSymbols = new HashSet <string>();
            foreach (var nt in useful_forwards)
            {
                if (useful_backwards.Contains(nt))
                {
                    usefulSymbols.Add(nt.Name);
                }
            }
            return(usefulSymbols);
        }
 internal ProductionNode(VariableNode parent, params VariableNode[] children)
 {
     this.parent   = parent;
     this.children = new HashSet <VariableNode>(children);
 }