@@ -62,10 +62,11 @@ public class diagram
6262 public void MakeNFA ( string pattern ) { Diagram = make_nfa ( "(" + pattern + ")" ) ; }
6363 public void OptimizeNFA ( ) { while ( opt_nfa ( Diagram ) ) ; }
6464 public void NFAtoDFA ( ) { Diagram = nfa2dfa ( Diagram ) ; }
65- public void MinimizeDFA ( ) { opt_dfa ( Diagram ) ; }
65+ public void MinimizeDFA ( ) { opt_dfa_hopcroft ( Diagram ) ; }
6666 public string PrintDiagram ( ) { return print_diagram ( Diagram ) ; }
6767
6868 public static string PrintDiagram ( diagram dia ) { return print_diagram ( dia ) ; }
69+ public static string PrintGraph ( diagram dia ) { return print_diagram_for_graphviz ( dia ) ; }
6970
7071 /// <summary>
7172 /// Try simple-regular-expression to optimized DFA
@@ -342,6 +343,86 @@ private static string print_diagram(diagram d)
342343 return builder . ToString ( ) ;
343344 }
344345
346+ private static string print_diagram_for_graphviz ( diagram d )
347+ {
348+ var builder = new StringBuilder ( ) ;
349+ var used = new HashSet < int > ( ) ;
350+ 351+ var stack_used = new Stack < transition_node > ( ) ;
352+ var check_used = new List < bool > ( d . count_of_vertex ) ;
353+ check_used . AddRange ( Enumerable . Repeat ( false , d . count_of_vertex ) ) ;
354+ 355+ stack_used . Push ( d . start_node ) ;
356+ used . Add ( d . start_node . index ) ;
357+ 358+ while ( stack_used . Count != 0 )
359+ {
360+ var tn = stack_used . Pop ( ) ;
361+ if ( check_used [ tn . index ] ) continue ;
362+ check_used [ tn . index ] = true ;
363+ 364+ used . Add ( tn . index ) ;
365+ 366+ tn . transition . ForEach ( x => stack_used . Push ( x . Item2 ) ) ;
367+ }
368+ 369+ builder . Append ( "digraph finite_state_machine {\r \n " ) ;
370+ builder . Append ( " rankdir=LR;\r \n " ) ;
371+ builder . Append ( " size=\" 20,30\" \r \n " ) ;
372+ 373+ // print doublecircle
374+ builder . Append ( " node [shape = doublecircle]; " ) ;
375+ foreach ( var dd in d . nodes )
376+ if ( dd . is_acceptable && used . Contains ( dd . index ) )
377+ builder . Append ( dd . index + "; " ) ;
378+ builder . Append ( "\r \n " ) ;
379+ 380+ // print point
381+ builder . Append ( " node [shape = point]; ss\r \n " ) ;
382+ 383+ // print circle
384+ builder . Append ( " node [shape = circle];\r \n " ) ;
385+ 386+ var stack = new Stack < transition_node > ( ) ;
387+ var check = new List < bool > ( d . count_of_vertex ) ;
388+ check . AddRange ( Enumerable . Repeat ( false , d . count_of_vertex ) ) ;
389+ 390+ stack . Push ( d . start_node ) ;
391+ builder . Append ( $ " ss -> { d . start_node . index } ") ;
392+ 393+ while ( stack . Count != 0 )
394+ {
395+ var tn = stack . Pop ( ) ;
396+ if ( check [ tn . index ] ) continue ;
397+ check [ tn . index ] = true ;
398+ 399+ foreach ( var j in tn . transition )
400+ {
401+ string v = "" ;
402+ if ( j . Item1 == e_closure )
403+ v = "ε" ;
404+ else if ( j . Item1 == '"' )
405+ v = "\" " ;
406+ else if ( j . Item1 == '\n ' )
407+ v = "\\ n" ;
408+ else if ( j . Item1 == '\r ' )
409+ v = "\\ r" ;
410+ else if ( j . Item1 == '\t ' )
411+ v = "\\ t" ;
412+ else
413+ v = new string ( j . Item1 , 1 ) ;
414+ 415+ builder . Append ( $@ " { tn . index } -> { j . Item2 . index } [ label = ""{ v } "" ];" + "\r \n " ) ;
416+ }
417+ 418+ tn . transition . ForEach ( x => stack . Push ( x . Item2 ) ) ;
419+ }
420+ 421+ builder . Append ( "}" ) ;
422+ 423+ return builder . ToString ( ) ;
424+ }
425+ 345426 /// <summary>
346427 /// Get inverse array of diagram nodes
347428 /// </summary>
@@ -612,8 +693,7 @@ private diagram nfa2dfa(diagram dia)
612693 break ;
613694 }
614695 }
615- 616- 696+ 617697 diagram . count_of_vertex = transition_node_list . Count ;
618698 diagram . nodes = transition_node_list ;
619699 diagram . start_node = transition_node_list [ 0 ] ;
@@ -661,7 +741,7 @@ private void opt_dfa(diagram dia)
661741 }
662742
663743 color_count ++ ;
664- 744+
665745 while ( true )
666746 {
667747 // Collect transition color
@@ -700,6 +780,93 @@ private void opt_dfa(diagram dia)
700780
701781 previous_group = group ;
702782 }
783+ 784+ var dicc = new Dictionary < int , int > ( ) ;
785+ var inverse_transition = get_inverse_transtition ( dia ) ;
786+ for ( int i = 0 ; i < color . Count ; i ++ )
787+ if ( ! dicc . ContainsKey ( color [ i ] ) )
788+ dicc . Add ( color [ i ] , i ) ;
789+ else if ( inverse_transition . ContainsKey ( i ) )
790+ {
791+ foreach ( var inv in inverse_transition [ i ] )
792+ for ( int j = 0 ; j < dia . nodes [ inv ] . transition . Count ; j ++ )
793+ if ( dia . nodes [ inv ] . transition [ j ] . Item2 . index == i )
794+ dia . nodes [ inv ] . transition [ j ] = new Tuple < char , transition_node > ( dia . nodes [ inv ] . transition [ j ] . Item1 , dia . nodes [ dicc [ color [ i ] ] ] ) ;
795+ }
796+ }
797+ 798+ /// <summary>
799+ /// Minimization DFA using Hopcroft Algorithm
800+ /// </summary>
801+ /// <param name="dia"></param>
802+ /// <returns></returns>
803+ private void opt_dfa_hopcroft ( diagram dia )
804+ {
805+ var visit = new HashSet < string > ( ) ;
806+ var queue = new Queue < List < int > > ( ) ;
807+ 808+ // Enqueue Nodes
809+ var acc_nodes = new List < int > ( ) ;
810+ var nacc_nodes = new List < int > ( ) ;
811+ foreach ( var node in dia . nodes )
812+ if ( node . is_acceptable )
813+ acc_nodes . Add ( node . index ) ;
814+ else
815+ nacc_nodes . Add ( node . index ) ;
816+ 817+ queue . Enqueue ( acc_nodes ) ;
818+ queue . Enqueue ( nacc_nodes ) ;
819+ 820+ var color = new List < int > ( ) ;
821+ var color_count = 1 ;
822+ color . AddRange ( Enumerable . Repeat ( 0 , dia . count_of_vertex ) ) ;
823+ 824+ acc_nodes . ForEach ( x => color [ x ] = color_count ) ;
825+ color_count = 1 ;
826+ 827+ while ( queue . Count > 0 )
828+ {
829+ var front = queue . Dequeue ( ) ;
830+ front . Sort ( ) ;
831+ var str = string . Join ( "," , front ) ;
832+ 833+ if ( visit . Contains ( str ) ) continue ;
834+ visit . Add ( str ) ;
835+ 836+ //foreach (var node in front)
837+ // color[node] = color_count;
838+ //color_count++;
839+ 840+ // Collect transition color
841+ var dic = new Dictionary < int , SortedDictionary < char , int > > ( ) ;
842+ foreach ( var index in front )
843+ {
844+ var node = dia . nodes [ index ] ;
845+ foreach ( var ts in node . transition )
846+ {
847+ if ( ! dic . ContainsKey ( node . index ) )
848+ dic . Add ( node . index , new SortedDictionary < char , int > ( ) ) ;
849+ dic [ node . index ] . Add ( ts . Item1 , color [ ts . Item2 . index ] ) ;
850+ }
851+ }
852+ 853+ var list = dic . ToList ( ) ;
854+ var group = new Dictionary < string , List < int > > ( ) ;
855+ for ( int i = 0 ; i < list . Count ; i ++ )
856+ {
857+ var ds = dic2str ( list [ i ] . Value ) ;
858+ if ( ! group . ContainsKey ( ds ) )
859+ group . Add ( ds , new List < int > ( ) ) ;
860+ group [ ds ] . Add ( list [ i ] . Key ) ;
861+ }
862+ 863+ foreach ( var gi in group )
864+ {
865+ queue . Enqueue ( gi . Value ) ;
866+ gi . Value . ForEach ( x => color [ x ] = color_count ) ;
867+ color_count ++ ;
868+ }
869+ }
703870
704871 var dicc = new Dictionary < int , int > ( ) ;
705872 var inverse_transition = get_inverse_transtition ( dia ) ;
@@ -1004,4 +1171,4 @@ public Tuple<string, string, int, int> Lookahead()
10041171 return result ;
10051172 }
10061173 }
1007- }
1174+ }
0 commit comments