diff Implab/Automaton/DFATable.cs @ 182:76e8f2ba12b8 ref20160224

pretty print DFA, the minimization is still buggy
author cin
date Thu, 24 Mar 2016 18:52:10 +0300
parents b2b6a6640aa3
children 4f82e0f161c3
line wrap: on
line diff
--- a/Implab/Automaton/DFATable.cs	Thu Mar 24 03:54:46 2016 +0300
+++ b/Implab/Automaton/DFATable.cs	Thu Mar 24 18:52:10 2016 +0300
@@ -3,6 +3,9 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Diagnostics;
+using System.IO;
+using System.CodeDom.Compiler;
+using System.CodeDom;
 
 namespace Implab.Automaton {
     public class DFATable : IDFATableBuilder {
@@ -103,6 +106,11 @@
             return GetEnumerator();
         }
 
+        public void AddSymbol(int symbol) {
+            Safe.ArgumentAssert(symbol >= 0, "symbol");
+            m_symbolCount = Math.Max(symbol + 1, m_symbolCount);
+        }
+
         public int[,] CreateTransitionTable() {
             var table = new int[StateCount,AlphabetSize];
 
@@ -162,7 +170,7 @@
 
             var state = new HashSet<int>(
                 Enumerable
-                .Range(0, m_stateCount - 1)
+                .Range(0, m_stateCount)
                 .Where(i => !m_finalStates.Contains(i))
             );
 
@@ -182,10 +190,13 @@
 
                 for (int c = 0; c < m_symbolCount; c++) {
                     var stateX = new HashSet<int>();
-                    foreach(var a in stateA.Where(rmap.ContainsKey))
-                        stateX.UnionWith(rmap[a][c]); // all states from wich the symbol 'c' leads to the state 'a'
+                    //foreach(var a in stateA.Where(rmap.ContainsKey))
+                    //    stateX.UnionWith(rmap[a][c]); // all states from wich the symbol 'c' leads to the state 'a'
 
-                    foreach (var stateY in optimalStates.ToArray()) {
+                    stateX.UnionWith(m_transitions.Where(t => stateA.Contains(t.s2) && t.edge == c).Select(t => t.s1));
+
+                    var tmp = optimalStates.ToArray();
+                    foreach (var stateY in tmp) {
                         if (stateX.Overlaps(stateY) && !stateY.IsSubsetOf(stateX)) {
                             var stateR1 = new HashSet<int>(stateY);
                             var stateR2 = new HashSet<int>(stateY);
@@ -245,12 +256,8 @@
 
                     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 s2 = m_transitions.Where(t => stateMap[t.s1] == s && t.edge == term).Select(t => stateMap[t.s2]).DefaultIfEmpty(-1).First();
 
-                        Debug.Assert(res.Length <= 1);
-
-                        var s2 = res.Length > 0 ? res[0] : -1;
-                            
                         HashSet<int> a2;
                         if (!classes.TryGetValue(s2, out a2)) {
                             a2 = new HashSet<int>();
@@ -283,6 +290,7 @@
 
                 // сохраняем DFAConst.UNCLASSIFIED_INPUT
                 var cls = item.Contains(AutomatonConst.UNCLASSIFIED_INPUT) ? AutomatonConst.UNCLASSIFIED_INPUT : nextCls++;
+                optimalDFA.AddSymbol(cls);
 
                 foreach (var a in item)
                     alphabetMap[a] = cls;
@@ -298,19 +306,38 @@
                 optimalDFA.Add(t);
         }
 
-        protected void PrintDFA<TInput, TState>(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) {
+        protected string PrintDFA<TInput, TState>(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) {
             Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet");
             Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet");
 
-            foreach(var t in m_transitions)
-                Console.WriteLine(
-                    "[{0}] -{{{1}}}-> [{2}]{3}",
-                    String.Join(",", stateAlphabet.GetSymbols(t.s1)),
-                    String.Join("", inputAlphabet.GetSymbols(t.edge)),
-                    String.Join(",", stateAlphabet.GetSymbols(t.s2)),
-                    m_finalStates.Contains(t.s2) ? "$" : ""
-                );
+            var data = new List<string>();
+
+            data.Add("digraph dfa {");
+
+            foreach (var final in m_finalStates)
+                data.Add(String.Format("{0} [shape=box];",String.Join("", stateAlphabet.GetSymbols(final))));
+
+            foreach (var t in m_transitions)
+                data.Add(String.Format(
+                    "{0} -> {2} [label={1}];",
+                    String.Join("", stateAlphabet.GetSymbols(t.s1)),
+                    ToLiteral(ToLiteral(String.Join("", t.edge == AutomatonConst.UNCLASSIFIED_INPUT ? new [] { "@" } : inputAlphabet.GetSymbols(t.edge).Select(x => x.ToString())))),
+                    String.Join("", stateAlphabet.GetSymbols(t.s2))
+                ));
+            data.Add("}");
+            return String.Join("\n", data);
         }
 
+        static string ToLiteral(string input)
+        {
+            using (var writer = new StringWriter())
+            {
+                using (var provider = CodeDomProvider.CreateProvider("CSharp"))
+                {
+                    provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null);
+                    return writer.ToString();
+                }
+            }
+        }
     }
 }