| author | Christian Urban <christian.urban@kcl.ac.uk> | 
| Wed, 21 Dec 2022 14:33:05 +0000 | |
| changeset 905 | d8f870aad77d | 
| parent 93 | 4794759139ea | 
| permissions | -rw-r--r-- | 
| 
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"))
 |