/// <summary> /// Prunes all the unreachable states from this automaton /// </summary> public void Prune() { DFAInverse inverse = new DFAInverse(this); List <DFAState> finals = inverse.CloseByAntecedents(inverse.Finals); // no changes if (finals.Count == states.Count) { return; } // Prune the transitions for (int i = 0; i != finals.Count; i++) { DFAState state = finals[i]; List <CharSpan> transitions = new List <CharSpan>(state.Transitions); foreach (CharSpan key in transitions) { DFAState child = state.GetChildBy(key); if (!finals.Contains(child)) { // the child should be dropped state.RemoveTransition(key); } } } // prune DFAState first = states[0]; finals.Remove(states[0]); states.Clear(); states.Add(first); states.AddRange(finals); }
/// <summary> /// Extracts the sub-DFA that leads to any of the specified states /// </summary> /// <param name="targets">States in this DFA</param> /// <returns>The sub-DFA for the specified states</returns> public DFA ExtractSubTo(IEnumerable <DFAState> targets) { if (targets == null) { throw new System.ArgumentException("The specified collection must not be null"); } // build a list of all the required states DFAInverse inverse = new DFAInverse(this); List <DFAState> originals = inverse.CloseByAntecedents(targets); // setup the list int index = originals.IndexOf(states[0]); if (index == -1) { throw new System.ArgumentException("The specified states are not reachable from the starting state"); } originals[index] = originals[0]; originals[0] = states[0]; // copies the states List <DFAState> copy = new List <DFAState>(); for (int i = 0; i != originals.Count; i++) { copy.Add(new DFAState(i)); } for (int i = 0; i != originals.Count; i++) { DFAState original = originals[i]; DFAState clone = copy[i]; clone.AddItems(original.Items); foreach (CharSpan key in original.Transitions) { index = originals.IndexOf(original.GetChildBy(key)); if (index != -1) { clone.AddTransition(key, copy[index]); } } } return(new DFA(copy)); }
/// <summary> /// Determines whether two states should be in the same group /// </summary> /// <param name="s1">A state</param> /// <param name="s2">Another state</param> /// <param name="old">The old partition</param> /// <returns></returns> private static bool AddState_SameGroup(DFAState s1, DFAState s2, DFAPartition old) { if (s1.Transitions.Count != s2.Transitions.Count) { return(false); } // For each transition from state 1 foreach (CharSpan key in s1.Transitions) { // If state 2 does not have a transition with the same value : not same group if (!s2.HasTransition(key)) { return(false); } // Here State1 and State2 have both a transition of the same value // If the target of these transitions are in the same group in the old partition : same transition if (old.AddState_GetGroupOf(s1.GetChildBy(key)) != old.AddState_GetGroupOf(s2.GetChildBy(key))) { return(false); } } return(true); }