progs/automata.scala
author Christian Urban <christian.urban@kcl.ac.uk>
Fri, 22 Jan 2021 10:39:04 +0000
changeset 822 6b06aeb192ea
parent 93 4794759139ea
permissions -rw-r--r--
updated
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
34
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     1
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     2
// a class for deterministic finite automata,
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     3
// the type of states is kept polymorphic
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     4
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     5
case class Automaton[A](start: A, states: Set[A], delta: Map[(A, Char), A], fins: Set[A]) {
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     6
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     7
  // the transition function lifted to list of characters
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     8
  def deltas(q: A, cs: List[Char]) : Either[A, String] = 
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     9
    if (states.contains(q)) cs match {
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    10
      case Nil => Left(q)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    11
      case c::cs => 
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    12
        if (delta.isDefinedAt(q, c)) deltas(delta(q, c), cs)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    13
        else Right(q + " does not have a transition for " + c)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    14
    }
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    15
    else Right(q + " is not a state of the automaton")
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    16
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    17
  // wether a string is accepted by the automaton
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    18
  def accepts(s: String) = deltas(start, s.toList) match {
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    19
    case Left(q) => fins.contains(q)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    20
    case _ => false
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    21
  } 
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    22
}
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    23
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    24
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    25
// translating a regular expression into a finite
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    26
// automaton
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    27
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    28
abstract class Rexp
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    29
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    30
case object NULL extends Rexp
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    31
case object EMPTY extends Rexp
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    32
case class CHAR(c: Char) extends Rexp 
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    33
case class ALT(r1: Rexp, r2: Rexp) extends Rexp
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    34
case class SEQ(r1: Rexp, r2: Rexp) extends Rexp 
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    35
case class STAR(r: Rexp) extends Rexp
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    36
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    37
implicit def string2rexp(s : String) = { 
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    38
  def chars2rexp (cs: List[Char]) : Rexp = cs match {
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    39
    case Nil => EMPTY
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    40
    case c::Nil => CHAR(c)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    41
    case c::cs => SEQ(CHAR(c), chars2rexp(cs))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    42
  }
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    43
  chars2rexp(s.toList)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    44
}
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    45
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    46
def nullable (r: Rexp) : Boolean = r match {
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    47
  case NULL => false
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    48
  case EMPTY => true
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    49
  case CHAR(_) => false
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    50
  case ALT(r1, r2) => nullable(r1) || nullable(r2)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    51
  case SEQ(r1, r2) => nullable(r1) && nullable(r2)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    52
  case STAR(_) => true
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    53
}
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    54
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    55
def der (r: Rexp, c: Char) : Rexp = r match {
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    56
  case NULL => NULL
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    57
  case EMPTY => NULL
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    58
  case CHAR(d) => if (c == d) EMPTY else NULL
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    59
  case ALT(r1, r2) => ALT(der(r1, c), der(r2, c))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    60
  case SEQ(r1, r2) => if (nullable(r1)) ALT(SEQ(der(r1, c), r2), der(r2, c))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    61
                      else SEQ(der(r1, c), r2)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    62
  case STAR(r) => SEQ(der(r, c), STAR(r))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    63
}
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    64
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    65
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    66
// Here we construct an automaton whose
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    67
// states are regular expressions
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    68
type State = Rexp
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    69
type States = Set[State]
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    70
type Transition =  Map[(State, Char), State]
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    71
35
Christian Urban <urbanc@in.tum.de>
parents: 34
diff changeset
    72
// we use as an alphabet all lowercase letters
Christian Urban <urbanc@in.tum.de>
parents: 34
diff changeset
    73
val alphabet = "abcdefghijklmnopqrstuvwxyz".toSet
Christian Urban <urbanc@in.tum.de>
parents: 34
diff changeset
    74
34
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    75
def goto(q: State, c: Char, qs: States, delta: Transition) : (States, Transition) = {
35
Christian Urban <urbanc@in.tum.de>
parents: 34
diff changeset
    76
  val q_der : State = der(q, c)
Christian Urban <urbanc@in.tum.de>
parents: 34
diff changeset
    77
  if (qs.contains(q_der)) (qs, delta + ((q, c) -> q))
Christian Urban <urbanc@in.tum.de>
parents: 34
diff changeset
    78
  else explore(qs + q_der, delta + ((q, c) -> q_der), q_der)
34
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    79
}
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    80
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    81
def explore (qs: States, delta: Transition, q: State) : (States, Transition) =
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    82
  alphabet.foldRight[(States, Transition)] (qs, delta) ((c, qsd) => goto(q, c, qsd._1, qsd._2)) 
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    83
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    84
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    85
def mk_automaton (r: Rexp) : Automaton[Rexp] = {
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    86
  val (qs, delta) = explore(Set(r), Map(), r);
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    87
  val fins = for (q <- qs if nullable(q)) yield q;
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    88
  Automaton[Rexp](r, qs, delta, fins)
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    89
}
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    90
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    91
val A = mk_automaton(ALT("ab","ac"))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    92
43
Christian Urban <urbanc@in.tum.de>
parents: 35
diff changeset
    93
A.start
Christian Urban <urbanc@in.tum.de>
parents: 35
diff changeset
    94
A.states.toList.length
Christian Urban <urbanc@in.tum.de>
parents: 35
diff changeset
    95
34
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    96
println(A.accepts("bd"))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    97
println(A.accepts("ab"))
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    98
println(A.accepts("ac"))
43
Christian Urban <urbanc@in.tum.de>
parents: 35
diff changeset
    99
Christian Urban <urbanc@in.tum.de>
parents: 35
diff changeset
   100
val r1 = STAR(ALT("a","b"))
Christian Urban <urbanc@in.tum.de>
parents: 35
diff changeset
   101
val r2 = SEQ("b","b")
Christian Urban <urbanc@in.tum.de>
parents: 35
diff changeset
   102
val r3 = SEQ(SEQ(SEQ(r1, r2), r1), "a")
Christian Urban <urbanc@in.tum.de>
parents: 35
diff changeset
   103
val B = mk_automaton(r3)
Christian Urban <urbanc@in.tum.de>
parents: 35
diff changeset
   104
Christian Urban <urbanc@in.tum.de>
parents: 35
diff changeset
   105
B.start
Christian Urban <urbanc@in.tum.de>
parents: 35
diff changeset
   106
B.states.toList.length