diff Implab/Automaton/DFADefinition.cs @ 162:0526412bbb26 ref20160224

DFA refactoring
author cin
date Wed, 24 Feb 2016 08:39:53 +0300
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Automaton/DFADefinition.cs	Wed Feb 24 08:39:53 2016 +0300
@@ -0,0 +1,213 @@
+using Implab;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Implab.Automaton {
+    public class DFADefinition<TInput, TState, TTag> : IDFADefinitionBuilder<TTag>, IDFADefinition<TInput, TState, TTag> {
+        DFAStateDescriptior<TTag>[] m_dfaTable;
+        readonly IAlphabet<TInput> m_inputAlphabet;
+        readonly IAlphabet<TState> m_stateAlphabet;
+
+        readonly Dictionary<int, TTag[]> m_finalStates = new Dictionary<int, TTag[]>();
+        readonly HashSet<AutomatonTransition> m_transitions = new HashSet<AutomatonTransition>();
+
+        public DFADefinition(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) {
+            Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet");
+            Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet");
+
+            m_inputAlphabet = inputAlphabet;
+            m_stateAlphabet = stateAlphabet;
+        }
+
+        public void DefineTransition(int s1, int s2, int symbol) {
+            Safe.ArgumentInRange(s1, 0, m_stateAlphabet.Count-1, "s1");
+            Safe.ArgumentInRange(s2, 0, m_stateAlphabet.Count-1, "s2");
+            Safe.ArgumentInRange(symbol, 0, m_inputAlphabet.Count-1, "symbol");
+
+            m_transitions.Add(new AutomatonTransition(s1, s2, symbol));
+        }
+
+
+        #region IDFADefinition implementation
+
+        public DFAStateDescriptior<TTag>[] GetTransitionTable() {
+            if (m_dfaTable == null) {
+                m_dfaTable = new DFAStateDescriptior<TTag>[m_stateAlphabet.Count];
+
+                foreach (var pair in m_finalStates) {
+                    var idx = pair.Key;
+
+                    m_dfaTable[idx].final = true;
+                    m_dfaTable[idx].tag = m_dfaTable[idx].tag != null ?
+                        m_dfaTable[idx].tag.Concat(pair.Value).Distinct().ToArray() :
+                        pair.Value;
+                }
+
+                foreach (var t in m_transitions) {
+                    if (m_dfaTable[t.s1].transitions == null) {
+                        m_dfaTable[t.s1].transitions = new int[m_inputAlphabet.Count];
+                        for (int i = 0; i < m_dfaTable[t.s1].transitions.Length; i++)
+                            m_dfaTable[t.s1].transitions[i] = DFAConst.UNREACHABLE_STATE;
+                    }
+
+                    m_dfaTable[t.s1].transitions[t.edge] = t.s2;
+                }
+            }
+            return m_dfaTable;
+        }
+
+        public IAlphabet<TInput> InputAlphabet {
+            get {
+                return m_inputAlphabet;
+            }
+        }
+
+        public IAlphabet<TState> StateAlphabet {
+            get {
+                return m_stateAlphabet;
+            }
+        }
+
+        #endregion
+
+        #region IDFADefinitionBuilder
+
+        public void DefineTransition(int s1, int s2, int symbol) {
+            Safe.ArgumentInRange(s1, 0, m_stateAlphabet.Count - 1, "s1");
+            Safe.ArgumentInRange(s2, 0, m_stateAlphabet.Count - 1, "s2");
+            Safe.ArgumentInRange(symbol, 0, m_inputAlphabet.Count - 1, "symbol");
+
+            m_transitions.Add(new AutomatonTransition(s1, s2, symbol));
+        }
+
+        public void MarkFinalState(int state, params TTag[] tags) {
+            m_finalStates[state] = tags;
+        }
+
+
+        #endregion
+
+        protected void Optimize(IDFADefinitionBuilder<TTag> optimalDFA,IAlphabetBuilder<TInput> optimalInputAlphabet, IAlphabetBuilder<TState> optimalStateAlphabet) {
+            Safe.ArgumentNotNull(optimalDFA, "dfa");
+            Safe.ArgumentNotNull(optimalInputAlphabet, "optimalInputAlphabet");
+            Safe.ArgumentNotNull(optimalStateAlphabet, "optimalStateAlphabet");
+
+            var setComparer = new CustomEqualityComparer<HashSet<int>>(
+                (x, y) => x.SetEquals(y),
+                s => s.Sum(x => x.GetHashCode())
+            );
+
+            var arrayComparer = new CustomEqualityComparer<TTag[]>(
+                (x,y) => (new HashSet<int>(x)).SetEquals(new HashSet<int>(y)),
+                a => a.Sum(x => x.GetHashCode())
+            );
+
+            var optimalStates = new HashSet<HashSet<int>>(setComparer);
+            var queue = new HashSet<HashSet<int>>(setComparer);
+
+            // получаем конечные состояния, сгруппированные по маркерам
+            optimalStates.UnionWith(
+                m_finalStates
+                .GroupBy(pair => pair.Value, arrayComparer)
+                .Select(
+                    g => new HashSet<int>(
+                        g.Select( pair => pair.Key)
+                    )
+                )
+            );
+
+            var state = new HashSet<int>(
+                Enumerable
+                .Range(0, m_stateAlphabet.Count - 1)
+                .Where(i => !m_finalStates.ContainsKey(i))
+            );
+            optimalStates.Add(state);
+            queue.Add(state);
+
+            var rmap = m_transitions
+                .GroupBy(t => t.s2)
+                .ToLookup(
+                    g => g.Key, // s2
+                    g => g.ToLookup(t => t.edge, t => t.s1)
+                );
+
+            while (queue.Count > 0) {
+                var stateA = queue.First();
+                queue.Remove(stateA);
+
+                for (int c = 0; c < m_inputAlphabet.Count; c++) {
+                    var stateX = new HashSet<int>();
+                        foreach(var a in stateA)
+                            stateX.UnionWith(rmap[a][c]); // all states from wich 'c' leads to 'a'
+
+                    foreach (var stateY in optimalStates.ToArray()) {
+                        if (stateX.Overlaps(stateY) && !stateY.IsSubsetOf(stateX)) {
+                            var stateR1 = new HashSet<int>(stateY);
+                            var stateR2 = new HashSet<int>(stateY);
+
+                            stateR1.IntersectWith(stateX);
+                            stateR2.ExceptWith(stateX);
+
+                            optimalStates.Remove(stateY);
+                            optimalStates.Add(stateR1);
+                            optimalStates.Add(stateR2);
+
+                            if (queue.Contains(stateY)) {
+                                queue.Remove(stateY);
+                                queue.Add(stateR1);
+                                queue.Add(stateR2);
+                            } else {
+                                queue.Add(stateR1.Count <= stateR2.Count ? stateR1 : stateR2);
+                            }
+                        }
+                    }
+                }
+            }
+
+            // карта получения оптимального состояния по соотвествующему ему простому состоянию
+            var statesMap = m_stateAlphabet.Reclassify(optimalStateAlphabet, optimalStates);
+
+            // получаем минимальный алфавит
+            // входные символы не различимы, если Move(s,a1) == Move(s,a2)
+            var optimalAlphabet = m_transitions
+                .GroupBy(t => Tuple.Create(statesMap[t.s1], statesMap[t.s2]), t => t.edge);
+            
+            var alphabetMap = m_inputAlphabet.Reclassify(optimalInputAlphabet, optimalAlphabet);
+
+            var optimalTags = m_finalStates
+                .GroupBy(pair => statesMap[pair.Key])
+                .ToDictionary(
+                    g => g.Key,
+                    g => g.SelectMany(pair => pair.Value).ToArray()
+                );
+
+            // построение автомата
+            foreach (var pair in optimalTags)
+                optimalDFA.MarkFinalState(pair.Key, pair.Value);
+
+            foreach (var t in m_transitions.Select(t => new AutomatonTransition(statesMap[t.s1],statesMap[t.s2],alphabetMap[t.edge])).Distinct())
+                optimalDFA.DefineTransition(t.s1, t.s2, t.edge);
+        }
+
+        public void PrintDFA() {
+            
+            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(
+                    "S{0} -{1}-> S{2}{3}",
+                    stateMap[t.s1],
+                    String.Join(",", inputMap[t.edge]),
+                    stateMap[t.s2],
+                    m_finalStates.ContainsKey(t.s2) ? "$" : ""
+                );
+
+        }
+    }
+}