@@ -42,6 +42,71 @@ pub enum StateOrdering {
4242}
4343
4444impl Nfa {
45+ /// checks if the nfa is is complete:
46+ /// every state has a an outgoing transition for every letter in the alphabet
47+ ///
48+ /// TODO: this uses equality on (sorted) vectors. Are HashSets better?
49+ pub fn is_complete ( & self ) -> bool {
50+ // get the alphabet
51+ let mut letters = self . get_alphabet ( ) ;
52+ letters. sort ( ) ;
53+ // for each state, check if it has a transition for each letter in the alphabet
54+ for state in 0 ..self . nb_states ( ) {
55+ let mut state_actions = self
56+ . transitions
57+ . iter ( )
58+ . filter ( |t| t. from == state)
59+ . map ( |t| t. label . clone ( ) )
60+ . collect :: < Vec < _ > > ( ) ;
61+ state_actions. sort ( ) ;
62+ if state_actions != letters {
63+ return false ;
64+ }
65+ }
66+ true
67+ }
68+
69+ /// completes the nfa by adding self-loops for every letter in the alphabet
70+ ///
71+ /// This takes an optional state to be used as target for the new transitions.
72+ /// If this is None, new transitions will be self-loops.
73+ ///
74+ /// This is really horrible because we have to recompute the alphabet lots
75+ pub fn complete ( & mut self , sink_state : Option < State > ) {
76+ // get the alphabet
77+ let mut letters = self
78+ . get_alphabet ( )
79+ . iter ( )
80+ . map ( |x| x. to_string ( ) )
81+ . collect :: < Vec < _ > > ( ) ;
82+ letters. sort ( ) ;
83+ // for each state, get all its actions
84+ for state in 0 ..self . nb_states ( ) {
85+ let mut state_actions = self
86+ . transitions
87+ . iter ( )
88+ . filter ( |t| t. from == state)
89+ . map ( |t| t. label . clone ( ) )
90+ . collect :: < Vec < _ > > ( ) ;
91+ state_actions. sort ( ) ;
92+
93+ // for every alphabent letter add new transitions
94+ for letter in & letters {
95+ if !state_actions. contains ( letter) {
96+ match sink_state {
97+ Some ( sink) => {
98+ self . add_transition_by_index2 ( state, sink, letter) ;
99+ }
100+ None => {
101+ // add a self-loop
102+ self . add_transition_by_index2 ( state, state, letter) ;
103+ }
104+ }
105+ }
106+ }
107+ }
108+ }
109+
45110 /// getter for the states attribute
46111 pub fn states ( & self ) -> & Vec < String > {
47112 & self . states
@@ -208,6 +273,8 @@ impl Nfa {
208273 nfa
209274 }
210275
276+ /// Returns the alphabet of the NFA
277+ /// TODO: return a set?
211278 pub fn get_alphabet ( & self ) -> Vec < & str > {
212279 let mut letters = Vec :: new ( ) ;
213280 self . transitions . iter ( ) . for_each ( |t| {
@@ -463,6 +530,70 @@ impl fmt::Display for Nfa {
463530mod test {
464531 use super :: * ;
465532
533+ #[ test]
534+ fn is_complete1 ( ) {
535+ let mut nfa = Nfa :: from_size ( 2 ) ;
536+ nfa. add_transition_by_index1 ( 0 , 1 , 'a' ) ;
537+ nfa. add_transition_by_index1 ( 0 , 1 , 'b' ) ;
538+ nfa. add_transition_by_index1 ( 1 , 0 , 'b' ) ;
539+
540+ assert ! ( !nfa. is_complete( ) ) ;
541+ }
542+ #[ test]
543+ fn is_complete2 ( ) {
544+ let mut nfa = Nfa :: from_size ( 2 ) ;
545+ nfa. add_transition_by_index1 ( 0 , 1 , 'a' ) ;
546+ nfa. add_transition_by_index1 ( 0 , 1 , 'b' ) ;
547+ nfa. add_transition_by_index1 ( 1 , 0 , 'a' ) ;
548+ nfa. add_transition_by_index1 ( 1 , 0 , 'b' ) ;
549+
550+ assert ! ( nfa. is_complete( ) ) ;
551+ }
552+ #[ test]
553+ fn complete_to_selfloops ( ) {
554+ // this NFA is missing a 'b'-strep from state 1.
555+ // after completion, there should be a step 1 -b-> 1.
556+ let mut nfa = Nfa :: from_size ( 2 ) ;
557+ nfa. add_transition_by_index1 ( 0 , 1 , 'a' ) ;
558+ nfa. add_transition_by_index1 ( 0 , 1 , 'b' ) ;
559+ nfa. add_transition_by_index1 ( 1 , 0 , 'a' ) ;
560+
561+ assert ! ( !nfa. is_complete( ) ) ;
562+ nfa. complete ( None ) ;
563+ assert ! ( nfa. is_complete( ) ) ;
564+ assert ! ( nfa. transitions
565+ . iter( )
566+ . filter( |t| t. from == 1 && t. label== "b" && t. to==1 )
567+ . next( ) . is_some( )
568+ ) ;
569+ }
570+ #[ test]
571+ fn complete_to_first ( ) {
572+ // this NFA is missing an 'a'-step from state 0 and a b'-step from state 1.
573+ // after completion, both should exist and point to 0.
574+ let mut nfa = Nfa :: from_size ( 2 ) ;
575+ nfa. add_transition_by_index1 ( 0 , 1 , 'b' ) ;
576+ nfa. add_transition_by_index1 ( 1 , 0 , 'a' ) ;
577+
578+ assert ! ( !nfa. is_complete( ) ) ;
579+ nfa. complete ( Some ( 0 ) ) ;
580+
581+ assert ! ( nfa. is_complete( ) ) ;
582+
583+ // check if 0 -a-> 0 exists
584+ assert ! ( nfa. transitions
585+ . iter( )
586+ . filter( |t| t. from == 0 && t. label == "a" && t. to==0 )
587+ . next( ) . is_some( )
588+ ) ;
589+ // check if 1 -b-> 0 exists
590+ assert ! ( nfa. transitions
591+ . iter( )
592+ . filter( |t| t. from == 1 && t. label == "b" && t. to == 0 )
593+ . next( ) . is_some( )
594+ ) ;
595+ }
596+
466597 #[ test]
467598 fn create ( ) {
468599 let mut nfa = Nfa :: from_states ( & [ "toto" , "titi" ] ) ;
0 commit comments