110 lines
3.3 KiB
Text
110 lines
3.3 KiB
Text
#import "../common.typ": *
|
|
#import "@preview/prooftrees:0.1.0": *
|
|
#show: doc => conf("Rule-based languages from modular design to modular verification", doc)
|
|
#import "@preview/finite:0.3.0" as finite: automaton
|
|
|
|
== Lecture 1
|
|
|
|
*Definition (module).* $(S."type", {R}_(i in S), {v m}, {a m})$
|
|
|
|
- States
|
|
- $R subset S times S$. these are transitions, very similar to automata
|
|
- $a m subset S times NN times S$. argument methods. One argument always, type natural number. "If I'm in a state, and then I call some action, then I end up in a new state"
|
|
- $v m subset S times NN times NN$. value methods are the only way to observe anything in the system. Observations are always of type nat for now.
|
|
|
|
*Example (coffee-tea machine).*
|
|
|
|
#automaton(
|
|
layout: finite.layout.snake.with(columns: 3),
|
|
(
|
|
q1: (q2: "put"),
|
|
q2: (q3: "coffee", q4: "tea"),
|
|
q3: (q3: "see"),
|
|
q4: (q4: "see"),
|
|
)
|
|
)
|
|
|
|
This is encoded as:
|
|
|
|
$({1, 2, 3, 4}, {}, {
|
|
"getTea" = {(2, star, 4)},
|
|
"getCoffee" = {(2, star, 3)},
|
|
"putMoney" = {(1, 1, 2)},
|
|
}, {
|
|
"see" = {(3, star, "coffee"), (4, star, "tea")}
|
|
})$
|
|
|
|
Similarity to automata
|
|
- Finite states
|
|
Differences from automata
|
|
- Sliced transitions between things that change the state of the system and ones that observe the state of the system
|
|
|
|
We are interested in modeling the basic blocks of hardware as this kind of machine.
|
|
We will write a language to plug together these modules into bigger modules.
|
|
|
|
*Example (register).*
|
|
|
|
$ (NN, {}, &{"write" = {(x, y, y) | forall x, y in NN^2}} \
|
|
&{"read" = {(x, z, x) | forall x, z in NN^2}}) $
|
|
|
|
Infinite transitions are ok but there needs to be a finite number of them.
|
|
|
|
*Example (infinite atomic memory).* This can't be expressed in hardware.
|
|
|
|
$ (NN -> NN, {}, &{"write" = {(f, ("idx", v), f') | forall y. "idx" = j -> f j = f' j, f' "idx" = v}}, \
|
|
&{"read" = {(f, "arg", f("arg")) | forall f, "arg"}})
|
|
$
|
|
|
|
*Example (queue).* $([NN], {}, {"enqueue", "dequeue"}, {"first"})$
|
|
|
|
== #strike[Equivalence] Refinement
|
|
|
|
If both sides can be refined into each other then they are equivalent.
|
|
|
|
- One way is to construct the language of the automata
|
|
|
|
*Definition (traces of a module/behaviors).*
|
|
|
|
Silent transition: $s_0 mapsto s_1$
|
|
|
|
Observations about the state must be added to the trace as well.
|
|
Trace looks like $["enqueue" (1), "first" () -> 1]$ for a queue.
|
|
|
|
*Definition (Refinement).* A module $M$ refines $M'$ iff $db(M) subset.eq db(M')$.
|
|
|
|
*Definition (weak simulation).* A module $M$ simulates $M'$
|
|
|
|
$ M op(subset.sq.eq)_phi M'$
|
|
|
|
s.t $phi : S_M times S_M'$ (relation between state of $M$ and state of $M'$).
|
|
|
|
$phi$ witnesses that $M'$ simulates $M$ iff $(m_0, m'_0) in phi$
|
|
|
|
#let arg = "arg"
|
|
#let sset = "set"
|
|
- Base case: $forall v in cal(V), forall arg, forall sset, (m_0, arg, sset) in v ==> (m'_0, arg, sset)$
|
|
- Inductive case: $forall m in S_M, m' in S_M', (m, m') in phi ==> forall "am" in a_m, forall arg, m mapsto^("am"(arg)) m_2 ==> (m' mapsto^("am"(arg)) m'_2)$
|
|
|
|
$ (M op(subset.sq.eq)_phi M') ==> db(M) subset db(M') $
|
|
|
|
=== Composing
|
|
|
|
Compose $M_1$, $M_2$, and $M_3$ into a bigger module.
|
|
|
|
#tree(
|
|
axi[$(m, f("arg"), m') in "enq"_M$],
|
|
uni[$m."enqE"("arg") --> m'$],
|
|
)
|
|
|
|
#tree(
|
|
axi[$(m, f("arg"), m') in "enq"_M$],
|
|
uni[$m."deq"("arg") --> m'$],
|
|
)
|
|
|
|
#pagebreak()
|
|
|
|
== Lecture 2
|
|
|
|
- Language Definition
|
|
- Compilation to circuits
|
|
- Example weak simulation + refinement theorem
|