Mercurial > pub > ImplabNet
diff 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 |
line wrap: on
line diff
--- a/Implab/Automaton/DFATable.cs Fri Mar 04 01:56:31 2016 +0300 +++ b/Implab/Automaton/DFATable.cs Thu Mar 10 01:19:33 2016 +0300 @@ -5,8 +5,6 @@ namespace Implab.Automaton { public class DFATable : IDFATableBuilder { - DFAStateDescriptior[] m_dfaTable; - int m_stateCount; int m_symbolCount; int m_initialState; @@ -14,30 +12,13 @@ readonly HashSet<int> m_finalStates = new HashSet<int>(); readonly HashSet<AutomatonTransition> m_transitions = new HashSet<AutomatonTransition>(); - void AssertNotReadOnly() { - if (m_dfaTable != null) - throw new InvalidOperationException("The object is readonly"); - } - #region IDFADefinition implementation - public DFAStateDescriptior[] GetTransitionTable() { - if (m_dfaTable == null) { - if (m_stateCount <= 0) - throw new InvalidOperationException("Invalid automaton definition: states count = {0}", m_stateCount); - if (m_symbolCount <= 0) - throw new InvalidOperationException("Invalid automaton definition: symbols count = {0}", m_symbolCount); - - m_dfaTable = ConstructTransitionTable(); - } - return m_dfaTable; - } - public bool IsFinalState(int s) { Safe.ArgumentInRange(s, 0, m_stateCount, "s"); - return m_dfaTable != null ? m_dfaTable[s].final : m_finalStates.Contains(s); + return m_finalStates.Contains(s); } public IEnumerable<int> FinalStates { @@ -60,35 +41,16 @@ #endregion - protected virtual DFAStateDescriptior[] ConstructTransitionTable() { - var dfaTable = new DFAStateDescriptior[m_stateCount]; - - - foreach (var t in m_transitions) { - if (dfaTable[t.s1].transitions == null) - dfaTable[t.s1] = new DFAStateDescriptior(m_symbolCount, m_finalStates.Contains(t.s1)); - - dfaTable[t.s1].transitions[t.edge] = t.s2; - } - - foreach (var s in m_finalStates) - if (!dfaTable[s].final) - m_dfaTable[s] = new DFAStateDescriptior(m_symbolCount, true); - - } - public void SetInitialState(int s) { Safe.ArgumentAssert(s >= 0, "s"); m_initialState = s; } public void MarkFinalState(int state) { - AssertNotReadOnly(); m_finalStates.Add(state); } public void Add(AutomatonTransition item) { - AssertNotReadOnly(); Safe.ArgumentAssert(item.s1 >= 0, "item"); Safe.ArgumentAssert(item.s2 >= 0, "item"); Safe.ArgumentAssert(item.edge >= 0, "item"); @@ -100,8 +62,6 @@ } public void Clear() { - AssertNotReadOnly(); - m_stateCount = 0; m_symbolCount = 0; m_finalStates.Clear(); @@ -117,7 +77,6 @@ } public bool Remove(AutomatonTransition item) { - AssertNotReadOnly(); m_transitions.Remove(item); } @@ -129,7 +88,7 @@ public bool IsReadOnly { get { - return m_dfaTable != null; + return false; } } @@ -153,23 +112,15 @@ return new HashSet<int>[] { m_finalStates }; } - protected void Optimize<TInput, TState>( + protected void Optimize( IDFATableBuilder optimalDFA, - IAlphabet<TInput> inputAlphabet, - IAlphabetBuilder<TInput> optimalInputAlphabet, - IAlphabet<TState> stateAlphabet, - IAlphabetBuilder<TState> optimalStateAlphabet + IDictionary<int,int> alphabetMap, + IDictionary<int,int> stateMap ) { Safe.ArgumentNotNull(optimalDFA, "dfa"); - Safe.ArgumentNotNull(optimalInputAlphabet, "optimalInputAlphabet"); - Safe.ArgumentNotNull(optimalStateAlphabet, "optimalStateAlphabet"); - Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet"); - Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet"); + Safe.ArgumentNotNull(alphabetMap, "alphabetMap"); + Safe.ArgumentNotNull(stateMap, "stateMap"); - if (inputAlphabet.Count != m_symbolCount) - throw new InvalidOperationException("The input symbols aphabet mismatch"); - if (stateAlphabet.Count != m_stateCount) - throw new InvalidOperationException("The states alphabet mismatch"); var setComparer = new CustomEqualityComparer<HashSet<int>>( (x, y) => x.SetEquals(y), @@ -234,46 +185,106 @@ } // карта получения оптимального состояния по соотвествующему ему простому состоянию - var statesMap = stateAlphabet.Reclassify(optimalStateAlphabet, optimalStates); + var nextState = 0; + foreach (var item in optimalStates) { + var id = nextState++; + foreach (var s in item) + stateMap[s] = id; + } // получаем минимальный алфавит - // входные символы не различимы, если Move(s,a1) == Move(s,a2) - var optimalAlphabet = m_transitions - .GroupBy(t => Tuple.Create(statesMap[t.s1], statesMap[t.s2]), t => t.edge); + // входные символы не различимы, если Move(s,a1) == Move(s,a2), для любого s + // для этого используем алгоритм кластеризации, сначала + // считаем, что все символы не различимы + + var minClasses = new HashSet<HashSet<int>>(setComparer); + var alphaQueue = new Queue<HashSet<int>>(); + alphaQueue.Enqueue(new HashSet<int>(Enumerable.Range(0,AlphabetSize))); + + // для всех состояний, будем проверять каждый класс на различимость, + // т.е. символы различимы, если они приводят к разным состояниям + for (int s = 0 ; s < optimalStates.Count; s++) { + var newQueue = new Queue<HashSet<int>>(); + + foreach (var A in alphaQueue) { + // классы из одного символа делить бесполезно, переводим их сразу в + // результирующий алфавит + if (A.Count == 1) { + minClasses.Add(A); + continue; + } + + // различаем классы символов, которые переводят в различные оптимальные состояния + // optimalState -> alphaClass + var classes = new Dictionary<int, HashSet<int>>(); + + foreach (var term in A) { + // ищем все переходы класса по символу term + var res = m_transitions.Where(t => stateMap[t.s1] == s && t.edge == term).Select(t => stateMap[t.s2]).ToArray(); - var alphabetMap = inputAlphabet.Reclassify(optimalInputAlphabet, optimalAlphabet); + var s2 = res.Length > 0 ? res[0] : -1; + + HashSet<int> a2; + if (!classes.TryGetValue(s2, out a2)) { + a2 = new HashSet<int>(); + newQueue.Enqueue(a2); + classes[s2] = a2; + } + a2.Add(term); + } + } + + if (newQueue.Count == 0) + break; + alphaQueue = newQueue; + } + + // после окончания работы алгоритма в очереди останутся минимальные различимые классы + // входных символов + foreach (var A in alphaQueue) + minClasses.Add(A); + + // построение отображения алфавитов входных символов. + // поскольку символ DFAConst.UNCLASSIFIED_INPUT может иметь + // специальное значение, тогда сохраним минимальный класс, + // содержащий этот символ на томже месте. + + var nextCls = 0; + foreach (var item in minClasses) { + if (nextCls == DFAConst.UNCLASSIFIED_INPUT) + nextCls++; + + // сохраняем DFAConst.UNCLASSIFIED_INPUT + var cls = item.Contains(DFAConst.UNCLASSIFIED_INPUT) ? DFAConst.UNCLASSIFIED_INPUT : nextCls; + + foreach (var a in item) + alphabetMap[a] = cls; + + nextCls++; + } // построение автомата - optimalDFA.SetInitialState(statesMap[m_initialState]); + optimalDFA.SetInitialState(stateMap[m_initialState]); - foreach (var sf in m_finalStates.GroupBy(s => statesMap[s])) - optimalDFA.MarkFinalState(sf.Key); + foreach (var sf in m_finalStates.Select(s => stateMap[s]).Distinct()) + optimalDFA.MarkFinalState(sf); - foreach (var t in m_transitions.Select(t => new AutomatonTransition(statesMap[t.s1],statesMap[t.s2],alphabetMap[t.edge])).Distinct()) + foreach (var t in m_transitions.Select(t => new AutomatonTransition(stateMap[t.s1],stateMap[t.s2],alphabetMap[t.edge])).Distinct()) optimalDFA.Add(t); - } protected void PrintDFA<TInput, TState>(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) { Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet"); Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet"); - var inputMap = inputAlphabet.CreateReverseMap(); - var stateMap = stateAlphabet.CreateReverseMap(); - - for (int i = 0; i < inputMap.Length; i++) - Console.WriteLine("C{0}: {1}", i, String.Join(",", inputMap[i])); - - foreach(var t in m_transitions) Console.WriteLine( "[{0}] -{{{1}}}-> [{2}]{3}", - stateMap[t.s1], - String.Join(",", inputMap[t.edge]), - stateMap[t.s2], + String.Join(",", stateAlphabet.GetSymbols(t.s1)), + String.Join("", inputAlphabet.GetSymbols(t.edge)), + String.Join(",", stateAlphabet.GetSymbols(t.s2)), m_finalStates.Contains(t.s2) ? "$" : "" ); - } }