Mercurial > pub > ImplabNet
comparison Implab/Automaton/DFADefinition.cs @ 162:0526412bbb26 ref20160224
DFA refactoring
| author | cin |
|---|---|
| date | Wed, 24 Feb 2016 08:39:53 +0300 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 161:2a8466f0cb8a | 162:0526412bbb26 |
|---|---|
| 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 } |
