progs/automata/nfa1.scala
author Chengsong
Tue, 01 Mar 2022 11:14:17 +0000
changeset 435 65e786a58365
parent 215 645ce5697621
permissions -rw-r--r--
hi
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
215
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     1
// NFAs based on Scala's partial functions
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     2
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     3
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     4
// function that tests whether the intersection of two sets
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     5
// is non-empty
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     6
def share[A](a: Set[A], b: Set[A]) : Boolean =
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     7
  !(a intersect b).isEmpty
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     8
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     9
share(Set(1,2,3), Set(2, 3, 4))   // true
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    10
share(Set(1,2,3), Set(4, 5, 6))   // false
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    11
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    12
// nodes of the NFAs
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    13
abstract class State
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    14
type States = Set[State]
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    15
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    16
// edges of the NFAs
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    17
type Edge = PartialFunction[(State, Char), State]
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    18
type Edges = Set[Edge]
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    19
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    20
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    21
// gives a new state, when the edge fires
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    22
def fire(e: Edge, qc: (State, Char)) : Option[State] = 
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    23
  if (e.isDefinedAt(qc)) Some(e(qc)) else None
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    24
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    25
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    26
// class for NFAs
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    27
case class NFA(start: State,       // starting state
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    28
               trans: Edges,       // transition edges
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    29
               fins:  States)      // final states
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    30
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    31
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    32
// given the transitions and a state/character, 
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    33
// what are the set of next states?
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    34
def next(trans: Edges, q: State, c: Char) : States = {
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    35
  trans.map(fire(_, (q, c))).flatten
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    36
}
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    37
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    38
// given the transitions and some states/character, 
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    39
// what are the set of next states?
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    40
def nexts(trans: Edges, qs: States, c: Char) : States = {
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    41
  qs.flatMap(next(trans, _, c))
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    42
}
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    43
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    44
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    45
// given the transitions, some states and a string, 
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    46
// what are the set of next states?
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    47
def nextss(trans: Edges, qs: States, s: List[Char]) : States = s match {
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    48
  case Nil => qs
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    49
  case c::cs => nextss(trans, nexts(trans, qs, c), cs)
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    50
}
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    51
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    52
// is a string accepted by an NFA?
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    53
def accepts(nfa: NFA, s: String) : Boolean = {
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    54
  share(nextss(nfa.trans, Set(nfa.start), s.toList), nfa.fins)
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    55
}
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    56
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    57
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    58
// test cases
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    59
case object Q0 extends State
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    60
case object Q1 extends State
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    61
case object Q2 extends State
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    62
case object Q3 extends State
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    63
case object Q4 extends State
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    64
case object Q5 extends State
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    65
case object Q6 extends State
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    66
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    67
// 1 
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    68
val trans1 = Set[Edge](
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    69
  { case (Q0, 'a') => Q1 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    70
  { case (Q0, _)   => Q0 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    71
  { case (Q1, _)   => Q2 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    72
  { case (Q2, _)   => Q3 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    73
  { case (Q3, _)   => Q4 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    74
  { case (Q4, 'b') => Q5 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    75
  { case (Q5, 'c') => Q6 }
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    76
)
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    77
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    78
val nfa1 = NFA(Q0, trans1, Set[State](Q6))
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    79
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    80
accepts(nfa1, "axaybzbc")     // true
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    81
accepts(nfa1, "aaaaxaybzbc")  // true
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    82
accepts(nfa1, "axaybzbd")     // false
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    83
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    84
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    85
// 2
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    86
val trans2 = Set[Edge](
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    87
  { case (Q0, 'a') => Q0 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    88
  { case (Q0, 'a') => Q1 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    89
  { case (Q0, 'b') => Q2 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    90
  { case (Q1, 'a') => Q1 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    91
  { case (Q2, 'b') => Q2 }
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    92
)
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    93
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    94
val nfa2 = NFA(Q0, trans2, Set[State](Q2))
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    95
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    96
accepts(nfa2, "aa")             // false
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    97
accepts(nfa2, "aaaaa")          // false
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    98
accepts(nfa2, "aaaaab")         // true
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    99
accepts(nfa2, "aaaaabbb")       // true
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   100
accepts(nfa2, "aaaaabbbaaa")    // false
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   101
accepts(nfa2, "ac")             // false
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   102
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   103
// 3
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   104
val trans3 = Set[Edge](
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   105
  { case (Q0, _)   => Q0 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   106
  { case (Q0, 'a') => Q1 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   107
  { case (Q0, 'b') => Q3 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   108
  { case (Q1, 'b') => Q2 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   109
  { case (Q2, 'c') => Q5 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   110
  { case (Q3, 'c') => Q4 },
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   111
  { case (Q4, 'd') => Q5 }
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   112
)
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   113
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   114
val nfa3 = NFA(Q0, trans3, Set[State](Q5))
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   115
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   116
accepts(nfa3, "aaaaabc")      // true
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   117
accepts(nfa3, "aaaabcd")      // true
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   118
accepts(nfa3, "aaaaab")       // false
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   119
accepts(nfa3, "aaaabc")       // true
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   120
accepts(nfa3, "aaaaabbbaaa")  // false
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   121
645ce5697621 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   122