static void Main(string[] args) { Console.WriteLine("Given Regular Expression: a+bc"); EpsilonNFA thomsonNFA1 = EpsilonNFA.ThomsonsConstruction("a+bc"); Console.WriteLine(thomsonNFA1.ToString()); Console.WriteLine("-----------------------------------------------------------\n"); Console.WriteLine("Given Expression: a"); EpsilonNFA thomsonNFA2 = EpsilonNFA.ThomsonsConstruction("a"); Console.WriteLine(thomsonNFA2.ToString()); Console.WriteLine("-----------------------------------------------------------\n"); Console.WriteLine("Given Expression: A+B"); EpsilonNFA thomsonNFA3 = EpsilonNFA.ThomsonsConstruction("A+B"); Console.WriteLine(thomsonNFA3.ToString()); Console.WriteLine("-----------------------------------------------------------\n"); // Subset Construction은 오류 때문에 실행이 안됩니다 ㅠㅠ. Console.WriteLine("Subset Construction"); //DFA subsetDFA = EpsilonNFA.SubsetConstruction(thomsonNFA2); //Console.WriteLine(subsetDFA.ToString()); Console.WriteLine("-----------------------------------------------------------\n"); }
// 왼쪽NFA에 오른쪽NFA의 State추가 Transition추가해서 통합시켜 준다 private static EpsilonNFA IntegrateEpsilonNFA(EpsilonNFA l, EpsilonNFA r) { // copy l to new instance var leftCopy = new EpsilonNFA(); leftCopy.Inputs = l.Inputs; foreach (var start in l.StartState) { leftCopy.StartState.Add(start); } foreach (var final in l.FinalStates) { leftCopy.FinalStates.Add(final); } foreach (var state in l.States) { leftCopy.States.Add(state); } foreach (var trans in l.TransitionFunctions) { foreach (var val in trans.Value) { leftCopy.AddTransition(new Tuple <string, string>(trans.Key.Item1, trans.Key.Item2), val); } } // do integration foreach (var item in r.States) { leftCopy.States.Add("r" + item); } foreach (var item in r.TransitionFunctions) { var rCurrentState = item.Key.Item1; rCurrentState = "r" + rCurrentState; var rInput = item.Key.Item2; var rValues = item.Value; foreach (var rVal in rValues) { leftCopy.TransitionFunctions.Add(new Tuple <string, string>(rCurrentState, rInput), "r" + rVal); } } return(leftCopy); }
// 두 입실론 NFA를 Concat한다 static EpsilonNFA Concat(EpsilonNFA l, EpsilonNFA r) { if (null == l || l.FinalStates.Count == 0 || l.StartState.Count == 0) { return(r); } else if (null == r || r.FinalStates.Count == 0 || r.StartState.Count == 0) { return(l); } else { // concat Thomson's Construction 적용 // l에 State 추가 ㅁ -> ㅁ (->) ㅇ -> ㅇ // l의 final state 랑 r의 start state 연결 // final 재설정 var target = IntegrateEpsilonNFA(l, r); target.FinalStates.RemoveAll(s => true); // remove all foreach (var rFinal in r.FinalStates) { target.FinalStates.Add("r" + rFinal); } if (l.FinalStates.Count == 0) { return(target); } foreach (var start in r.StartState) { target.AddTransition(new Tuple <string, string>(l.FinalStates[0].ToString(), string.Empty), "r" + start); break; } return(target); } }
//e-NFA to DFA public static DFA SubsetConstruction(EpsilonNFA epsilonNFA) { HashSet <string> startState = new HashSet <string>(); List <HashSet <string> > states = new List <HashSet <string> >(); Microsoft.Collections.Extensions.MultiValueDictionary <Tuple <string, string>, string> transitionFunctions = new Microsoft.Collections.Extensions.MultiValueDictionary <Tuple <string, string>, string>(); HashSet <string> reconstructedStates = new HashSet <string>(); List <string> finalStates = new List <string>(); foreach (var item in epsilonNFA.StartState) { startState.UnionWith(epsilonNFA.closure(item)); break; } foreach (var input in epsilonNFA.Inputs) { foreach (var state in startState) { foreach (var output in epsilonNFA.TransitionFunctions[new Tuple <string, string>(state, input)]) { var newState = epsilonNFA.closure(output); if (states.Contains(newState)) // 여기서 같은것이 반복되면 무시! { continue; } states.Add(newState); string reconstructedStartState = ""; string reconstructedFinalState = ""; foreach (var item in startState) { reconstructedStartState += item; } foreach (var item in newState) { reconstructedFinalState += item; } if (reconstructedFinalState.Equals(string.Empty)) { continue; } transitionFunctions.Add(new Tuple <string, string>(reconstructedStartState, input), reconstructedFinalState); } } } // 해쉬셋을 재구성해서 스테이트로 쓰기위해 하나의 문자열로 만든다 foreach (var set in states) { var newState = ""; foreach (var str in set) { newState += str; } reconstructedStates.Add(newState); } // 원래 NFA의 finalstate를 가진 것이 곧 DFA의 finalStte foreach (var state in reconstructedStates) { foreach (var nfaFinal in epsilonNFA.FinalStates) { if (state.Contains(nfaFinal.ToString())) { finalStates.Add(state); } } } return(new DFA(reconstructedStates, epsilonNFA.Inputs, transitionFunctions, startState, finalStates)); }
public static EpsilonNFA ThomsonsConstruction(string RegularExpression) { // 톰슨이 가능한 경우 if (canKleene(RegularExpression)) { var newNFA = new EpsilonNFA(); //do kleene if (RegularExpression.StartsWith("(")) {// (RE)*인 경우 newNFA.StartState.Add("q0"); newNFA.FinalStates.Add("q3"); newNFA.States.Add("q0"); newNFA.States.Add("q3"); // can skip newNFA.AddTransition(new Tuple <string, string>("q0", string.Empty), "q3"); // can loop string innerRE = RegularExpression.Substring(1, RegularExpression.Length - 3); var innerNFA = ThomsonsConstruction(innerRE); foreach (var startState in innerNFA.StartState) { innerNFA.AddTransition(new Tuple <string, string>(innerNFA.FinalStates[0].ToString(), string.Empty), startState); break;// startstate는 하나일 것이므로 바로 break } //두개의 NFA 통합 var output = IntegrateEpsilonNFA(newNFA, innerNFA); foreach (var innerStartState in innerNFA.StartState) { output.AddTransition(new Tuple <string, string>("q0", string.Empty), "r" + innerStartState); break;// startstate는 하나일 것이므로 바로 break } output.AddTransition(new Tuple <string, string>("r" + innerNFA.FinalStates[0].ToString(), string.Empty), "q3"); return(output); } else {// a*인 경우 newNFA.StartState.Add("q0"); newNFA.FinalStates.Add("q3"); newNFA.States.Add("q0"); newNFA.States.Add("q1"); newNFA.States.Add("q2"); newNFA.States.Add("q3"); newNFA.AddTransition(new Tuple <string, string>("q0", string.Empty), "q1"); newNFA.AddTransition(new Tuple <string, string>("q0", string.Empty), "q3"); newNFA.AddTransition(new Tuple <string, string>("q1", RegularExpression), "q2"); newNFA.AddTransition(new Tuple <string, string>("q2", string.Empty), "q3"); newNFA.AddTransition(new Tuple <string, string>("q2", string.Empty), "q1"); return(newNFA); } } else if (canConcat(RegularExpression)) { //do concat // ab var left = ThomsonsConstruction(RegularExpression.Substring(0, 1)); var right = ThomsonsConstruction(RegularExpression.Substring(1)); return(Concat(left, right)); } else if (canUnion(RegularExpression)) { if (RegularExpression.Length == 3) { // a + b인 경우 var newNFA = new EpsilonNFA(); //do branch newNFA.StartState.Add("q0"); newNFA.FinalStates.Add("q5"); newNFA.States.Add("q0"); newNFA.States.Add("q1"); newNFA.States.Add("q2"); newNFA.States.Add("q3"); newNFA.States.Add("q4"); newNFA.States.Add("q5"); newNFA.AddTransition(new Tuple <string, string>("q0", string.Empty), "q1"); newNFA.AddTransition(new Tuple <string, string>("q0", string.Empty), "q2"); newNFA.AddTransition(new Tuple <string, string>("q3", string.Empty), "q5"); newNFA.AddTransition(new Tuple <string, string>("q4", string.Empty), "q5"); newNFA.AddTransition(new Tuple <string, string>("q1", RegularExpression.Substring(0, 1)), "q3"); newNFA.AddTransition(new Tuple <string, string>("q2", RegularExpression.Substring(2)), "q4"); return(newNFA); } else { // 괄호가 있는 경우 구현 못했음 } } else if (canParen(RegularExpression)) { // (RE)인 경우 => RE // do paren string noParen = RegularExpression.Substring(1, RegularExpression.Length - 2); return(ThomsonsConstruction(noParen)); } else if (RegularExpression.Length == 1 && DefaultInputs.Contains(RegularExpression)) { // 하나의 인풋인 경우 // a var newNFA = new EpsilonNFA(); newNFA.StartState.Add("q0"); newNFA.FinalStates.Add("q1"); newNFA.States.Add("q0"); newNFA.States.Add("q1"); newNFA.AddTransition(new Tuple <string, string>("q0", RegularExpression), "q1"); return(newNFA); } // 더 쪼개야 톰슨이 가능한 경우 // 제일 먼저 적용돼야되는 부분을 m으로 두고 쪼갠다 EpsilonNFA l = new EpsilonNFA(); EpsilonNFA m = new EpsilonNFA(); EpsilonNFA r = new EpsilonNFA(); if (RegularExpression.Contains("*")) { int starIndex = RegularExpression.IndexOf("*"); if (DefaultInputs.Contains(RegularExpression[starIndex - 1].ToString())) {// a* l = ThomsonsConstruction(RegularExpression.Substring(0, starIndex - 1)); m = ThomsonsConstruction(RegularExpression.Substring(starIndex - 1, 2)); r = ThomsonsConstruction(RegularExpression.Substring(starIndex + 1)); } else {// (RE)* //괄호가 있는 경우 구현하지 못했습니다 ㅠㅠ } } else if (RegularExpression.Length > 1 && hasConcatableInput(RegularExpression) != -1) {// abRE int concatIndex = hasConcatableInput(RegularExpression); l = ThomsonsConstruction((RegularExpression.Substring(0, concatIndex))); m = ThomsonsConstruction((RegularExpression.Substring(concatIndex, 2))); if (concatIndex + 2 < RegularExpression.Length - 1) { // abRE인 경우 r = ThomsonsConstruction((RegularExpression.Substring(concatIndex + 2))); } else { //ab인 경우 r = null; } // 괄호가 있는 경우는 고려하지 못했습니다 ㅠㅠ } else if (RegularExpression.Contains("+")) { int unionIndex = RegularExpression.IndexOf("+"); if (DefaultInputs.Contains(RegularExpression[unionIndex - 1].ToString()) && DefaultInputs.Contains(RegularExpression[unionIndex + 1].ToString())) {//a+b l = ThomsonsConstruction(RegularExpression.Substring(0, unionIndex - 1)); m = ThomsonsConstruction(RegularExpression.Substring(unionIndex - 1, 3)); r = ThomsonsConstruction(RegularExpression.Substring(unionIndex + 2)); } else { //괄호가 있는 경우 구현하지 못했습니다 ㅠㅠ } } // 우선 순위대로 쪼갠다 else if (RegularExpression.Contains("(") && RegularExpression.Contains(")")) { int firstIndex = RegularExpression.IndexOf("("); int lastIndex = RegularExpression.LastIndexOf(")"); if (firstIndex > 0) { l = ThomsonsConstruction(RegularExpression.Substring(0, firstIndex)); } else { l = null; } m = ThomsonsConstruction(RegularExpression.Substring(firstIndex, lastIndex - firstIndex + 1)); if (lastIndex == (RegularExpression.Length - 1)) {// RE(RE) r = null; } else { r = ThomsonsConstruction(RegularExpression.Substring(lastIndex)); } } return(Concat(Concat(l, m), r)); }