comparison Implab/Automaton/DFATable.cs @ 171:0f70905b4652 ref20160224

Working on regular DFA
author cin
date Thu, 10 Mar 2016 01:19:33 +0300
parents 54270c2f29f2
children 92d5278d1b10
comparison
equal deleted inserted replaced
170:181119ef3b39 171:0f70905b4652
3 using System.Collections.Generic; 3 using System.Collections.Generic;
4 using System.Linq; 4 using System.Linq;
5 5
6 namespace Implab.Automaton { 6 namespace Implab.Automaton {
7 public class DFATable : IDFATableBuilder { 7 public class DFATable : IDFATableBuilder {
8 DFAStateDescriptior[] m_dfaTable;
9
10 int m_stateCount; 8 int m_stateCount;
11 int m_symbolCount; 9 int m_symbolCount;
12 int m_initialState; 10 int m_initialState;
13 11
14 readonly HashSet<int> m_finalStates = new HashSet<int>(); 12 readonly HashSet<int> m_finalStates = new HashSet<int>();
15 readonly HashSet<AutomatonTransition> m_transitions = new HashSet<AutomatonTransition>(); 13 readonly HashSet<AutomatonTransition> m_transitions = new HashSet<AutomatonTransition>();
16 14
17 void AssertNotReadOnly() {
18 if (m_dfaTable != null)
19 throw new InvalidOperationException("The object is readonly");
20 }
21
22 15
23 #region IDFADefinition implementation 16 #region IDFADefinition implementation
24
25 public DFAStateDescriptior[] GetTransitionTable() {
26 if (m_dfaTable == null) {
27 if (m_stateCount <= 0)
28 throw new InvalidOperationException("Invalid automaton definition: states count = {0}", m_stateCount);
29 if (m_symbolCount <= 0)
30 throw new InvalidOperationException("Invalid automaton definition: symbols count = {0}", m_symbolCount);
31
32 m_dfaTable = ConstructTransitionTable();
33 }
34 return m_dfaTable;
35 }
36 17
37 public bool IsFinalState(int s) { 18 public bool IsFinalState(int s) {
38 Safe.ArgumentInRange(s, 0, m_stateCount, "s"); 19 Safe.ArgumentInRange(s, 0, m_stateCount, "s");
39 20
40 return m_dfaTable != null ? m_dfaTable[s].final : m_finalStates.Contains(s); 21 return m_finalStates.Contains(s);
41 } 22 }
42 23
43 public IEnumerable<int> FinalStates { 24 public IEnumerable<int> FinalStates {
44 get { 25 get {
45 return m_finalStates; 26 return m_finalStates;
58 get { return m_initialState; } 39 get { return m_initialState; }
59 } 40 }
60 41
61 #endregion 42 #endregion
62 43
63 protected virtual DFAStateDescriptior[] ConstructTransitionTable() {
64 var dfaTable = new DFAStateDescriptior[m_stateCount];
65
66
67 foreach (var t in m_transitions) {
68 if (dfaTable[t.s1].transitions == null)
69 dfaTable[t.s1] = new DFAStateDescriptior(m_symbolCount, m_finalStates.Contains(t.s1));
70
71 dfaTable[t.s1].transitions[t.edge] = t.s2;
72 }
73
74 foreach (var s in m_finalStates)
75 if (!dfaTable[s].final)
76 m_dfaTable[s] = new DFAStateDescriptior(m_symbolCount, true);
77
78 }
79
80 public void SetInitialState(int s) { 44 public void SetInitialState(int s) {
81 Safe.ArgumentAssert(s >= 0, "s"); 45 Safe.ArgumentAssert(s >= 0, "s");
82 m_initialState = s; 46 m_initialState = s;
83 } 47 }
84 48
85 public void MarkFinalState(int state) { 49 public void MarkFinalState(int state) {
86 AssertNotReadOnly();
87 m_finalStates.Add(state); 50 m_finalStates.Add(state);
88 } 51 }
89 52
90 public void Add(AutomatonTransition item) { 53 public void Add(AutomatonTransition item) {
91 AssertNotReadOnly();
92 Safe.ArgumentAssert(item.s1 >= 0, "item"); 54 Safe.ArgumentAssert(item.s1 >= 0, "item");
93 Safe.ArgumentAssert(item.s2 >= 0, "item"); 55 Safe.ArgumentAssert(item.s2 >= 0, "item");
94 Safe.ArgumentAssert(item.edge >= 0, "item"); 56 Safe.ArgumentAssert(item.edge >= 0, "item");
95 57
96 m_stateCount = Math.Max(m_stateCount, Math.Max(item.s1, item.s2) + 1); 58 m_stateCount = Math.Max(m_stateCount, Math.Max(item.s1, item.s2) + 1);
98 60
99 m_transitions.Add(item); 61 m_transitions.Add(item);
100 } 62 }
101 63
102 public void Clear() { 64 public void Clear() {
103 AssertNotReadOnly();
104
105 m_stateCount = 0; 65 m_stateCount = 0;
106 m_symbolCount = 0; 66 m_symbolCount = 0;
107 m_finalStates.Clear(); 67 m_finalStates.Clear();
108 m_transitions.Clear(); 68 m_transitions.Clear();
109 } 69 }
115 public void CopyTo(AutomatonTransition[] array, int arrayIndex) { 75 public void CopyTo(AutomatonTransition[] array, int arrayIndex) {
116 m_transitions.CopyTo(array, arrayIndex); 76 m_transitions.CopyTo(array, arrayIndex);
117 } 77 }
118 78
119 public bool Remove(AutomatonTransition item) { 79 public bool Remove(AutomatonTransition item) {
120 AssertNotReadOnly();
121 m_transitions.Remove(item); 80 m_transitions.Remove(item);
122 } 81 }
123 82
124 public int Count { 83 public int Count {
125 get { 84 get {
127 } 86 }
128 } 87 }
129 88
130 public bool IsReadOnly { 89 public bool IsReadOnly {
131 get { 90 get {
132 return m_dfaTable != null; 91 return false;
133 } 92 }
134 } 93 }
135 94
136 public IEnumerator<AutomatonTransition> GetEnumerator() { 95 public IEnumerator<AutomatonTransition> GetEnumerator() {
137 return m_transitions.GetEnumerator(); 96 return m_transitions.GetEnumerator();
151 /// <returns>The final states.</returns> 110 /// <returns>The final states.</returns>
152 protected virtual IEnumerable<HashSet<int>> GroupFinalStates() { 111 protected virtual IEnumerable<HashSet<int>> GroupFinalStates() {
153 return new HashSet<int>[] { m_finalStates }; 112 return new HashSet<int>[] { m_finalStates };
154 } 113 }
155 114
156 protected void Optimize<TInput, TState>( 115 protected void Optimize(
157 IDFATableBuilder optimalDFA, 116 IDFATableBuilder optimalDFA,
158 IAlphabet<TInput> inputAlphabet, 117 IDictionary<int,int> alphabetMap,
159 IAlphabetBuilder<TInput> optimalInputAlphabet, 118 IDictionary<int,int> stateMap
160 IAlphabet<TState> stateAlphabet,
161 IAlphabetBuilder<TState> optimalStateAlphabet
162 ) { 119 ) {
163 Safe.ArgumentNotNull(optimalDFA, "dfa"); 120 Safe.ArgumentNotNull(optimalDFA, "dfa");
164 Safe.ArgumentNotNull(optimalInputAlphabet, "optimalInputAlphabet"); 121 Safe.ArgumentNotNull(alphabetMap, "alphabetMap");
165 Safe.ArgumentNotNull(optimalStateAlphabet, "optimalStateAlphabet"); 122 Safe.ArgumentNotNull(stateMap, "stateMap");
166 Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet"); 123
167 Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet");
168
169 if (inputAlphabet.Count != m_symbolCount)
170 throw new InvalidOperationException("The input symbols aphabet mismatch");
171 if (stateAlphabet.Count != m_stateCount)
172 throw new InvalidOperationException("The states alphabet mismatch");
173 124
174 var setComparer = new CustomEqualityComparer<HashSet<int>>( 125 var setComparer = new CustomEqualityComparer<HashSet<int>>(
175 (x, y) => x.SetEquals(y), 126 (x, y) => x.SetEquals(y),
176 s => s.Sum(x => x.GetHashCode()) 127 s => s.Sum(x => x.GetHashCode())
177 ); 128 );
232 } 183 }
233 } 184 }
234 } 185 }
235 186
236 // карта получения оптимального состояния по соотвествующему ему простому состоянию 187 // карта получения оптимального состояния по соотвествующему ему простому состоянию
237 var statesMap = stateAlphabet.Reclassify(optimalStateAlphabet, optimalStates); 188 var nextState = 0;
189 foreach (var item in optimalStates) {
190 var id = nextState++;
191 foreach (var s in item)
192 stateMap[s] = id;
193 }
238 194
239 // получаем минимальный алфавит 195 // получаем минимальный алфавит
240 // входные символы не различимы, если Move(s,a1) == Move(s,a2) 196 // входные символы не различимы, если Move(s,a1) == Move(s,a2), для любого s
241 var optimalAlphabet = m_transitions 197 // для этого используем алгоритм кластеризации, сначала
242 .GroupBy(t => Tuple.Create(statesMap[t.s1], statesMap[t.s2]), t => t.edge); 198 // считаем, что все символы не различимы
243 199
244 var alphabetMap = inputAlphabet.Reclassify(optimalInputAlphabet, optimalAlphabet); 200 var minClasses = new HashSet<HashSet<int>>(setComparer);
201 var alphaQueue = new Queue<HashSet<int>>();
202 alphaQueue.Enqueue(new HashSet<int>(Enumerable.Range(0,AlphabetSize)));
203
204 // для всех состояний, будем проверять каждый класс на различимость,
205 // т.е. символы различимы, если они приводят к разным состояниям
206 for (int s = 0 ; s < optimalStates.Count; s++) {
207 var newQueue = new Queue<HashSet<int>>();
208
209 foreach (var A in alphaQueue) {
210 // классы из одного символа делить бесполезно, переводим их сразу в
211 // результирующий алфавит
212 if (A.Count == 1) {
213 minClasses.Add(A);
214 continue;
215 }
216
217 // различаем классы символов, которые переводят в различные оптимальные состояния
218 // optimalState -> alphaClass
219 var classes = new Dictionary<int, HashSet<int>>();
220
221 foreach (var term in A) {
222 // ищем все переходы класса по символу term
223 var res = m_transitions.Where(t => stateMap[t.s1] == s && t.edge == term).Select(t => stateMap[t.s2]).ToArray();
224
225 var s2 = res.Length > 0 ? res[0] : -1;
226
227 HashSet<int> a2;
228 if (!classes.TryGetValue(s2, out a2)) {
229 a2 = new HashSet<int>();
230 newQueue.Enqueue(a2);
231 classes[s2] = a2;
232 }
233 a2.Add(term);
234 }
235 }
236
237 if (newQueue.Count == 0)
238 break;
239 alphaQueue = newQueue;
240 }
241
242 // после окончания работы алгоритма в очереди останутся минимальные различимые классы
243 // входных символов
244 foreach (var A in alphaQueue)
245 minClasses.Add(A);
246
247 // построение отображения алфавитов входных символов.
248 // поскольку символ DFAConst.UNCLASSIFIED_INPUT может иметь
249 // специальное значение, тогда сохраним минимальный класс,
250 // содержащий этот символ на томже месте.
251
252 var nextCls = 0;
253 foreach (var item in minClasses) {
254 if (nextCls == DFAConst.UNCLASSIFIED_INPUT)
255 nextCls++;
256
257 // сохраняем DFAConst.UNCLASSIFIED_INPUT
258 var cls = item.Contains(DFAConst.UNCLASSIFIED_INPUT) ? DFAConst.UNCLASSIFIED_INPUT : nextCls;
259
260 foreach (var a in item)
261 alphabetMap[a] = cls;
262
263 nextCls++;
264 }
245 265
246 // построение автомата 266 // построение автомата
247 optimalDFA.SetInitialState(statesMap[m_initialState]); 267 optimalDFA.SetInitialState(stateMap[m_initialState]);
248 268
249 foreach (var sf in m_finalStates.GroupBy(s => statesMap[s])) 269 foreach (var sf in m_finalStates.Select(s => stateMap[s]).Distinct())
250 optimalDFA.MarkFinalState(sf.Key); 270 optimalDFA.MarkFinalState(sf);
251 271
252 foreach (var t in m_transitions.Select(t => new AutomatonTransition(statesMap[t.s1],statesMap[t.s2],alphabetMap[t.edge])).Distinct()) 272 foreach (var t in m_transitions.Select(t => new AutomatonTransition(stateMap[t.s1],stateMap[t.s2],alphabetMap[t.edge])).Distinct())
253 optimalDFA.Add(t); 273 optimalDFA.Add(t);
254
255 } 274 }
256 275
257 protected void PrintDFA<TInput, TState>(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) { 276 protected void PrintDFA<TInput, TState>(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) {
258 Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet"); 277 Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet");
259 Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet"); 278 Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet");
260 279
261 var inputMap = inputAlphabet.CreateReverseMap();
262 var stateMap = stateAlphabet.CreateReverseMap();
263
264 for (int i = 0; i < inputMap.Length; i++)
265 Console.WriteLine("C{0}: {1}", i, String.Join(",", inputMap[i]));
266
267
268 foreach(var t in m_transitions) 280 foreach(var t in m_transitions)
269 Console.WriteLine( 281 Console.WriteLine(
270 "[{0}] -{{{1}}}-> [{2}]{3}", 282 "[{0}] -{{{1}}}-> [{2}]{3}",
271 stateMap[t.s1], 283 String.Join(",", stateAlphabet.GetSymbols(t.s1)),
272 String.Join(",", inputMap[t.edge]), 284 String.Join("", inputAlphabet.GetSymbols(t.edge)),
273 stateMap[t.s2], 285 String.Join(",", stateAlphabet.GetSymbols(t.s2)),
274 m_finalStates.Contains(t.s2) ? "$" : "" 286 m_finalStates.Contains(t.s2) ? "$" : ""
275 ); 287 );
276
277 } 288 }
278 289
279 } 290 }
280 } 291 }