/// <summary> /// Builds this inverse graph from the specified DFA /// </summary> /// <param name="dfa">A DFA</param> public DFAInverse(DFA dfa) { reachable = new List <DFAState>(); inverses = new Dictionary <DFAState, List <DFAState> >(); finals = new List <DFAState>(); // transitive closure of the first state reachable.Add(dfa.States[0]); inverses.Add(dfa.States[0], new List <DFAState>()); for (int i = 0; i != reachable.Count; i++) { DFAState current = reachable[i]; foreach (DFAState next in current.Children) { if (!reachable.Contains(next)) { reachable.Add(next); inverses.Add(next, new List <DFAState>()); } inverses[next].Add(current); } if (current.Items.Count != 0) { finals.Add(current); } } }
/// <summary> /// Creates a new state in this DFA /// </summary> /// <returns>The create state</returns> public DFAState CreateState() { DFAState state = new DFAState(states.Count); states.Add(state); return(state); }
/// <summary> /// Closes the specified list of states through inverse transitions /// </summary> /// <param name="states">The list of states to close</param> /// <returns>The closure</returns> public List <DFAState> CloseByAntecedents(IEnumerable <DFAState> states) { List <DFAState> result = new List <DFAState>(states); // transitive closure of the final states by their antecedents // final states are all reachable for (int i = 0; i != result.Count; i++) { DFAState state = result[i]; if (!inverses.ContainsKey(state)) { continue; } foreach (DFAState antecedent in inverses[state]) { if (!result.Contains(antecedent) && reachable.Contains(antecedent)) { // this antecedent is reachable and not yet in the closure // => add it to the closure result.Add(antecedent); } } } return(result); }
/// <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> /// Initializes this dfa as equivalent to the given nfa /// </summary> /// <param name="nfa">A nfa</param> public DFA(NFA nfa) { states = new List <DFAState>(); List <NFAStateSet> nfaStateSets = new List <NFAStateSet>(); // Create the first NFA set, add the entry and close it NFAStateSet nfaInit = new NFAStateSet(); nfaStateSets.Add(nfaInit); nfaInit.Add(nfa.StateEntry); nfaInit.Close(); // Create the initial state for the DFA DFAState dfaInit = new DFAState(0); states.Add(dfaInit); // For each set in the list of the NFA states for (int i = 0; i != nfaStateSets.Count; i++) { // Normalize transitions nfaStateSets[i].Normalize(); // Get the transitions for the set Dictionary <CharSpan, NFAStateSet> transitions = nfaStateSets[i].GetTransitions(); // For each transition foreach (CharSpan value in transitions.Keys) { // The child by the transition NFAStateSet next = transitions[value]; // Search for the child in the existing sets bool found = false; for (int j = 0; j != nfaStateSets.Count; j++) { // An existing equivalent set is already present if (nfaStateSets[j].Equals(next)) { states[i].AddTransition(value, states[j]); found = true; break; } } // The child is not already present if (!found) { // Add to the sets list nfaStateSets.Add(next); // Create the corresponding DFA state DFAState newState = new DFAState(states.Count); states.Add(newState); // Setup transition states[i].AddTransition(value, newState); } } // Add finals states[i].AddItems(nfaStateSets[i].GetFinals()); } }
private int GetDFAStates_GetGroupIndexOf(DFAState state) { for (int i = 0; i != groups.Count; i++) { if (groups[i].Contains(state)) { return(i); } } return(-1); }
/// <summary> /// Gets the group of the given state in this partition /// </summary> /// <param name="state">A state</param> /// <returns>The corresponding group</returns> private DFAStateGroup AddState_GetGroupOf(DFAState state) { foreach (DFAStateGroup group in groups) { if (group.Contains(state)) { return(group); } } return(null); }
/// <summary> /// Determines if the two states have the same marks /// </summary> /// <param name="left">The left state</param> /// <param name="right">The right state</param> /// <returns>True if the two states have the same marks</returns> private bool DFAPartition_SameFinals(DFAState left, DFAState right) { if (left.Items.Count != right.Items.Count) { return(false); } foreach (FinalItem Final in left.Items) { if (!right.Items.Contains(Final)) { return(false); } } return(true); }
/// <summary> /// Extracts the sub-DFA that leads to the specified state /// </summary> /// <param name="state">A state in this DFA</param> /// <returns>The sub-DFA for the specified state</returns> public DFA ExtractSubTo(DFAState state) { if (state == null) { throw new System.ArgumentException("The specified state must not be null"); } if (!states.Contains(state)) { throw new System.ArgumentException("The specified state is not in this DFA"); } List <DFAState> targets = new List <DFAState>(1); targets.Add(state); return(ExtractSubTo(targets)); }
/// <summary> /// Gets the new dfa states produced by this partition /// </summary> /// <returns>The dfa states produced by this partition</returns> public List <DFAState> GetDFAStates() { // For each group in the partition foreach (DFAStateGroup group in groups) { bool found = false; foreach (DFAState state in group.States) { if (state.ID == 0) { groups.Remove(group); groups.Insert(0, group); found = true; break; } } if (found) { break; } } List <DFAState> states = new List <DFAState>(); // For each group in the partition // Create the coresponding state and add the finals foreach (DFAStateGroup group in groups) { // Create a new state DFAState newState = new DFAState(states.Count); // Add the terminal from the group to the new state newState.AddItems(group.Representative.Items); states.Add(newState); } // Do linkage for (int i = 0; i != groups.Count; i++) { foreach (CharSpan Key in groups[i].Representative.Transitions) { states[i].AddTransition(Key, states[GetDFAStates_GetGroupIndexOf(groups[i].Representative.GetChildBy(Key))]); } } return(states); }
/// <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> /// Adds a state to this partition, coming from the given old partition /// </summary> /// <param name="state">The state to add</param> /// <param name="old">The old partition</param> public void AddState(DFAState state, DFAPartition old) { bool added = false; // For each group in the resulting groups set foreach (DFAStateGroup group in groups) { // If the current state can be in this resulting group according to the old partition : if (AddState_SameGroup(group.Representative, state, old)) { // Add the state to the group group.AddState(state); added = true; } } // The state cannot be in any groups : create a new group if (!added) { groups.Add(new DFAStateGroup(state)); } }
/// <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); }
/// <summary> /// Adds a transition from this state /// </summary> /// <param name="value">The value on the transition</param> /// <param name="next">The next state by the transition</param> public void AddTransition(CharSpan value, DFAState next) { transitions.Add(value, next); }
/// <summary> /// Determines whether the given state is in this group /// </summary> /// <param name="state">A state</param> /// <returns>True of the state is in this group</returns> public bool Contains(DFAState state) { return(states.Contains(state)); }
/// <summary> /// Adds a state to this group /// </summary> /// <param name="state">The state to add</param> public void AddState(DFAState state) { states.Add(state); }
/// <summary> /// Initializes this group with a representative state /// </summary> /// <param name="init">The representative state</param> public DFAStateGroup(DFAState init) { states = new List <DFAState>(); states.Add(init); }