comparison Implab/Automaton/DFATable.cs @ 169:54270c2f29f2 ref20160224

DFA refactoring
author cin
date Thu, 03 Mar 2016 08:41:02 +0300
parents
children 0f70905b4652
comparison
equal deleted inserted replaced
168:8fb9c9507a26 169:54270c2f29f2
1 using Implab;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5
6 namespace Implab.Automaton {
7 public class DFATable : IDFATableBuilder {
8 DFAStateDescriptior[] m_dfaTable;
9
10 int m_stateCount;
11 int m_symbolCount;
12 int m_initialState;
13
14 readonly HashSet<int> m_finalStates = new HashSet<int>();
15 readonly HashSet<AutomatonTransition> m_transitions = new HashSet<AutomatonTransition>();
16
17 void AssertNotReadOnly() {
18 if (m_dfaTable != null)
19 throw new InvalidOperationException("The object is readonly");
20 }
21
22
23 #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
37 public bool IsFinalState(int s) {
38 Safe.ArgumentInRange(s, 0, m_stateCount, "s");
39
40 return m_dfaTable != null ? m_dfaTable[s].final : m_finalStates.Contains(s);
41 }
42
43 public IEnumerable<int> FinalStates {
44 get {
45 return m_finalStates;
46 }
47 }
48
49 public int StateCount {
50 get { return m_stateCount; }
51 }
52
53 public int AlphabetSize {
54 get { return m_symbolCount; }
55 }
56
57 public int InitialState {
58 get { return m_initialState; }
59 }
60
61 #endregion
62
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) {
81 Safe.ArgumentAssert(s >= 0, "s");
82 m_initialState = s;
83 }
84
85 public void MarkFinalState(int state) {
86 AssertNotReadOnly();
87 m_finalStates.Add(state);
88 }
89
90 public void Add(AutomatonTransition item) {
91 AssertNotReadOnly();
92 Safe.ArgumentAssert(item.s1 >= 0, "item");
93 Safe.ArgumentAssert(item.s2 >= 0, "item");
94 Safe.ArgumentAssert(item.edge >= 0, "item");
95
96 m_stateCount = Math.Max(m_stateCount, Math.Max(item.s1, item.s2) + 1);
97 m_symbolCount = Math.Max(m_symbolCount, item.edge);
98
99 m_transitions.Add(item);
100 }
101
102 public void Clear() {
103 AssertNotReadOnly();
104
105 m_stateCount = 0;
106 m_symbolCount = 0;
107 m_finalStates.Clear();
108 m_transitions.Clear();
109 }
110
111 public bool Contains(AutomatonTransition item) {
112 return m_transitions.Contains(item);
113 }
114
115 public void CopyTo(AutomatonTransition[] array, int arrayIndex) {
116 m_transitions.CopyTo(array, arrayIndex);
117 }
118
119 public bool Remove(AutomatonTransition item) {
120 AssertNotReadOnly();
121 m_transitions.Remove(item);
122 }
123
124 public int Count {
125 get {
126 return m_transitions.Count;
127 }
128 }
129
130 public bool IsReadOnly {
131 get {
132 return m_dfaTable != null;
133 }
134 }
135
136 public IEnumerator<AutomatonTransition> GetEnumerator() {
137 return m_transitions.GetEnumerator();
138 }
139
140 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
141 return GetEnumerator();
142 }
143
144 /// <summary>Формирует множества конечных состояний перед началом работы алгоритма минимизации.</summary>
145 /// <remarks>
146 /// В процессе построения минимального автомата требуется разделить множество состояний,
147 /// на два подмножества - конечные состояния и все остальные, после чего эти подмножества
148 /// будут резделены на более мелкие. Иногда требуется гарантировать различия конечных сосотяний,
149 /// для этого необходимо переопределить даннцю фукнцию, для получения множеств конечных состояний.
150 /// </remarks>
151 /// <returns>The final states.</returns>
152 protected virtual IEnumerable<HashSet<int>> GroupFinalStates() {
153 return new HashSet<int>[] { m_finalStates };
154 }
155
156 protected void Optimize<TInput, TState>(
157 IDFATableBuilder optimalDFA,
158 IAlphabet<TInput> inputAlphabet,
159 IAlphabetBuilder<TInput> optimalInputAlphabet,
160 IAlphabet<TState> stateAlphabet,
161 IAlphabetBuilder<TState> optimalStateAlphabet
162 ) {
163 Safe.ArgumentNotNull(optimalDFA, "dfa");
164 Safe.ArgumentNotNull(optimalInputAlphabet, "optimalInputAlphabet");
165 Safe.ArgumentNotNull(optimalStateAlphabet, "optimalStateAlphabet");
166 Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet");
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
174 var setComparer = new CustomEqualityComparer<HashSet<int>>(
175 (x, y) => x.SetEquals(y),
176 s => s.Sum(x => x.GetHashCode())
177 );
178
179 var optimalStates = new HashSet<HashSet<int>>(setComparer);
180 var queue = new HashSet<HashSet<int>>(setComparer);
181
182 // получаем конечные состояния, сгруппированные по маркерам
183 optimalStates.UnionWith(
184 GroupFinalStates()
185 );
186
187 var state = new HashSet<int>(
188 Enumerable
189 .Range(0, m_stateCount - 1)
190 .Where(i => !m_finalStates.Contains(i))
191 );
192
193 optimalStates.Add(state);
194 queue.Add(state);
195
196 var rmap = m_transitions
197 .GroupBy(t => t.s2)
198 .ToLookup(
199 g => g.Key, // s2
200 g => g.ToLookup(t => t.edge, t => t.s1)
201 );
202
203 while (queue.Count > 0) {
204 var stateA = queue.First();
205 queue.Remove(stateA);
206
207 for (int c = 0; c < m_symbolCount; c++) {
208 var stateX = new HashSet<int>();
209 foreach(var a in stateA)
210 stateX.UnionWith(rmap[a][c]); // all states from wich 'c' leads to 'a'
211
212 foreach (var stateY in optimalStates.ToArray()) {
213 if (stateX.Overlaps(stateY) && !stateY.IsSubsetOf(stateX)) {
214 var stateR1 = new HashSet<int>(stateY);
215 var stateR2 = new HashSet<int>(stateY);
216
217 stateR1.IntersectWith(stateX);
218 stateR2.ExceptWith(stateX);
219
220 optimalStates.Remove(stateY);
221 optimalStates.Add(stateR1);
222 optimalStates.Add(stateR2);
223
224 if (queue.Contains(stateY)) {
225 queue.Remove(stateY);
226 queue.Add(stateR1);
227 queue.Add(stateR2);
228 } else {
229 queue.Add(stateR1.Count <= stateR2.Count ? stateR1 : stateR2);
230 }
231 }
232 }
233 }
234 }
235
236 // карта получения оптимального состояния по соотвествующему ему простому состоянию
237 var statesMap = stateAlphabet.Reclassify(optimalStateAlphabet, optimalStates);
238
239 // получаем минимальный алфавит
240 // входные символы не различимы, если Move(s,a1) == Move(s,a2)
241 var optimalAlphabet = m_transitions
242 .GroupBy(t => Tuple.Create(statesMap[t.s1], statesMap[t.s2]), t => t.edge);
243
244 var alphabetMap = inputAlphabet.Reclassify(optimalInputAlphabet, optimalAlphabet);
245
246 // построение автомата
247 optimalDFA.SetInitialState(statesMap[m_initialState]);
248
249 foreach (var sf in m_finalStates.GroupBy(s => statesMap[s]))
250 optimalDFA.MarkFinalState(sf.Key);
251
252 foreach (var t in m_transitions.Select(t => new AutomatonTransition(statesMap[t.s1],statesMap[t.s2],alphabetMap[t.edge])).Distinct())
253 optimalDFA.Add(t);
254
255 }
256
257 protected void PrintDFA<TInput, TState>(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) {
258 Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet");
259 Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet");
260
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)
269 Console.WriteLine(
270 "[{0}] -{{{1}}}-> [{2}]{3}",
271 stateMap[t.s1],
272 String.Join(",", inputMap[t.edge]),
273 stateMap[t.s2],
274 m_finalStates.Contains(t.s2) ? "$" : ""
275 );
276
277 }
278
279 }
280 }