-
Notifications
You must be signed in to change notification settings - Fork 0
/
AutomatonCache.scala
64 lines (54 loc) · 1.58 KB
/
AutomatonCache.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package automaton
import stainless._
import stainless.collection._
import stainless.lang._
import stainless.proof._
case class MemDFA[State, Sym](
dfa: DFA[State, Sym],
cache: Map[(State, Sym), State]
) {
require {
forall { (s: State, w: Sym) =>
cache.isDefinedAt((s, w)) ==> (dfa.move(s, w) == cache((s, w)))
}
}
def move(s: State, w: Sym): (State, MemDFA[State, Sym]) = {
cache.get((s, w)) match {
case Some(t) => (t, this)
case None() =>
val t = dfa.move(s, w)
(t, MemDFA(dfa, cache + ((s, w) -> t)))
}
}
def run(state: State, word: List[Sym]): (State, MemDFA[State, Sym]) = {
word match {
case Nil() => (state, this)
case (w :: ws) =>
val (t, mem) = move(state, w)
mem.run(t, ws)
}
}
def accepts(word: List[Sym]): (Boolean, MemDFA[State, Sym]) = {
val (s, mem) = run(dfa.initialState, word)
(dfa.isFinal(s), mem)
}
}
object Specs {
def lemma[State, Sym](dfa: DFA[State, Sym], mem: MemDFA[State, Sym],
s: State, word: List[Sym]): Boolean = {
require(dfa == mem.dfa)
dfa.run(s, word) == mem.run(s, word)._1
}.holds because {
word match {
case Nil() => trivial
case (w :: ws) =>
val (t, newMem) = mem.move(s, w)
lemma(dfa, newMem, dfa.move(s, w), ws)
}
}
def equiv[State, Sym](dfa: DFA[State, Sym], mem: MemDFA[State, Sym],
word: List[Sym]): Boolean = {
require(dfa == mem.dfa)
dfa.accepts(word) == mem.accepts(word)._1
}.holds because lemma(dfa, mem, dfa.initialState, word)
}