progs/automata/nfa2.scala
changeset 229 81c85f2746f5
equal deleted inserted replaced
228:8b432cef3805 229:81c85f2746f5
       
     1 // DFAs and NFAs based on Scala's partial functions
       
     2 
       
     3 
       
     4 // edges of the DFAs and NFAs
       
     5 type Edge[A, C] = PartialFunction[(A, C), A]
       
     6 
       
     7 
       
     8 
       
     9 
       
    10 // some states for test cases 
       
    11 abstract class State
       
    12 case object Q0 extends State
       
    13 case object Q1 extends State
       
    14 case object Q2 extends State
       
    15 case object Q3 extends State
       
    16 case object Q4 extends State
       
    17 case object Q5 extends State
       
    18 case object Q6 extends State
       
    19 
       
    20 
       
    21 // class for DFAs
       
    22 case class DFA[A, C](start: A,               // starting state
       
    23                      trans: Edge[A, C],      // transition
       
    24                      fins:  A => Boolean) {  // final states
       
    25 
       
    26   // given a state and a character, 
       
    27   // what is the next state, if there is any?
       
    28   def next(q: A, c: C) : Option[A] = 
       
    29     trans.lift.apply((q, c))
       
    30 
       
    31   // given a state and a string, what is the next state?
       
    32   def nexts(q: A, s: List[C]) : Option[A] = s match {
       
    33     case Nil => Some(q)
       
    34     case c::cs => next(q, c).flatMap(nexts(_, cs))
       
    35   }
       
    36 
       
    37   // is a string accepted by an DFA?
       
    38   def accepts(s: List[C]) : Boolean = nexts(start, s) match {
       
    39     case None => false
       
    40     case Some(q) => fins(q)
       
    41   }
       
    42 
       
    43 }
       
    44 
       
    45 // DFA 1
       
    46 val dtrans1 : Edge[State, Char] = 
       
    47   { case (Q0, 'a') => Q0 
       
    48     case (Q0, 'b') => Q1 
       
    49   }
       
    50 
       
    51 val dfa1 = DFA(Q0, dtrans1, Set[State](Q1))
       
    52 
       
    53 dfa1.accepts("aaab".toList)     // true
       
    54 dfa1.accepts("aacb".toList)     // false
       
    55 
       
    56 // another DFA test
       
    57 abstract class S
       
    58 case object S0 extends S
       
    59 case object S1 extends S
       
    60 case object S2 extends S
       
    61 case object Sink extends S
       
    62 
       
    63 // transition function
       
    64 // S0 --a--> S1 --a--> S2
       
    65 val sigma : Edge[S, Char] = 
       
    66   { case (S0, 'a') => S1
       
    67     case (S1, 'a') => S2
       
    68     case _ => Sink
       
    69   }
       
    70 
       
    71 val dfa1a = DFA(S0, sigma, Set[S](S2))
       
    72 
       
    73 dfa1a.accepts("aa".toList)               //true
       
    74 dfa1a.accepts("".toList)                 //false
       
    75 dfa1a.accepts("ab".toList)               //false
       
    76 
       
    77 
       
    78 // class for NFAs
       
    79 case class NFA[A, C](starts: Set[A],            // starting states
       
    80                      trans: Set[Edge[A, C]],    // transition edges
       
    81                      fins:  A => Boolean) {     // final states 
       
    82 
       
    83   // given a state and a character, what is the set of next states?
       
    84   def next(q: A, c: C) : Set[A] = 
       
    85     trans.flatMap(_.lift.apply((q, c)))
       
    86 
       
    87   // given some states and a character, what is the set of next states?
       
    88   def nexts(qs: Set[A], c: C) : Set[A] = 
       
    89     qs.flatMap(next(_, c))
       
    90 
       
    91   // given some states and a string, what is the set of next states?
       
    92   def nextss(qs: Set[A], s: List[C]) : Set[A] = s match {
       
    93     case Nil => qs
       
    94     case c::cs => nextss(nexts(qs, c), cs)
       
    95   }
       
    96 
       
    97   // is a string accepted by an NFA?
       
    98   def accepts(s: List[C]) : Boolean = 
       
    99     nextss(starts, s.toList).exists(fins)
       
   100 
       
   101 }
       
   102 
       
   103 
       
   104 
       
   105 
       
   106 // NFA test cases
       
   107 
       
   108 // 1 
       
   109 val trans1 = Set[Edge[State, Char]](
       
   110   { case (Q0, 'a') => Q1 },
       
   111   { case (Q0, _)   => Q0 },
       
   112   { case (Q1, _)   => Q2 },
       
   113   { case (Q2, _)   => Q3 },
       
   114   { case (Q3, _)   => Q4 },
       
   115   { case (Q4, 'b') => Q5 },
       
   116   { case (Q5, 'c') => Q6 }
       
   117 )
       
   118 
       
   119 val nfa1 = NFA(Set[State](Q0), trans1, Set[State](Q6))
       
   120 
       
   121 nfa1.accepts("axaybzbc".toList)     // true
       
   122 nfa1.accepts("aaaaxaybzbc".toList)  // true
       
   123 nfa1.accepts("axaybzbd".toList)     // false
       
   124 
       
   125 
       
   126 
       
   127 // 2
       
   128 val trans2 = Set[Edge[State, Char]](
       
   129   { case (Q0, 'a') => Q0 },
       
   130   { case (Q0, 'a') => Q1 },
       
   131   { case (Q0, 'b') => Q2 },
       
   132   { case (Q1, 'a') => Q1 },
       
   133   { case (Q2, 'b') => Q2 }
       
   134 )
       
   135 
       
   136 val nfa2 = NFA(Set[State](Q0), trans2, Set[State](Q2))
       
   137 
       
   138 nfa2.accepts("aa".toList)             // false
       
   139 nfa2.accepts("aaaaa".toList)          // false
       
   140 nfa2.accepts("aaaaab".toList)         // true
       
   141 nfa2.accepts("aaaaabbb".toList)       // true
       
   142 nfa2.accepts("aaaaabbbaaa".toList)    // false
       
   143 nfa2.accepts("ac".toList)             // false
       
   144 
       
   145 // 3
       
   146 val trans3 = Set[Edge[State, Char]](
       
   147   { case (Q0, _)   => Q0 },
       
   148   { case (Q0, 'a') => Q1 },
       
   149   { case (Q0, 'b') => Q3 },
       
   150   { case (Q1, 'b') => Q2 },
       
   151   { case (Q2, 'c') => Q5 },
       
   152   { case (Q3, 'c') => Q4 },
       
   153   { case (Q4, 'd') => Q5 }
       
   154 )
       
   155 
       
   156 val nfa3 = NFA(Set[State](Q0), trans3, Set[State](Q5))
       
   157 
       
   158 nfa3.accepts("aaaaabc".toList)      // true
       
   159 nfa3.accepts("aaaabcd".toList)      // true
       
   160 nfa3.accepts("aaaaab".toList)       // false
       
   161 nfa3.accepts("aaaabc".toList)       // true
       
   162 nfa3.accepts("aaaaabbbaaa".toList)  // false
       
   163 
       
   164 
       
   165 
       
   166 // subset, or powerset, construction
       
   167 def powerset[A, C](nfa: NFA[A, C]) : DFA[Set[A], C] = {
       
   168   DFA(nfa.starts, 
       
   169       { case (qs, c) => nfa.nexts(qs, c) },
       
   170       _.exists(nfa.fins))
       
   171 }
       
   172 
       
   173 val dfa2 = powerset(nfa1)
       
   174 
       
   175 dfa2.accepts("axaybzbc".toList)     // true
       
   176 dfa2.accepts("aaaaxaybzbc".toList)  // true
       
   177 dfa2.accepts("axaybzbd".toList)     // false
       
   178 
       
   179 val dfa3 = powerset(nfa2)
       
   180 
       
   181 dfa3.accepts("aa".toList)             // false
       
   182 dfa3.accepts("aaaaa".toList)          // false
       
   183 dfa3.accepts("aaaaab".toList)         // true
       
   184 dfa3.accepts("aaaaabbb".toList)       // true
       
   185 dfa3.accepts("aaaaabbbaaa".toList)    // false
       
   186 dfa3.accepts("ac".toList)             // false
       
   187 
       
   188 
       
   189 import scala.annotation.tailrec
       
   190 @tailrec
       
   191 def fixpT[A](f: A => A, x: A): A = {
       
   192   val fx = f(x)
       
   193   if (fx == x) x else fixpT(f, fx) 
       
   194 }
       
   195 
       
   196 
       
   197 case class eNFA[A, C](starts: Set[A],                    // starting state
       
   198                       trans: Set[Edge[A, Option[C]]],    // transition edges
       
   199                       fins:  A => Boolean) {             // final states 
       
   200 
       
   201   def enext(q: A) : Set[A] = 
       
   202     trans.flatMap(_.lift.apply((q, None)))
       
   203 
       
   204   def enexts(qs: Set[A]) : Set[A] = 
       
   205     qs ++ qs.flatMap(enext(_))
       
   206 
       
   207   // epsilon closure
       
   208   def ecl(qs: Set[A]) : Set[A] = 
       
   209     fixpT(enexts, qs)
       
   210 
       
   211   def next(q: A, c: C) : Set[A] = 
       
   212     trans.flatMap(_.lift.apply((q, Some(c))))
       
   213 
       
   214   def nexts(qs: Set[A], c: C) : Set[A] = 
       
   215     qs.flatMap(next(_, c))
       
   216 
       
   217   def nextss(qs: Set[A], s: List[C]) : Set[A] = s match {
       
   218     case Nil => ecl(qs)
       
   219     case c::cs => nextss(ecl(nexts(ecl(qs), c)), cs)
       
   220   }
       
   221 
       
   222   def accepts(s: List[C]) : Boolean = 
       
   223     nextss(starts, s.toList).exists(fins)
       
   224 
       
   225 }
       
   226 
       
   227 val etrans1 = Set[Edge[State, Option[Char]]](
       
   228   { case (Q0, Some('a')) => Q1 },
       
   229   { case (Q1, None) => Q0 }
       
   230 )
       
   231 
       
   232 val enfa = eNFA(Set[State](Q0), etrans1, Set[State](Q1))
       
   233 
       
   234 enfa.accepts("a".toList)              // true
       
   235 enfa.accepts("".toList)               // false
       
   236 enfa.accepts("aaaaa".toList)          // true
       
   237 enfa.accepts("aaaaab".toList)         // flase
       
   238 enfa.accepts("aaaaabbb".toList)       // false
       
   239 enfa.accepts("aaaaabbbaaa".toList)    // false
       
   240 enfa.accepts("ac".toList)             // false
       
   241 
       
   242 
       
   243 
       
   244 abstract class Rexp
       
   245 case object ZERO extends Rexp
       
   246 case object ONE extends Rexp
       
   247 case class CHAR(c: Char) extends Rexp
       
   248 case object ALL extends Rexp
       
   249 case class ALT(r1: Rexp, r2: Rexp) extends Rexp 
       
   250 case class SEQ(r1: Rexp, r2: Rexp) extends Rexp 
       
   251 case class STAR(r: Rexp) extends Rexp 
       
   252 case class NTIMES(r: Rexp, n: Int) extends Rexp 
       
   253 case class UPNTIMES(r: Rexp, n: Int) extends Rexp 
       
   254 
       
   255 import scala.language.implicitConversions    
       
   256 import scala.language.reflectiveCalls 
       
   257 
       
   258 def charlist2rexp(s: List[Char]): Rexp = s match {
       
   259   case Nil => ONE
       
   260   case c::Nil => CHAR(c)
       
   261   case c::s => SEQ(CHAR(c), charlist2rexp(s))
       
   262 }
       
   263 implicit def string2rexp(s: String): Rexp = charlist2rexp(s.toList)
       
   264 
       
   265 implicit def RexpOps (r: Rexp) = new {
       
   266   def | (s: Rexp) = ALT(r, s)
       
   267   def % = STAR(r)
       
   268   def ~ (s: Rexp) = SEQ(r, s)
       
   269 }
       
   270 
       
   271 implicit def stringOps (s: String) = new {
       
   272   def | (r: Rexp) = ALT(s, r)
       
   273   def | (r: String) = ALT(s, r)
       
   274   def % = STAR(s)
       
   275   def ~ (r: Rexp) = SEQ(s, r)
       
   276   def ~ (r: String) = SEQ(s, r)
       
   277 }
       
   278 
       
   279 
       
   280 
       
   281 // nullable function: tests whether the regular 
       
   282 // expression can recognise the empty string
       
   283 def nullable (r: Rexp) : Boolean = r match {
       
   284   case ZERO => false
       
   285   case ONE => true
       
   286   case CHAR(_) => false
       
   287   case ALL => false
       
   288   case ALT(r1, r2) => nullable(r1) || nullable(r2)
       
   289   case SEQ(r1, r2) => nullable(r1) && nullable(r2)
       
   290   case STAR(_) => true
       
   291   case NTIMES(r, i) => if (i == 0) true else nullable(r)
       
   292   case UPNTIMES(r: Rexp, n: Int) => true
       
   293 }
       
   294 
       
   295 // derivative of a regular expression w.r.t. a character
       
   296 def der (c: Char, r: Rexp) : Rexp = r match {
       
   297   case ZERO => ZERO
       
   298   case ONE => ZERO
       
   299   case CHAR(d) => if (c == d) ONE else ZERO
       
   300   case ALL => ONE
       
   301   case ALT(r1, r2) => ALT(der(c, r1), der(c, r2))
       
   302   case SEQ(r1, r2) => 
       
   303     if (nullable(r1)) ALT(SEQ(der(c, r1), r2), der(c, r2))
       
   304     else SEQ(der(c, r1), r2)
       
   305   case STAR(r1) => SEQ(der(c, r1), STAR(r1))
       
   306   case NTIMES(r1, i) => 
       
   307     if (i == 0) ZERO else
       
   308     if (nullable(r1)) SEQ(der(c, r1), UPNTIMES(r1, i - 1))
       
   309     else SEQ(der(c, r1), NTIMES(r1, i - 1))
       
   310   case UPNTIMES(r1, i) => 
       
   311     if (i == 0) ZERO
       
   312     else SEQ(der(c, r1), UPNTIMES(r1, i - 1)) 
       
   313 }
       
   314 
       
   315 
       
   316 // partial derivative of a regular expression w.r.t. a character
       
   317 def pder (c: Char, r: Rexp) : Set[Rexp] = r match {
       
   318   case ZERO => Set()
       
   319   case ONE => Set()
       
   320   case CHAR(d) => if (c == d) Set(ONE) else Set()
       
   321   case ALL => Set(ONE)
       
   322   case ALT(r1, r2) => pder(c, r1) ++ pder(c, r2)
       
   323   case SEQ(r1, r2) => 
       
   324     (for (pr1 <- pder(c, r1)) yield SEQ(pr1, r2)) ++ 
       
   325     (if (nullable(r1)) pder(c, r2) else Set())
       
   326   case STAR(r1) => 
       
   327     for (pr1 <- pder(c, r1)) yield SEQ(pr1, STAR(r1))
       
   328   case NTIMES(r1, i) => 
       
   329     if (i == 0) Set() else
       
   330     if (nullable(r1)) 
       
   331       for (pr1 <- pder(c, r1)) yield SEQ(pr1, UPNTIMES(r1, i - 1))
       
   332     else 
       
   333       for (pr1 <- pder(c, r1)) yield SEQ(pr1, NTIMES(r1, i - 1))
       
   334   case UPNTIMES(r1, i) => 
       
   335     if (i == 0) Set()
       
   336     else 
       
   337       for (pr1 <- pder(c, r1)) yield SEQ(pr1, UPNTIMES(r1, i - 1))
       
   338 }
       
   339 
       
   340 val r = STAR(ALL) ~ "a" ~ NTIMES(ALL, 3) ~ "bc"
       
   341 val pder_nfa = NFA[Set[Rexp], Char](Set(Set(r)), 
       
   342                                     Set( { case (rs, c) => rs.flatMap(pder(c, _))} ), 
       
   343                                     _.exists(nullable))
       
   344 
       
   345 
       
   346 
       
   347 pder_nfa.accepts("axaybzbc".toList)     // true
       
   348 pder_nfa.accepts("aaaaxaybzbc".toList)  // true
       
   349 pder_nfa.accepts("axaybzbd".toList)     // false
       
   350 
       
   351 
       
   352 
       
   353 
       
   354 ///
       
   355 type Trans[A, C] = Map[(A, C), A]
       
   356