|         |      1 // NFAs and DFAs based on Scala's partial functions | 
|         |      2  | 
|         |      3  | 
|         |      4 // (1) Write a polymorphic function that tests whether the  | 
|         |      5 // intersection of two sets is non-empty | 
|         |      6  | 
|         |      7 def share[A](a: Set[A], b: Set[A]) : Boolean = ... | 
|         |      8  | 
|         |      9  | 
|         |     10 share(Set(1,2,3), Set(2, 3, 4))   // true | 
|         |     11 share(Set(1,2,3), Set(4, 5, 6))   // false | 
|         |     12  | 
|         |     13  | 
|         |     14 // State nodes of the DFAs and NFAs | 
|         |     15 abstract class State | 
|         |     16 type States = Set[State] | 
|         |     17  | 
|         |     18 // Some states for test cases | 
|         |     19 case object Q0 extends State | 
|         |     20 case object Q1 extends State | 
|         |     21 case object Q2 extends State | 
|         |     22 case object Q3 extends State | 
|         |     23 case object Q4 extends State | 
|         |     24 case object Q5 extends State | 
|         |     25 case object Q6 extends State | 
|         |     26  | 
|         |     27  | 
|         |     28 // Transitions for DFAs and NFAs | 
|         |     29 type Trans = PartialFunction[(State, Char), State] | 
|         |     30 type NTrans = Set[Trans] | 
|         |     31  | 
|         |     32  | 
|         |     33 // example transition of an DFA | 
|         |     34 val dtrans : Trans =  | 
|         |     35   { case (Q0, 'a') => Q1  | 
|         |     36     case (Q0, 'b') => Q0 | 
|         |     37     case (Q1, 'a') => Q2  | 
|         |     38     case (Q1, 'b') => Q0 | 
|         |     39     case (Q2, 'a') => Q2  | 
|         |     40     case (Q2, 'b') => Q0  | 
|         |     41   } | 
|         |     42  | 
|         |     43  | 
|         |     44 // (2) Write a function that takes a transition and a  | 
|         |     45 // (state, character)-pair as arguments and produces an  | 
|         |     46 // optional state (the state specified by the partial transition | 
|         |     47 // function whenever it is defined; if the transition function  | 
|         |     48 // is undefined, return None. | 
|         |     49  | 
|         |     50 def fire(e: Trans, qc: (State, Char)) : Option[State] = ... | 
|         |     51  | 
|         |     52  | 
|         |     53 // (3) Write a function that takes a transition, a state  | 
|         |     54 // and a list of characters as arguments and produces  | 
|         |     55 // the state generated by following the transitions for  | 
|         |     56 // each character in the list. | 
|         |     57  | 
|         |     58 def nexts(trans: Trans, q: State, s: List[Char]) : Option[State] = ... | 
|         |     59  | 
|         |     60  | 
|         |     61  | 
|         |     62 // class for DFAs | 
|         |     63 case class DFA(start: State,      // starting state | 
|         |     64                trans: Trans,      // transition | 
|         |     65                fins:  States)     // final states | 
|         |     66  | 
|         |     67 // (4) Write a function that tests whether a string is accepted  | 
|         |     68 // by an DFA or not. | 
|         |     69  | 
|         |     70 def accepts(dfa: DFA, s: String) : Boolean = ... | 
|         |     71  | 
|         |     72  | 
|         |     73  | 
|         |     74 // DFA examples | 
|         |     75   | 
|         |     76 val dtrans1 : Trans =  | 
|         |     77   { case (Q0, 'a') => Q0  | 
|         |     78     case (Q0, 'b') => Q1  | 
|         |     79   } | 
|         |     80  | 
|         |     81 val dfa1 = DFA(Q0, dtrans1, Set[State](Q1)) | 
|         |     82  | 
|         |     83 accepts(dfa1, "aaab")     // true | 
|         |     84 accepts(dfa1, "aacb")     // false | 
|         |     85  | 
|         |     86  | 
|         |     87 // NFAs | 
|         |     88  | 
|         |     89  | 
|         |     90 // (5) Write a function that takes a transition set, a state | 
|         |     91 // and a character as arguments, and calculates all possible  | 
|         |     92 // next states (returned as set). | 
|         |     93  | 
|         |     94 def nnext(trans: NTrans, q: State, c: Char) : States = ... | 
|         |     95  | 
|         |     96  | 
|         |     97 // (6) Write a function that takes a transition set, a set of states  | 
|         |     98 // and a character as arguments, and calculates all possible  | 
|         |     99 // next states that can be reached from any state in the set. | 
|         |    100  | 
|         |    101 def nnexts(trans: NTrans, qs: States, c: Char) : States = ... | 
|         |    102  | 
|         |    103  | 
|         |    104  | 
|         |    105 // (7) Write a function that lifts nnexts from from single  | 
|         |    106 // characters to lists of characters. | 
|         |    107 def nnextss(trans: NTrans, qs: States, s: List[Char]) : States = ... | 
|         |    108  | 
|         |    109  | 
|         |    110 // class for NFAs | 
|         |    111 case class NFA(start: States,       // starting state | 
|         |    112                trans: NTrans,       // transition edges | 
|         |    113                fins:  States)       // final states | 
|         |    114  | 
|         |    115  | 
|         |    116 // (8) Write a function that tests whether a string is  | 
|         |    117 // accepted by an NFA or not. | 
|         |    118  | 
|         |    119 def naccepts(nfa: NFA, s: String) : Boolean = ... | 
|         |    120  | 
|         |    121  | 
|         |    122 // (9) Write similar functions as in (7) and (8), but instead of  | 
|         |    123 // returning states or a boolean, calculate the number of states  | 
|         |    124 // that need to be followed in each step. | 
|         |    125  | 
|         |    126 def max_nextss(trans: NTrans, qs: States, s: List[Char], max: Int) : Int = ... | 
|         |    127  | 
|         |    128 def max_accepts(nfa: NFA, s: String) : Int = ... | 
|         |    129  | 
|         |    130  | 
|         |    131 // NFA examples | 
|         |    132  | 
|         |    133  | 
|         |    134 // 1  | 
|         |    135 val trans1 : NTrans = Set( | 
|         |    136   { case (Q0, 'a') => Q1 }, | 
|         |    137   { case (Q0, _)   => Q0 }, | 
|         |    138   { case (Q1, _)   => Q2 }, | 
|         |    139   { case (Q2, _)   => Q3 }, | 
|         |    140   { case (Q3, _)   => Q4 }, | 
|         |    141   { case (Q4, 'b') => Q5 }, | 
|         |    142   { case (Q5, 'c') => Q6 } | 
|         |    143 ) | 
|         |    144  | 
|         |    145 val nfa1 = NFA(Set[State](Q0), trans1, Set[State](Q6)) | 
|         |    146  | 
|         |    147 naccepts(nfa1, "axaybzbc")     // true | 
|         |    148 naccepts(nfa1, "aaaaxaybzbc")  // true | 
|         |    149 naccepts(nfa1, "axaybzbd")     // false | 
|         |    150  | 
|         |    151 // the nfa has five states, which might be all  | 
|         |    152 // active | 
|         |    153  | 
|         |    154 max_accepts(nfa1, "axaybzbc")     // 3  | 
|         |    155 max_accepts(nfa1, "aaaaxaybzbc")  // 5 | 
|         |    156 max_accepts(nfa1, "axaybzbd")     // 3 | 
|         |    157 max_accepts(nfa1, "aaaaaaaaaaaaaxaybzbd")   // 5 | 
|         |    158  | 
|         |    159  | 
|         |    160 // 2 | 
|         |    161 val trans2 : NTrans = Set( | 
|         |    162   { case (Q0, 'a') => Q0 }, | 
|         |    163   { case (Q0, 'a') => Q1 }, | 
|         |    164   { case (Q0, 'b') => Q2 }, | 
|         |    165   { case (Q1, 'a') => Q1 }, | 
|         |    166   { case (Q2, 'b') => Q2 } | 
|         |    167 ) | 
|         |    168  | 
|         |    169 val nfa2 = NFA(Set[State](Q0), trans2, Set[State](Q2)) | 
|         |    170  | 
|         |    171 naccepts(nfa2, "aa")             // false | 
|         |    172 naccepts(nfa2, "aaaaa")          // false | 
|         |    173 naccepts(nfa2, "aaaaab")         // true | 
|         |    174 naccepts(nfa2, "aaaaabbb")       // true | 
|         |    175 naccepts(nfa2, "aaaaabbbaaa")    // false | 
|         |    176 naccepts(nfa2, "ac")             // false | 
|         |    177  | 
|         |    178 // 3 | 
|         |    179 val trans3 : NTrans = Set( | 
|         |    180   { case (Q0, _)   => Q0 }, | 
|         |    181   { case (Q0, 'a') => Q1 }, | 
|         |    182   { case (Q0, 'b') => Q3 }, | 
|         |    183   { case (Q1, 'b') => Q2 }, | 
|         |    184   { case (Q2, 'c') => Q5 }, | 
|         |    185   { case (Q3, 'c') => Q4 }, | 
|         |    186   { case (Q4, 'd') => Q5 } | 
|         |    187 ) | 
|         |    188  | 
|         |    189 val nfa3 = NFA(Set[State](Q0), trans3, Set[State](Q5)) | 
|         |    190  | 
|         |    191 naccepts(nfa3, "aaaaabc")      // true | 
|         |    192 naccepts(nfa3, "aaaabcd")      // true | 
|         |    193 naccepts(nfa3, "aaaaab")       // false | 
|         |    194 naccepts(nfa3, "aaaabc")       // true | 
|         |    195 naccepts(nfa3, "aaaaabbbaaa")  // false | 
|         |    196  | 
|         |    197  |