| 162 | 1 using Implab; | 
|  | 2 using System; | 
|  | 3 using System.Collections.Generic; | 
|  | 4 using System.Linq; | 
|  | 5 | 
|  | 6 namespace Implab.Automaton { | 
|  | 7     public class DFADefinition<TInput, TState, TTag> : IDFADefinitionBuilder<TTag>, IDFADefinition<TInput, TState, TTag> { | 
|  | 8         DFAStateDescriptior<TTag>[] m_dfaTable; | 
|  | 9         readonly IAlphabet<TInput> m_inputAlphabet; | 
|  | 10         readonly IAlphabet<TState> m_stateAlphabet; | 
|  | 11 | 
|  | 12         readonly Dictionary<int, TTag[]> m_finalStates = new Dictionary<int, TTag[]>(); | 
|  | 13         readonly HashSet<AutomatonTransition> m_transitions = new HashSet<AutomatonTransition>(); | 
|  | 14 | 
|  | 15         public DFADefinition(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) { | 
|  | 16             Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet"); | 
|  | 17             Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet"); | 
|  | 18 | 
|  | 19             m_inputAlphabet = inputAlphabet; | 
|  | 20             m_stateAlphabet = stateAlphabet; | 
|  | 21         } | 
|  | 22 | 
|  | 23         public void DefineTransition(int s1, int s2, int symbol) { | 
|  | 24             Safe.ArgumentInRange(s1, 0, m_stateAlphabet.Count-1, "s1"); | 
|  | 25             Safe.ArgumentInRange(s2, 0, m_stateAlphabet.Count-1, "s2"); | 
|  | 26             Safe.ArgumentInRange(symbol, 0, m_inputAlphabet.Count-1, "symbol"); | 
|  | 27 | 
|  | 28             m_transitions.Add(new AutomatonTransition(s1, s2, symbol)); | 
|  | 29         } | 
|  | 30 | 
|  | 31 | 
|  | 32         #region IDFADefinition implementation | 
|  | 33 | 
|  | 34         public DFAStateDescriptior<TTag>[] GetTransitionTable() { | 
|  | 35             if (m_dfaTable == null) { | 
|  | 36                 m_dfaTable = new DFAStateDescriptior<TTag>[m_stateAlphabet.Count]; | 
|  | 37 | 
|  | 38                 foreach (var pair in m_finalStates) { | 
|  | 39                     var idx = pair.Key; | 
|  | 40 | 
|  | 41                     m_dfaTable[idx].final = true; | 
|  | 42                     m_dfaTable[idx].tag = m_dfaTable[idx].tag != null ? | 
|  | 43                         m_dfaTable[idx].tag.Concat(pair.Value).Distinct().ToArray() : | 
|  | 44                         pair.Value; | 
|  | 45                 } | 
|  | 46 | 
|  | 47                 foreach (var t in m_transitions) { | 
|  | 48                     if (m_dfaTable[t.s1].transitions == null) { | 
|  | 49                         m_dfaTable[t.s1].transitions = new int[m_inputAlphabet.Count]; | 
|  | 50                         for (int i = 0; i < m_dfaTable[t.s1].transitions.Length; i++) | 
|  | 51                             m_dfaTable[t.s1].transitions[i] = DFAConst.UNREACHABLE_STATE; | 
|  | 52                     } | 
|  | 53 | 
|  | 54                     m_dfaTable[t.s1].transitions[t.edge] = t.s2; | 
|  | 55                 } | 
|  | 56             } | 
|  | 57             return m_dfaTable; | 
|  | 58         } | 
|  | 59 | 
|  | 60         public IAlphabet<TInput> InputAlphabet { | 
|  | 61             get { | 
|  | 62                 return m_inputAlphabet; | 
|  | 63             } | 
|  | 64         } | 
|  | 65 | 
|  | 66         public IAlphabet<TState> StateAlphabet { | 
|  | 67             get { | 
|  | 68                 return m_stateAlphabet; | 
|  | 69             } | 
|  | 70         } | 
|  | 71 | 
|  | 72         #endregion | 
|  | 73 | 
|  | 74         #region IDFADefinitionBuilder | 
|  | 75 | 
|  | 76         public void DefineTransition(int s1, int s2, int symbol) { | 
|  | 77             Safe.ArgumentInRange(s1, 0, m_stateAlphabet.Count - 1, "s1"); | 
|  | 78             Safe.ArgumentInRange(s2, 0, m_stateAlphabet.Count - 1, "s2"); | 
|  | 79             Safe.ArgumentInRange(symbol, 0, m_inputAlphabet.Count - 1, "symbol"); | 
|  | 80 | 
|  | 81             m_transitions.Add(new AutomatonTransition(s1, s2, symbol)); | 
|  | 82         } | 
|  | 83 | 
|  | 84         public void MarkFinalState(int state, params TTag[] tags) { | 
|  | 85             m_finalStates[state] = tags; | 
|  | 86         } | 
|  | 87 | 
|  | 88 | 
|  | 89         #endregion | 
|  | 90 | 
|  | 91         protected void Optimize(IDFADefinitionBuilder<TTag> optimalDFA,IAlphabetBuilder<TInput> optimalInputAlphabet, IAlphabetBuilder<TState> optimalStateAlphabet) { | 
|  | 92             Safe.ArgumentNotNull(optimalDFA, "dfa"); | 
|  | 93             Safe.ArgumentNotNull(optimalInputAlphabet, "optimalInputAlphabet"); | 
|  | 94             Safe.ArgumentNotNull(optimalStateAlphabet, "optimalStateAlphabet"); | 
|  | 95 | 
|  | 96             var setComparer = new CustomEqualityComparer<HashSet<int>>( | 
|  | 97                 (x, y) => x.SetEquals(y), | 
|  | 98                 s => s.Sum(x => x.GetHashCode()) | 
|  | 99             ); | 
|  | 100 | 
|  | 101             var arrayComparer = new CustomEqualityComparer<TTag[]>( | 
|  | 102                 (x,y) => (new HashSet<int>(x)).SetEquals(new HashSet<int>(y)), | 
|  | 103                 a => a.Sum(x => x.GetHashCode()) | 
|  | 104             ); | 
|  | 105 | 
|  | 106             var optimalStates = new HashSet<HashSet<int>>(setComparer); | 
|  | 107             var queue = new HashSet<HashSet<int>>(setComparer); | 
|  | 108 | 
|  | 109             // получаем конечные состояния, сгруппированные по маркерам | 
|  | 110             optimalStates.UnionWith( | 
|  | 111                 m_finalStates | 
|  | 112                 .GroupBy(pair => pair.Value, arrayComparer) | 
|  | 113                 .Select( | 
|  | 114                     g => new HashSet<int>( | 
|  | 115                         g.Select( pair => pair.Key) | 
|  | 116                     ) | 
|  | 117                 ) | 
|  | 118             ); | 
|  | 119 | 
|  | 120             var state = new HashSet<int>( | 
|  | 121                 Enumerable | 
|  | 122                 .Range(0, m_stateAlphabet.Count - 1) | 
|  | 123                 .Where(i => !m_finalStates.ContainsKey(i)) | 
|  | 124             ); | 
|  | 125             optimalStates.Add(state); | 
|  | 126             queue.Add(state); | 
|  | 127 | 
|  | 128             var rmap = m_transitions | 
|  | 129                 .GroupBy(t => t.s2) | 
|  | 130                 .ToLookup( | 
|  | 131                     g => g.Key, // s2 | 
|  | 132                     g => g.ToLookup(t => t.edge, t => t.s1) | 
|  | 133                 ); | 
|  | 134 | 
|  | 135             while (queue.Count > 0) { | 
|  | 136                 var stateA = queue.First(); | 
|  | 137                 queue.Remove(stateA); | 
|  | 138 | 
|  | 139                 for (int c = 0; c < m_inputAlphabet.Count; c++) { | 
|  | 140                     var stateX = new HashSet<int>(); | 
|  | 141                         foreach(var a in stateA) | 
|  | 142                             stateX.UnionWith(rmap[a][c]); // all states from wich 'c' leads to 'a' | 
|  | 143 | 
|  | 144                     foreach (var stateY in optimalStates.ToArray()) { | 
|  | 145                         if (stateX.Overlaps(stateY) && !stateY.IsSubsetOf(stateX)) { | 
|  | 146                             var stateR1 = new HashSet<int>(stateY); | 
|  | 147                             var stateR2 = new HashSet<int>(stateY); | 
|  | 148 | 
|  | 149                             stateR1.IntersectWith(stateX); | 
|  | 150                             stateR2.ExceptWith(stateX); | 
|  | 151 | 
|  | 152                             optimalStates.Remove(stateY); | 
|  | 153                             optimalStates.Add(stateR1); | 
|  | 154                             optimalStates.Add(stateR2); | 
|  | 155 | 
|  | 156                             if (queue.Contains(stateY)) { | 
|  | 157                                 queue.Remove(stateY); | 
|  | 158                                 queue.Add(stateR1); | 
|  | 159                                 queue.Add(stateR2); | 
|  | 160                             } else { | 
|  | 161                                 queue.Add(stateR1.Count <= stateR2.Count ? stateR1 : stateR2); | 
|  | 162                             } | 
|  | 163                         } | 
|  | 164                     } | 
|  | 165                 } | 
|  | 166             } | 
|  | 167 | 
|  | 168             // карта получения оптимального состояния по соотвествующему ему простому состоянию | 
|  | 169             var statesMap = m_stateAlphabet.Reclassify(optimalStateAlphabet, optimalStates); | 
|  | 170 | 
|  | 171             // получаем минимальный алфавит | 
|  | 172             // входные символы не различимы, если Move(s,a1) == Move(s,a2) | 
|  | 173             var optimalAlphabet = m_transitions | 
|  | 174                 .GroupBy(t => Tuple.Create(statesMap[t.s1], statesMap[t.s2]), t => t.edge); | 
|  | 175 | 
|  | 176             var alphabetMap = m_inputAlphabet.Reclassify(optimalInputAlphabet, optimalAlphabet); | 
|  | 177 | 
|  | 178             var optimalTags = m_finalStates | 
|  | 179                 .GroupBy(pair => statesMap[pair.Key]) | 
|  | 180                 .ToDictionary( | 
|  | 181                     g => g.Key, | 
|  | 182                     g => g.SelectMany(pair => pair.Value).ToArray() | 
|  | 183                 ); | 
|  | 184 | 
|  | 185             // построение автомата | 
|  | 186             foreach (var pair in optimalTags) | 
|  | 187                 optimalDFA.MarkFinalState(pair.Key, pair.Value); | 
|  | 188 | 
|  | 189             foreach (var t in m_transitions.Select(t => new AutomatonTransition(statesMap[t.s1],statesMap[t.s2],alphabetMap[t.edge])).Distinct()) | 
|  | 190                 optimalDFA.DefineTransition(t.s1, t.s2, t.edge); | 
|  | 191         } | 
|  | 192 | 
|  | 193         public void PrintDFA() { | 
|  | 194 | 
|  | 195             var inputMap = InputAlphabet.CreateReverseMap(); | 
|  | 196             var stateMap = StateAlphabet.CreateReverseMap(); | 
|  | 197 | 
|  | 198             for (int i = 0; i < inputMap.Length; i++) { | 
|  | 199                 Console.WriteLine("C{0}: {1}", i, String.Join(",", inputMap[i])); | 
|  | 200             } | 
|  | 201 | 
|  | 202             foreach(var t in m_transitions) | 
|  | 203                 Console.WriteLine( | 
|  | 204                     "S{0} -{1}-> S{2}{3}", | 
|  | 205                     stateMap[t.s1], | 
|  | 206                     String.Join(",", inputMap[t.edge]), | 
|  | 207                     stateMap[t.s2], | 
|  | 208                     m_finalStates.ContainsKey(t.s2) ? "$" : "" | 
|  | 209                 ); | 
|  | 210 | 
|  | 211         } | 
|  | 212     } | 
|  | 213 } |