mirror of
https://github.com/achlipala/frap.git
synced 2024-11-10 00:07:51 +00:00
493 lines
12 KiB
Coq
493 lines
12 KiB
Coq
(** Formal Reasoning About Programs <http://adam.chlipala.net/frap/>
|
|
* Chapter 5: Model Checking
|
|
* Author: Adam Chlipala
|
|
* License: https://creativecommons.org/licenses/by-nc-nd/4.0/ *)
|
|
|
|
Require Import Frap TransitionSystems.
|
|
|
|
Set Implicit Arguments.
|
|
|
|
|
|
Definition oneStepClosure_current {state} (sys : trsys state)
|
|
(invariant1 invariant2 : state -> Prop) :=
|
|
forall st, invariant1 st
|
|
-> invariant2 st.
|
|
|
|
Definition oneStepClosure_new {state} (sys : trsys state)
|
|
(invariant1 invariant2 : state -> Prop) :=
|
|
forall st st', invariant1 st
|
|
-> sys.(Step) st st'
|
|
-> invariant2 st'.
|
|
|
|
Definition oneStepClosure {state} (sys : trsys state)
|
|
(invariant1 invariant2 : state -> Prop) :=
|
|
oneStepClosure_current sys invariant1 invariant2
|
|
/\ oneStepClosure_new sys invariant1 invariant2.
|
|
|
|
Theorem prove_oneStepClosure : forall state (sys : trsys state) (inv1 inv2 : state -> Prop),
|
|
(forall st, inv1 st -> inv2 st)
|
|
-> (forall st st', inv1 st -> sys.(Step) st st' -> inv2 st')
|
|
-> oneStepClosure sys inv1 inv2.
|
|
Proof.
|
|
unfold oneStepClosure.
|
|
propositional.
|
|
Qed.
|
|
|
|
Theorem oneStepClosure_done : forall state (sys : trsys state) (invariant : state -> Prop),
|
|
(forall st, sys.(Initial) st -> invariant st)
|
|
-> oneStepClosure sys invariant invariant
|
|
-> invariantFor sys invariant.
|
|
Proof.
|
|
unfold oneStepClosure, oneStepClosure_current, oneStepClosure_new.
|
|
propositional.
|
|
apply invariant_induction.
|
|
assumption.
|
|
simplify.
|
|
eapply H2.
|
|
eassumption.
|
|
assumption.
|
|
Qed.
|
|
|
|
Inductive multiStepClosure {state} (sys : trsys state)
|
|
: (state -> Prop) -> (state -> Prop) -> Prop :=
|
|
| MscDone : forall inv,
|
|
oneStepClosure sys inv inv
|
|
-> multiStepClosure sys inv inv
|
|
| MscStep : forall inv inv' inv'',
|
|
oneStepClosure sys inv inv'
|
|
-> multiStepClosure sys inv' inv''
|
|
-> multiStepClosure sys inv inv''.
|
|
|
|
Lemma multiStepClosure_ok' : forall state (sys : trsys state) (inv inv' : state -> Prop),
|
|
multiStepClosure sys inv inv'
|
|
-> (forall st, sys.(Initial) st -> inv st)
|
|
-> invariantFor sys inv'.
|
|
Proof.
|
|
induct 1; simplify.
|
|
|
|
apply oneStepClosure_done.
|
|
assumption.
|
|
assumption.
|
|
|
|
apply IHmultiStepClosure.
|
|
simplify.
|
|
unfold oneStepClosure, oneStepClosure_current in *. (* <-- *)
|
|
propositional.
|
|
apply H3.
|
|
apply H1.
|
|
assumption.
|
|
Qed.
|
|
|
|
Theorem multiStepClosure_ok : forall state (sys : trsys state) (inv : state -> Prop),
|
|
multiStepClosure sys sys.(Initial) inv
|
|
-> invariantFor sys inv.
|
|
Proof.
|
|
simplify.
|
|
eapply multiStepClosure_ok'.
|
|
eassumption.
|
|
propositional.
|
|
Qed.
|
|
|
|
Theorem oneStepClosure_empty : forall state (sys : trsys state),
|
|
oneStepClosure sys (constant nil) (constant nil).
|
|
Proof.
|
|
unfold oneStepClosure, oneStepClosure_current, oneStepClosure_new; propositional.
|
|
Qed.
|
|
|
|
Theorem oneStepClosure_split : forall state (sys : trsys state) st sts (inv1 inv2 : state -> Prop),
|
|
(forall st', sys.(Step) st st' -> inv1 st')
|
|
-> oneStepClosure sys (constant sts) inv2
|
|
-> oneStepClosure sys (constant (st :: sts)) ({st} \cup inv1 \cup inv2).
|
|
Proof.
|
|
unfold oneStepClosure, oneStepClosure_current, oneStepClosure_new; propositional.
|
|
|
|
invert H0.
|
|
|
|
left.
|
|
left.
|
|
simplify.
|
|
propositional.
|
|
|
|
right.
|
|
apply H1.
|
|
assumption.
|
|
|
|
simplify.
|
|
propositional.
|
|
|
|
left.
|
|
right.
|
|
apply H.
|
|
equality.
|
|
|
|
right.
|
|
eapply H2.
|
|
eassumption.
|
|
assumption.
|
|
Qed.
|
|
|
|
Definition fact_correct (original_input : nat) (st : fact_state) : Prop :=
|
|
match st with
|
|
| AnswerIs ans => fact original_input = ans
|
|
| WithAccumulator _ _ => True
|
|
end.
|
|
|
|
Theorem fact_init_is : forall original_input,
|
|
fact_init original_input = {WithAccumulator original_input 1}.
|
|
Proof.
|
|
simplify.
|
|
apply sets_equal; simplify.
|
|
propositional.
|
|
|
|
invert H.
|
|
equality.
|
|
|
|
rewrite <- H0.
|
|
constructor.
|
|
Qed.
|
|
|
|
Theorem singleton_in : forall {A} (x : A) rest,
|
|
({x} \cup rest) x.
|
|
Proof.
|
|
simplify.
|
|
left.
|
|
simplify.
|
|
equality.
|
|
Qed.
|
|
|
|
Theorem singleton_in_other : forall {A} (x : A) (s1 s2 : set A),
|
|
s2 x
|
|
-> (s1 \cup s2) x.
|
|
Proof.
|
|
simplify.
|
|
right.
|
|
assumption.
|
|
Qed.
|
|
|
|
Theorem factorial_ok_2 :
|
|
invariantFor (factorial_sys 2) (fact_correct 2).
|
|
Proof.
|
|
simplify.
|
|
eapply invariantFor_weaken.
|
|
|
|
apply multiStepClosure_ok.
|
|
simplify.
|
|
rewrite fact_init_is.
|
|
|
|
eapply MscStep.
|
|
apply oneStepClosure_split; simplify.
|
|
invert H; simplify.
|
|
apply singleton_in.
|
|
apply oneStepClosure_empty.
|
|
simplify.
|
|
|
|
eapply MscStep.
|
|
apply oneStepClosure_split; simplify.
|
|
invert H; simplify.
|
|
apply singleton_in.
|
|
apply oneStepClosure_split; simplify.
|
|
invert H; simplify.
|
|
apply singleton_in.
|
|
apply oneStepClosure_empty.
|
|
simplify.
|
|
|
|
eapply MscStep.
|
|
apply oneStepClosure_split; simplify.
|
|
invert H; simplify.
|
|
apply singleton_in.
|
|
apply oneStepClosure_split; simplify.
|
|
invert H; simplify.
|
|
apply singleton_in.
|
|
apply oneStepClosure_split; simplify.
|
|
invert H; simplify.
|
|
apply singleton_in.
|
|
apply oneStepClosure_empty.
|
|
simplify.
|
|
|
|
apply MscDone.
|
|
apply prove_oneStepClosure; simplify.
|
|
propositional.
|
|
propositional; invert H0; try equality.
|
|
invert H; equality.
|
|
invert H1; equality.
|
|
|
|
simplify.
|
|
propositional; subst; simplify; propositional.
|
|
(* ^-- *)
|
|
Qed.
|
|
|
|
Hint Rewrite fact_init_is.
|
|
|
|
Ltac model_check_done :=
|
|
apply MscDone; apply prove_oneStepClosure; simplify; propositional; subst;
|
|
repeat match goal with
|
|
| [ H : _ |- _ ] => invert H
|
|
end; simplify; equality.
|
|
|
|
Ltac singletoner :=
|
|
repeat match goal with
|
|
| _ => apply singleton_in
|
|
| [ |- (_ \cup _) _ ] => apply singleton_in_other
|
|
end.
|
|
|
|
Ltac model_check_step :=
|
|
eapply MscStep; [
|
|
repeat ((apply oneStepClosure_empty; simplify)
|
|
|| (apply oneStepClosure_split; [ simplify;
|
|
repeat match goal with
|
|
| [ H : _ |- _ ] => invert H
|
|
end; solve [ singletoner ] | ]))
|
|
| simplify ].
|
|
|
|
Ltac model_check_steps1 := model_check_done || model_check_step.
|
|
Ltac model_check_steps := repeat model_check_steps1.
|
|
|
|
Ltac model_check_finish := simplify; propositional; subst; simplify; equality.
|
|
|
|
Ltac model_check_find_invariant :=
|
|
simplify; eapply invariantFor_weaken; [
|
|
apply multiStepClosure_ok; simplify; model_check_steps
|
|
| ].
|
|
|
|
Ltac model_check := model_check_find_invariant; model_check_finish.
|
|
|
|
Theorem factorial_ok_2_snazzy :
|
|
invariantFor (factorial_sys 2) (fact_correct 2).
|
|
Proof.
|
|
model_check.
|
|
Qed.
|
|
|
|
Theorem factorial_ok_3 :
|
|
invariantFor (factorial_sys 3) (fact_correct 3).
|
|
Proof.
|
|
model_check.
|
|
Qed.
|
|
|
|
Theorem factorial_ok_5 :
|
|
invariantFor (factorial_sys 5) (fact_correct 5).
|
|
Proof.
|
|
model_check.
|
|
Qed.
|
|
|
|
|
|
(** * Getting smarter about not exploring from the same state twice *)
|
|
|
|
Inductive multiStepClosure_smarter {state} (sys : trsys state)
|
|
: (state -> Prop) -> (state -> Prop) -> (state -> Prop) -> Prop :=
|
|
| MscsDone : forall inv worklist,
|
|
oneStepClosure sys inv inv
|
|
-> multiStepClosure_smarter sys inv worklist inv
|
|
| MscsStep : forall inv worklist inv' inv'',
|
|
oneStepClosure_new sys worklist inv'
|
|
-> multiStepClosure_smarter sys (inv \cup inv') (inv' \setminus inv) inv''
|
|
-> multiStepClosure_smarter sys inv worklist inv''.
|
|
|
|
Lemma multiStepClosure_smarter_ok' : forall state (sys : trsys state)
|
|
(inv worklist inv' : state -> Prop),
|
|
multiStepClosure_smarter sys inv worklist inv'
|
|
-> (forall st, sys.(Initial) st -> inv st)
|
|
-> invariantFor sys inv'.
|
|
Proof.
|
|
induct 1; simplify.
|
|
|
|
apply oneStepClosure_done.
|
|
assumption.
|
|
assumption.
|
|
|
|
apply IHmultiStepClosure_smarter.
|
|
simplify.
|
|
left.
|
|
apply H1.
|
|
assumption.
|
|
Qed.
|
|
|
|
Theorem multiStepClosure_smarter_ok : forall state (sys : trsys state) (inv : state -> Prop),
|
|
multiStepClosure_smarter sys sys.(Initial) sys.(Initial) inv
|
|
-> invariantFor sys inv.
|
|
Proof.
|
|
simplify.
|
|
eapply multiStepClosure_smarter_ok'.
|
|
eassumption.
|
|
propositional.
|
|
Qed.
|
|
|
|
Theorem oneStepClosure_new_empty : forall state (sys : trsys state),
|
|
oneStepClosure_new sys (constant nil) (constant nil).
|
|
Proof.
|
|
unfold oneStepClosure_new; propositional.
|
|
Qed.
|
|
|
|
Theorem oneStepClosure_new_split : forall state (sys : trsys state) st sts (inv1 inv2 : state -> Prop),
|
|
(forall st', sys.(Step) st st' -> inv1 st')
|
|
-> oneStepClosure_new sys (constant sts) inv2
|
|
-> oneStepClosure_new sys (constant (st :: sts)) (inv1 \cup inv2).
|
|
Proof.
|
|
unfold oneStepClosure_new; propositional.
|
|
|
|
invert H1.
|
|
|
|
left.
|
|
apply H.
|
|
assumption.
|
|
|
|
right.
|
|
eapply H0.
|
|
eassumption.
|
|
assumption.
|
|
Qed.
|
|
|
|
Theorem factorial_ok_2_smarter :
|
|
invariantFor (factorial_sys 2) (fact_correct 2).
|
|
Proof.
|
|
simplify.
|
|
eapply invariantFor_weaken.
|
|
|
|
apply multiStepClosure_smarter_ok.
|
|
simplify.
|
|
|
|
eapply MscsStep.
|
|
apply oneStepClosure_new_split; simplify.
|
|
invert H; simplify.
|
|
apply singleton_in.
|
|
apply oneStepClosure_new_empty.
|
|
simplify.
|
|
|
|
eapply MscsStep.
|
|
apply oneStepClosure_new_split; simplify.
|
|
invert H; simplify.
|
|
apply singleton_in.
|
|
apply oneStepClosure_empty.
|
|
simplify.
|
|
|
|
eapply MscsStep.
|
|
apply oneStepClosure_new_split; simplify.
|
|
invert H; simplify.
|
|
apply singleton_in.
|
|
apply oneStepClosure_empty.
|
|
simplify.
|
|
|
|
apply MscsDone.
|
|
apply prove_oneStepClosure; simplify.
|
|
propositional.
|
|
propositional; invert H0; try equality.
|
|
invert H; equality.
|
|
invert H1; equality.
|
|
|
|
simplify.
|
|
propositional; subst; simplify; propositional.
|
|
Qed.
|
|
|
|
Ltac smodel_check_done :=
|
|
apply MscsDone; apply prove_oneStepClosure; simplify; propositional; subst;
|
|
repeat match goal with
|
|
| [ H : _ |- _ ] => invert H
|
|
end; simplify; equality.
|
|
|
|
Ltac smodel_check_step :=
|
|
eapply MscsStep; [
|
|
repeat ((apply oneStepClosure_new_empty; solve [ simplify ])
|
|
|| (apply oneStepClosure_new_split; [ simplify;
|
|
repeat match goal with
|
|
| [ H : _ |- _ ] => invert H
|
|
end; solve [ singletoner ] | ]))
|
|
| simplify ].
|
|
|
|
Ltac smodel_check_steps1 := smodel_check_done || smodel_check_step.
|
|
Ltac smodel_check_steps := repeat smodel_check_steps1.
|
|
|
|
Ltac smodel_check_setup :=
|
|
simplify; eapply invariantFor_weaken; [
|
|
apply multiStepClosure_smarter_ok; simplify
|
|
| ].
|
|
|
|
Ltac smodel_check_find_invariant := smodel_check_setup; [ smodel_check_steps | ].
|
|
|
|
Ltac smodel_check := smodel_check_find_invariant; model_check_finish.
|
|
|
|
Theorem factorial_ok_2_smarter_snazzy :
|
|
invariantFor (factorial_sys 2) (fact_correct 2).
|
|
Proof.
|
|
smodel_check.
|
|
Qed.
|
|
|
|
Theorem factorial_ok_3_smarter_snazzy :
|
|
invariantFor (factorial_sys 3) (fact_correct 3).
|
|
Proof.
|
|
smodel_check.
|
|
Qed.
|
|
|
|
Theorem factorial_ok_5_smarter_snazzy :
|
|
invariantFor (factorial_sys 5) (fact_correct 5).
|
|
Proof.
|
|
smodel_check.
|
|
Qed.
|
|
|
|
|
|
(** * Back to the multithreaded example from last time *)
|
|
|
|
Theorem increment2_init_is :
|
|
parallel1 increment_init increment_init = { {| Shared := {| Global := 0; Locked := false |};
|
|
Private := (Lock, Lock) |} }.
|
|
Proof.
|
|
simplify.
|
|
apply sets_equal; simplify.
|
|
propositional.
|
|
|
|
invert H.
|
|
invert H2.
|
|
invert H4.
|
|
equality.
|
|
|
|
rewrite <- H0.
|
|
constructor.
|
|
constructor.
|
|
constructor.
|
|
Qed.
|
|
|
|
Hint Rewrite increment2_init_is.
|
|
|
|
(*Theorem increment2_ok :
|
|
invariantFor increment2_sys increment2_right_answer.
|
|
Proof.
|
|
unfold increment2_right_answer.
|
|
smodel_check.
|
|
Qed.*)
|
|
|
|
Definition increment3_sys := parallel increment_sys increment2_sys.
|
|
|
|
Definition increment3_right_answer
|
|
(s : threaded_state inc_state (increment_program * (increment_program * increment_program))) :=
|
|
s.(Private) = (Done, (Done, Done))
|
|
-> s.(Shared).(Global) = 3.
|
|
|
|
Theorem increment3_init_is :
|
|
parallel1 increment_init (parallel1 increment_init increment_init)
|
|
= { {| Shared := {| Global := 0; Locked := false |};
|
|
Private := (Lock, (Lock, Lock)) |} }.
|
|
Proof.
|
|
simplify.
|
|
apply sets_equal; simplify.
|
|
propositional.
|
|
|
|
invert H.
|
|
invert H2.
|
|
invert H4.
|
|
equality.
|
|
invert H.
|
|
|
|
rewrite <- H0.
|
|
constructor.
|
|
constructor.
|
|
constructor.
|
|
constructor.
|
|
Qed.
|
|
|
|
Hint Rewrite increment3_init_is.
|
|
|
|
Theorem increment3_ok :
|
|
invariantFor increment3_sys increment3_right_answer.
|
|
Proof.
|
|
unfold increment3_right_answer.
|
|
smodel_check_find_invariant.
|
|
model_check_finish.
|
|
Qed.
|