public static IEnumerable <string> Search(string oriWord, int maxDist, TrieDictionary dict) { LenvstnNFA nfa = LenvstnNFA.BuildNFA(oriWord, maxDist); //nfa.Show(); LenvstnDFA dfa = SubsetMachine.SubsetConstruct(nfa); //dfa.Show(); List <string> output = new List <string>(); DFSserach(dfa, dfa.start, dict.Root, output); return(output); }
/// <summary> /// Builds the Epsilon closure of states for the given NFA /// </summary> /// <param name="nfa"></param> /// <param name="states"></param> /// <returns></returns> static Set <state> EpsilonClosure(LenvstnNFA nfa, Set <state> states) { if (states.IsEmpty) { return(states); } // Push all states onto a stack Stack <state> uncheckedStack = new Stack <state>(states); // Initialize EpsilonClosure(states) to states Set <state> epsilonClosure = states; while (uncheckedStack.Count != 0) { // Pop state t, the top element, off the stack state t = uncheckedStack.Pop(); int i = 0; // For each state u with an edge from t to u labeled Epsilon foreach (input input in nfa.transTable[t]) { if (input == (char)LenvstnNFA.Constants.EpsilonAny) { state u = Array.IndexOf(nfa.transTable[t], input, i); // If u is not already in epsilonClosure, add it and push it onto stack if (!epsilonClosure.Contains(u)) { epsilonClosure.Add(u); uncheckedStack.Push(u); } } i = i + 1; } } return(epsilonClosure); }
/// <summary> /// NFA building functions, build a NFA to find all words within given levenshtein distance from given word. /// </summary> /// <param name="str">The input word</param> /// <param name="maxDist">The max levenshtein distance from input word</param> /// <returns></returns> public static LenvstnNFA BuildNFA(String str, int maxDist) { int width = str.Length + 1; int height = maxDist + 1; int size = width * height; Set <state> final = new Set <state>(); for (int i = 1; i <= height; ++i) { final.Add(i * width - 1); } LenvstnNFA nfa = new LenvstnNFA(size, 0, final); //Every state except those in right most coulmn in the matrix for (int e = 0; e < height; ++e) { for (int i = 0; i < width - 1; ++i) { //trans to right nfa.AddTrans(e * width + i, e * width + i + 1, str[i]); if (e < (height - 1)) { //trans to upper nfa.AddTrans(e * width + i, (e + 1) * width + i, (char)Constants.Any); //trans to diagonal upper nfa.AddTrans(e * width + i, (e + 1) * width + i + 1, (char)Constants.EpsilonAny); } } } //right most column for (int k = 1; k < height; ++k) { //trans to upper nfa.AddTrans(k * width - 1, (k + 1) * width - 1, (char)Constants.Any); } return(nfa); }
public static LenvstnDFA SubsetConstruct(LenvstnNFA nfa) { ResetState(); LenvstnDFA dfa = new LenvstnDFA(); // Sets of NFA states which is represented by some DFA state Set <Set <state> > markedStates = new Set <Set <state> >(); Set <Set <state> > unmarkedStates = new Set <Set <state> >(); // Gives a number to each state in the DFA Dictionary <Set <state>, state> dfaStateNum = new Dictionary <Set <state>, state>(); Set <state> nfaInitial = new Set <state>(); nfaInitial.Add(nfa.initial); // Initially, EpsilonClosure(nfa.initial) is the only state in the DFAs states // and it's unmarked. Set <state> first = EpsilonClosure(nfa, nfaInitial); unmarkedStates.Add(first); // The initial dfa state state dfaInitial = GenNewState(); dfaStateNum[first] = dfaInitial; dfa.start = dfaInitial; while (unmarkedStates.Count != 0) { // Takes out one unmarked state and posteriorly mark it. Set <state> aState = unmarkedStates.Choose(); // Removes from the unmarked set. unmarkedStates.Remove(aState); // Inserts into the marked set. markedStates.Add(aState); // If this state contains the NFA's final state, add it to the DFA's set of // final states. if (aState.Where(state => nfa.final.Contains(state)).Count() > 0) { dfa.final.Add(dfaStateNum[aState]); } IEnumerator <input> iE = nfa.inputs.GetEnumerator(); // For each input symbol the NFA knows... while (iE.MoveNext()) { // Next state Set <state> next = EpsilonClosure(nfa, nfa.Move(aState, iE.Current)); if (next.IsEmpty) { continue; } // If we haven't examined this state before, add it to the unmarkedStates, // and make up a new number for it. if (!unmarkedStates.Contains(next) && !markedStates.Contains(next)) { unmarkedStates.Add(next); dfaStateNum.Add(next, GenNewState()); } if (iE.Current != (char)LenvstnNFA.Constants.Any && iE.Current != (char)LenvstnNFA.Constants.EpsilonAny) { KeyValuePair <state, input> transition = new KeyValuePair <state, input>(dfaStateNum[aState], iE.Current); dfa.transTable[transition] = dfaStateNum[next]; } else { if (!dfa.defaultTrans.ContainsKey(dfaStateNum[aState])) { dfa.defaultTrans.Add(dfaStateNum[aState], dfaStateNum[next]); } } } } return(dfa); }