-
Notifications
You must be signed in to change notification settings - Fork 105
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
simpler corres
and corressimp
methods
#634
Comments
Some extra thoughts:
Best-guess automation as with The way wpsimp et al only split off a chunk (bind) if they can do something with it is nice, we should keep that. Graceful degradation is helpful, i.e. being able to get dumped in the middle of a failed wp discharging after the corres. For bonus points, being able to resume after human assistance would also be helpful, but that can get really weird given that corres can spit out combinations of corres and wp goals, and we wouldn't want the tactic to just keep eating away at goals as long as they are of either form. I guess one could limit the number of goals, but by that argument one could also do It sucks to have to specify |
Ok, here a first few lines for discussion: method corres_cleanup = assumption | rule refl
method corres_split declares corres = ((rule corres_split, (rule corres; corres_cleanup?))+)[1]
method corres_split_simp uses simp declares corres = ((corres_split corres: corres | clarsimp simp: simp)+)[1] As @Xaphiosis pointed out on chat, this needs a bit more refinement and thinking. In particular:
I think we should constrain the focus of this method somewhat. The 3 lines above are definitely not the final method, but they are already pretty useful in the example I tried and do almost all I wanted for it. As I see it, there are roughly 3 kinds of corres rules:
What I think is easily automatable:
What I don't think is easily automatable:
Leaving out symb_exec rules is easy, we can just not provide them. The other point is almost impossible, because terminal corres rules might have side conditions that look simple (e.g. The usual way to deal with this kind of problem is to move the verification of such side conditions to later. In the current corres calculus this is not possible -- you can't put So, the best we can do when we apply a terminal corres rule is to apply the rule and attempt to solve the side conditions, and either stop and hand over to the user in this unsolved state or give up and stop completely. I think that's Ok, this entire argument was just to map out expectations. For these two questions:
I'm not sure there is, but I'm open to ideas. The idea is that the terminal step might fail to resolve all side conditions, in which case we want the tactic to stop and not attempt to work on any goals further down in the chain.
The |
I'll think some more, but meanwhile point out that I would encourage a browse of the |
I do not agree with closing off symbolic execution early. That kind of approach results in someone doing another approach later, or using your method for hammers like
There are other situations like when we're dealing with machine ops that I don't really remember, but while the tactic doesn't have to deal with that now, it would be nice to be able to expand it to deal with some of those situations (such as a chain of provably identical machine ops on both sides). My initial thought was also that some rules are used with I guess if I were to summarise what bothers me about the current approach is exactly that "they are already pretty useful in the example I tried and do almost all I wanted for it":
My vision for how this should go is that for a braindead linear corres proof, we should be able to one-line it, go as far as being able to handle a matching |
From MM: I apologise for sounding overly critical, but for the monadic rewrite stuff I hammered out a lot of edge cases to make sub-methods and sub-tactics stable and therefore being able to be assembled into bigger steps/tactics (extending monadic_rewrite to I really don't want to see those approaches immediately forgotten by default :/ |
Ok, here are some draft features I think we want
That's what I thought of for the time being. Additions and comments welcome. edit: remove |
The checklist is looking pretty good. Esp agree that the clarsimp needs more finesse (and all the bits not mentioned below). There are some bits where don't seem to be quite on the same page yet:
The clarsimp is specifically there to run on corres goals, I was actually thinking about guarding it so that it applies to only corres goals. The idea is that you often want to be able to tweak the corres goal slightly, i.e. unfold some function to inline it or unfold a Having said that, corres is more subtle and fragile than Because of the outer
corres_cleanup is only ever applied to the side conditions of terminal corres rules. By definition, these cannot be corres goals (otherwise that would have to be a split rule). Edit: I'm arguing above that having cores_cleain fail on corres goals is not necessary. Thinking further: so what if we do it anyway, do we gain anything? I think we might: we could then allow terminal corres rules that are not really terminal, e.g. transformation rules that turn one corres form into another one. I had initially excluded that, because it's not safe -- it would make a split applicable where the next step is just a transformation and not a terminal rule that will solve something. I still think that such rules should never be declared
I agree with you about the The We might still go that way, but after thinking more about it, I have more doubts. The side conditions of terminal rules is where we spend the actual manual proof time of the corres part (apart from wsimp and the final two implication goals). I'm having trouble imagining one where I wouldn't want to say Maybe we need to experiment with this one a bit, I currently can't tell what is more useful. I'd want to avoid the situation where we always call (Not entirely by thoughtful design the 3-liner does actually always apply clarsimp to those side conditions that aren't solved, because if the side condition proof fails, it will be left in the goal, the corres split will fail, and the clarsimp will be called, which will end the outer loop. For the admittedly few goals that I played with, that clarsimp on the terminal-rule side condition worked very nicely).
This is an interesting one. I don't see asserts working as a general capability of the method that it always tries, because they cannot be made safe in general, but as potentially user-supplied rules or maybe even a method that you put in when you know what you want to do, that is a different situation. It could even be a built-in capability that usually gets an empty lemma set (and therefore fails/does nothing), but you can put switch it on by providing the right rule when you want to use the capability. Something like that. I'd build the rest first and then see how we can add this before we deploy the method more widely.
That could probably be done as a separate extension, because it's unlikely to break anything or change fundamental behaviour of existing applications of the method. I'm not sure we actually need to change anything in the method, it's possible that just providing the right split rule and potentially simp rules does make that bit work (for simple doMachineOp corres goals, the 3-liner already worked, so this would be those case where they are wrapped differently in ASpec vs Haskell). |
Ok, here is a larger new draft for further discussion (untested and still incomplete -- imagine all the parameters properly passed through from the top instead of just simp/cong). method corres_rel = (WP_pre.pre_tac corres_rel_imp)?
method is_corres = rule corres_inst
method is_wp = rule hoare_triv (* add validE + variations; also no_fail? *)
named_theorems corres_splits
method corres_split declares corres_splits = no_name_eta, rule corres_splits
method corres_cleanup methods m uses simp simp_del split split_del cong intro =
m
| assumption
| rule refl
| clarsimp simp: simp split: split split_del: split_del cong: cong intro!: intro
(* enables passing in conjI for terminal goals: *)
| (rule intro;
corres_cleanup m simp: simp simp_del: simp_del split: split
split_del: split_del cong: cong intro: intro)
named_theorems corres
method corres_terminal methods m uses simp cong declares corres =
(rule corres | corres_rel, rule corres);
(fails ‹is_corres›, fails ‹is_wp›, solves ‹corres_cleanup m simp: simp cong: cong›)?
method corres' methods m uses simp cong fallback declares corres corres_splits =
((wpfix
| corres_pre
| corres_terminal m simp: simp cong: cong corres: corres
| corres_split corres_splits: corres_splits,
corres_terminal m simp: simp cong: cong corres: corres
| corres_terminal m simp: simp cong: cong corres: fallback
| wpc
| succeeds ‹is_corres›,
clarsimp cong: corres_weaker_cong simp: simp cong: cong split del: if_split
| succeeds ‹is_wp›, (wpsimp simp: simp cong: cong)+
)+)[1]
method corres uses simp cong declares corres fallback corres_splits =
corres' ‹fail› simp: simp cong: cong corres: corres fallback: fallback corres_splits: corres_splits This is now a version that will not leave an unfinished clarsimp for the side conditions of terminal corres rules. Still not sure that's what we want, but happy to experiment. It'd be relatively easy to change this into using Another question is if the whole thing should be prefixed by an Edit: updated this with a apply (corres corres: corres_assert_gen_asm_l) then apply (corres fallback: corres_assert_gen_asm_l) which will apply the safe standard rules first, and the supplied rules when neither terminal nor split step succeed. |
Sadly, Eisbach methods don't have doc strings. Comment is the best we can do currently. |
This is much more thorough. More inline comments would be good as well to walk the reader through intent, there are a lot of stages going on. Would like to discuss and go through this, it'll be very easy for me to miss something otherwise. |
Dan built two fairly sophisticated proof methods for refinement proofs,
corres
andcorressimp
, but we don't use them a lot.One reason for that is that we're currently mostly updating existing corres proofs and not writing very many new ones. The other reason is that they don't fail in very useful ways. I.e. when they succeed, it's great, but when the methods fail it is very hard to understand why and where, and even harder to figure out how to make progress from there.
My guess is that if we simplify these methods so that they do much less, it will be easier to form a mental model of what they are doing and therefore to use them more productively. They'll probably solve a lot fewer goals automatically, but if it's clear how to make progress on the goals that they leave over, I think they'll be used a lot more.
Similar (but but not equal) to how
clarsimp
is a lot easier to use incrementally thanforce
orblast
, because it makes incremental progress and one can usually understand how to add things to make more progress.For instance, one thing that Dan did for these methods is to change the underlying corres calculus such that it better supports automation. That new calculus definitely is better for automation, but since we don't use it manually, we don't really understand its subtleties.
My proposal would be as first step to write a completely naive
corres
method that only know how to split offbind
with functions it already has rules for. Maybe, as a plus, it can attempt to immediately solve thewp
goals that it produces, but that is already advanced.Opinions and discussions welcome!
The text was updated successfully, but these errors were encountered: