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