progs/automata.scala
changeset 121 4fc05d4f0e01
equal deleted inserted replaced
120:564b4baec85e 121:4fc05d4f0e01
       
     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