/// <summary> /// Returns the set of all states that can be reached by following epsilon transitions only /// </summary> /// <param name="nfa"></param> /// <param name="group"></param> /// <returns></returns> public Set <TState> EpsilonClosure(INFA <TState, TInput, TTransition> nfa, IEnumerable <TState> group) { var queue = new Queue <TState>(group); var closure = new Set <TState>(); while (queue.Count != 0) { var state = queue.Dequeue(); closure.Add(state); // Targets reachable from the current node not already added to the closure var epsilonTargets = nfa.FromSource(state) .Where(t => t.Input.Equals(nfa.Epsilon)) .Where(t => !closure.Contains(t.Target)) .Select(t => t.Target); foreach (var target in epsilonTargets) { queue.Enqueue(target); } } return(closure); }
/// <summary> /// Generates and returns the equivalent <see cref="IDFA{TState, TInput, TTransition}"/> /// from the supplied <see cref="INFA{TState, TInput, TTransition}"/> /// </summary> /// <param name="nfa"></param> /// <returns></returns> public IDFA <TState, TInput, TTransition> DFAFromNFA(INFA <TState, TInput, TTransition> nfa) { var partial = RemoveDeadStates(EquivalenceMinimization(DFA(nfa))); return(new DFA <TState, TInput, TTransition>( partial.Initial, partial.Terminals, partial.Transitions )); }
/// <summary> /// Transforms an <see cref="INFA{TState, TInput, TTransition}"/> to a /// <see cref="IDFA{TState, TInput, TTransition}"/> by removing all epsilon /// transitions from an NFA by compositing states and transitions under /// epsilon closures /// </summary> /// <param name="nfa"></param> /// <returns></returns> public PartialDFA DFA( INFA <TState, TInput, TTransition> nfa) { var first = EpsilonClosure(nfa, Set <TState> .Of(nfa.Initial)); var groupTransitions = new List <TGroupTransition>(); var terminalGroups = new List <Set <TState> >(); // Create work queue of groups to process var unmarkedGroups = new Queue <Set <TState> >(); unmarkedGroups.Enqueue(first); var markedGroups = new Set <Set <TState> >(); while (unmarkedGroups.Any()) { var group = unmarkedGroups.Dequeue(); markedGroups.Add(group); if (group.Contains(nfa.Terminal)) { terminalGroups.Add(group); } // Find new epsilon closed group for each possible input foreach (var input in nfa.Inputs.Where(i => !i.Equals(nfa.Epsilon))) { var closure = EpsilonClosure(nfa, nfa.Move(group, input)); if (!closure.Any()) { continue; } // Add unseen groups to unmarked groups if (!unmarkedGroups.Contains(closure) && !markedGroups.Contains(closure)) { unmarkedGroups.Enqueue(closure); } // Add the newly formed transition groupTransitions.Add(GroupTransition(group, input, closure)); } } return(Reduce( first, terminalGroups, groupTransitions )); }