-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
state machine refinement structure #2
Comments
* impossible to write a generic composition proof within the module
system (no such proof would be allowed to rely on an SMT condition like
A.Inv ==> B.Inv)
Why not? Why can't the proof prototype module be abstract, leaving a
body-less lemma Inv, so that if you want to instantiate the proof
module, you have to supply an implementation of Inv to complete the
proof?
On 2021-07-13 08:53, Travis Hance wrote:
Currently our refinement structure looks like: we have a bunch of state machines, A, B, C, ... etc. with refinement theorems of the form A_Refines_B.i.dfy. These are all named pretty consistently (although something much less consistent is the state machine invariants; sometimes the invariants for A are in the A file itself, and sometimes they are in separate files).
Sometimes, the A_Refines_B.i.dfy files are interesting, and sometimes they are not. There are a lot of files A_Refines_C which simply compose two existing refinements, A_Refines_B and B_Refines_C. All these 'composition' refinements have nearly the exact same boiler plate. With a "module system" on the horizon, we can start to think about writing a generic refinement composition proof. See this proof-of-concept [1].
However, there's another issue that needs to be taken care of first, which has to do with the way the refinement theorems are stated.
Here's a typical refinement theorem statement (Betree_Refines_Map.i.dfy):
lemma RefinesNext(s: Betree.Variables, s':Betree.Variables, uiop: UI.Op)
requires Inv(s)
requires Betree.Next(s, s', uiop)
ensures Inv(s')
ensures MS.Next(I(s), I(s'), uiop)
{
// ...
}
Note that this has Inv(s) as a pre-condition. Often, the interpretation function in these refinements has Inv as a precondition as well. The consequence of this is that A_Refines_B only composes with B_Refines_C if A.Inv implies B.Inv. This is problematic for a bunch of reasons, including:
* It makes it impossible to write a generic composition proof within the module system (no such proof would be allowed to rely on an SMT condition like A.Inv ==> B.Inv)
* Creates long dependency chains where invariants include other invariants that they don't really need.(*) This is bad for proof isolation.
(*) One (the only?) exception is ByteBlockCacheSystem, which includes the invariants of BlockCacheSystem for nontrivial reasons.
The solution to this is to define our generic refinement theorem without reference to 'Inv'. For example, we could use 'Reachable' instead (i.e., Reachable(s) := exists s0...sn . Init(s) && (forall i . Next(s_i, s_(i+1))) && sn == s). Reachable is the universal invariant which implies Inv for any predicate Inv satisfying the usual inductiveness conditions. We could also use an even more general definition of refinement, like behavior-based refinement. (Actually, this might be desirable for other reasons, as it would let us freely and locally introduce 'history' into state machines, which has come up in a few hypotheticals.) Either way, we need to pick some generic definition of refinement which actually composes properly, but which is implied by our usual TLA-style refinement statement. (Of course, we would define generic module-theorems that transform one style into another, so we'd keep writing proofs as before.)
--
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub [2], or unsubscribe [3].
|
you're right, you could leave a body-less lemma. But what I want, ideally, is to just instantly create the refinement tower by a giant module functor application. I don't want to have a bunch of boilerplate where I refine each module each step of the way just to instantiate a body-less lemma. Actually, thinking more about it, there's probably another fairly simple thing to do, which is to make |
Here's an example of a Refinement definition that should be composable:
|
In |
we already have NextPreservesInv as an obligation, so it's all equivalent |
As written, any caller of |
Currently our refinement structure looks like: we have a bunch of state machines, A, B, C, ... etc. with refinement theorems of the form
A_Refines_B.i.dfy
. These are all named pretty consistently (although something much less consistent is the state machine invariants; sometimes the invariants forA
are in theA
file itself, and sometimes they are in separate files).Sometimes, the
A_Refines_B.i.dfy
files are interesting, and sometimes they are not. There are a lot of files A_Refines_C which simply compose two existing refinements, A_Refines_B and B_Refines_C. All these 'composition' refinements have nearly the exact same boiler plate. With a "module system" on the horizon, we can start to think about writing a generic refinement composition proof. See this proof-of-concept.However, there's another issue that needs to be taken care of first, which has to do with the way the refinement theorems are stated.
Here's a typical refinement theorem statement (
Betree_Refines_Map.i.dfy
):Note that this has
Inv(s)
as a pre-condition. Often, the interpretation function in these refinements hasInv
as a precondition as well. The consequence of this is thatA_Refines_B
only composes withB_Refines_C
ifA.Inv
impliesB.Inv
. This is problematic for a bunch of reasons, including:A.Inv ==> B.Inv
)(*) One (the only?) exception is ByteBlockCacheSystem, which includes the invariants of BlockCacheSystem for nontrivial reasons.
The solution to this is to define our generic refinement theorem without reference to 'Inv'. For example, we could use 'Reachable' instead (i.e., Reachable(s) := exists s0...sn . Init(s) && (forall i . Next(s_i, s_(i+1))) && sn == s). Reachable is the universal invariant which implies Inv for any predicate Inv satisfying the usual inductiveness conditions. We could also use an even more general definition of refinement, like behavior-based refinement. (Actually, this might be desirable for other reasons, as it would let us freely and locally introduce 'history' into state machines, which has come up in a few hypotheticals.) Either way, we need to pick some generic definition of refinement which actually composes properly, but which is implied by our usual TLA-style refinement statement. (Of course, we would define generic module-theorems that transform one style into another, so we'd keep writing proofs as before.)
The text was updated successfully, but these errors were encountered: